muse1.7b4/
muse1.7b4/config/
muse1.7b4/doc/
muse1.7b4/run/
muse1.7b4/run/db/
muse1.7b4/src/
muse1.7b4/src/db/
muse1.7b4/src/files/
muse1.7b4/src/io/
muse1.7b4/src/prog/
muse1.7b4/src/util/
/* $Header: /u/cvsroot/muse/src/db/inherit.c,v 1.6 1993/03/21 00:49:57 nils Exp $ */

#include <stdio.h>
#include "externs.h"
#include "config.h"
#include "db.h"

void put_atrdefs (f, defs)
     FILE *f;
     ATRDEF *defs;
{
  extern void putstring P((FILE *, char *));
  for (;defs;defs=defs->next) {
    fputc('/',f);
    putref(f, defs->a.flags);
    putref(f, defs->a.obj);
    putstring(f, defs->a.name);
  }
  fputs("\\\n",f);
}

ATRDEF *get_atrdefs (f,olddefs)
     FILE *f;
     ATRDEF *olddefs;
{
  extern char *getstring_noalloc P((FILE *));
  char k;
  ATRDEF *ourdefs=NULL, *endptr=NULL;
  
  for (;;) {
    k = fgetc(f);
    switch (k) {
    case '\\':
      if (fgetc(f)!='\n')
	log_error ("No atrdef newline.");
      return ourdefs;
      break;
    case '/':
      if (!endptr)
	if (olddefs) {
	  endptr = ourdefs = olddefs;
	  olddefs = olddefs->next;
	} else
	  endptr = ourdefs = malloc( sizeof(ATRDEF));
      else
	if (olddefs) {
	  endptr->next = olddefs;
	  olddefs = olddefs->next;
	  endptr = endptr->next;
	} else {
	  endptr->next = malloc( sizeof(ATRDEF));
	  endptr = endptr->next;
	}
      endptr->a.flags = getref(f);
      endptr->a.obj = getref(f);
      endptr->next = NULL;
      endptr->a.name = NULL;
      SET (endptr->a.name, getstring_noalloc(f));
      break;
    default:
      log_error ("Illegal character in get_atrdefs");
      return 0;
    }
  }
}

void remove_attribute (obj, atr)
     dbref obj;
     ATTR *atr;
{
  int i;
  atr_add (obj, atr, "");
  for (i=0; db[obj].children && db[obj].children[i] != NOTHING; i++)
    remove_attribute (db[obj].children[i], atr);
}

void do_undefattr (player, arg1)
     dbref player;
     char *arg1;
{
  dbref obj;
  ATTR *atr;
  ATRDEF *d, *prev=NULL;
  
  if(!parse_attrib(player, arg1, &obj, &atr, POW_MODIFY)) {
    notify(player, "No match.");
    return;
  }
  for (d= db[obj].atrdefs; d; prev=d, d=d->next)
    if (&(d->a) == atr) {
      if (prev)
	prev->next = d->next;
      else
	db[obj].atrdefs = d->next;
      remove_attribute (obj, atr);
      if (0==--d->a.refcount) {	/* this should always happen, but... */
	free(d->a.name);
	free(d);
      }
      notify(player, "Deleted.");
      return;
    }
  notify(player, "No match.");
}

void do_defattr (player, arg1, arg2)
     dbref player;
     char *arg1,*arg2;
{
  ATTR *atr;
  char *flag_parse;
  int atr_flags = 0;
  dbref thing;
  char *attribute;
  int i;

  if (!(attribute=strchr(arg1,'/'))) {
    notify(player,"no match");
    return;
  }
  *(attribute++) = '\0';
  
  thing = match_controlled(player, arg1, POW_MODIFY);
  if (thing == NOTHING)
    return;

  if (!ok_attribute_name (attribute)) {
    notify(player,"Illegal attribute name.");
    return;
  }
  
  while ((flag_parse = parse_up(&arg2,' '))) {
    if (flag_parse == NULL);	/* empty if, so we can do else: */
#define IFIS(foo,baz) else if(!string_compare(flag_parse,foo)) atr_flags|=baz
    IFIS("wizard",AF_WIZARD);
    IFIS("osee",AF_OSEE);
    IFIS("dark",AF_DARK);
    IFIS("inherit",AF_INHERIT);
    IFIS("unsaved",AF_UNIMP);
    IFIS("date",AF_DATE);
    IFIS("lock",AF_LOCK);
    IFIS("function",AF_FUNC);
#undef IFIS
  else
    notify(player,tprintf("Unknown attribute option: %s",flag_parse));
  }
  
  atr = atr_str (thing, thing, attribute);
  if (atr && atr->obj == thing) {
    atr->flags = atr_flags;
    notify(player, "Options set.");
    return;
  }

  {
    ATRDEF *k;
    
    for (k=db[thing].atrdefs,i=0; k; k=k->next, i++);
    if (i>90 && !power(player,POW_SECURITY)) {
      notify(player,"Sorry, you can't have that many attribute defs on an object.");
      return;
    }
    if (atr) {
      notify(player, "Sorry, attribute shadows a builtin attribute or one on a parent.");
      return;
    }
    k=malloc( sizeof(ATRDEF));
    k->a.name = NULL;
    SET (k->a.name, attribute);
    k->a.flags = atr_flags;
    k->a.obj = thing;
    k->a.refcount = 1;
    k->next = db[thing].atrdefs;
    db[thing].atrdefs = k;
  }
  notify(player,"Attribute defined.");
}


static int is_a_internal (thing, parent, dep)
     dbref thing;
     dbref parent;
     int dep;
{
  int j;
  if (thing == parent) return 1;
  if (dep < 0) return 1;
  if (!db[thing].parents) return 0;
  for (j=0; db[thing].parents[j]!=NOTHING; j++)
    if (is_a_internal (db[thing].parents[j], parent, dep-1))
      return 1;
  return 0;
}

int is_a (thing, parent)
     dbref thing;
     dbref parent;
{
  if (thing == NOTHING)
    return 1;
  return is_a_internal (thing, parent, 20); /* 20 is the max depth */
}
#if 0
static void reparent P((dbref, dbref, dbref *)), unparent P((dbref));
#endif

void do_delparent (player, arg1, arg2)
     dbref player;
     char *arg1,*arg2;
{
  dbref thing;
  dbref parent;
  int i;
  int can_doit = 0;

  thing = match_controlled(player, arg1 , POW_MODIFY);
  if (thing == NOTHING)
    return;
  mark_hearing(thing);
  parent = match_thing (player, arg2);
  if (parent == NOTHING) return;
  if (!(db[parent].flags&BEARING) && !controls(player,parent,POW_MODIFY)) {
    notify (player,tprintf("Sorry, you can't unparent from that."));
    can_doit = 1;
  }
      
  
  for (i=0; db[thing].parents && db[thing].parents[i]!=NOTHING;
       i++)
    if (db[thing].parents[i] == parent)
      can_doit |= 2;
  
  if (!(can_doit&2))
    notify (player, "Sorry, it doesn't have that as its parent.");
  if (can_doit != 2)
    return;

  REMOVE_FIRST_L (db[thing].parents, parent);
  REMOVE_FIRST_L (db[parent].children, thing);
  notify(player, tprintf("%s is no longer a parent of %s.",
			 unparse_object_a (player, parent),
			 unparse_object_a (player, thing)));
  check_hearing();
}

void do_addparent (player, arg1, arg2)
     dbref player;
     char *arg1,*arg2;
{
  dbref thing;
  dbref parent;
  int i;
  int can_doit = 0;

  thing = match_controlled(player, arg1 , POW_MODIFY);
  if (thing == NOTHING)
    return;
  mark_hearing(thing);
  parent = match_thing (player, arg2);
  if (parent == NOTHING)
    return;
  if (is_a(parent, thing)) {
    notify (player,tprintf("but %s is a descendant of %s!",
			   unparse_object_a (player, parent),
			   unparse_object_a (player, thing)));
    can_doit |= 4;
  }
  if (!(db[parent].flags&BEARING) && !controls(player,parent,POW_MODIFY)) {
    notify (player,tprintf("Sorry, you can't parent to that."));
    can_doit |= 1;
  }
      
  
  for (i=0; db[thing].parents && db[thing].parents[i]!=NOTHING;
       i++)
    if (db[thing].parents[i] == parent)
	can_doit |= 2;
  
  if (can_doit&2)
    notify (player, "Sorry, it already has that as its parent.");
  if (can_doit != 0)
    return;

  PUSH_L (db[thing].parents, parent);
  PUSH_L (db[parent].children, thing);
  notify(player, tprintf("%s is now a parent of %s.",
			 unparse_object_a (player, parent),
			 unparse_object_a (player, thing)));
  check_hearing();
}

#if 0
static void reparent (player, thing, parents)
     dbref player;
     dbref thing;
     dbref *parents;		/* as in return from match_things; length
				 * at beginning. */
{
  int k,j;
  extern NALLOC *db_strings;
  int numparents;		/* number weactually need to allocate */
  int did_hear;
  did_hear = Hearer(thing);
  
  unparent(thing);
  
  numparents = parents[0]+1;	/* 1 for the NOTHING at the end */
  for (k=0; k<=parents[0]; k++)
    if (parents[k] == NOTHING)
      numparents--;

  db[thing].parents = malloc( sizeof(dbref)*(numparents));
  for (k=1, j=0; k<=parents[0]; k++, j++)
    if (parents[k] == NOTHING)
      j--;
    else
      db[thing].parents[j] = parents[k];
  db[thing].parents[j] = NOTHING;

  for (j=0; db[thing].parents[j]!=NOTHING; j++)
    PUSH_L(db[db[thing].parents[j]].children, thing);
  if (Hearer(thing) && !did_hear) {
    dbref *tmp;			/* terrible kludge. */
    tmp = db[thing].parents;
    db[thing].parents = NULL;
    make_hearing (thing);
    db[thing].parents = tmp;
  }
  if (did_hear && !Hearer(thing))
    notify_in [db[player].location, NOTHING,
		   tprintf("%s loses its ears and becomes deaf.",db[thing].name));

}

static void unparent (thing)
     dbref thing;
{
  int i;
  extern NALLOC *db_strings;

  if (!db[thing].parents) return;
  for (i=0; db[thing].parents[i] != NOTHING; i++)
    REMOVE_FIRST_L(db[db[thing].parents[i]].children, thing);
  malloc(db[thing].parents);
  db[thing].parents = NULL;
}
#endif