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/
/* create.c */
/* $Id: create.c,v 1.14 1994/01/26 05:39:15 nils Exp $ */

#include "db.h"
#include "config.h"
#include "interface.h"
#include "externs.h"

/* utility for open and link */
static dbref parse_linkable_room(player,room_name)
     dbref player;
 char *room_name;
{
  dbref room;
  
  /* skip leading NUMBER_TOKEN if any */
  if(*room_name == NUMBER_TOKEN) room_name++;
  
  /* parse room */
  if(!string_compare(room_name, "here")) {
    room = db[player].location;
  } else if(!string_compare(room_name, "home")) {
    return HOME;		/* HOME is always linkable */
  } else {
    room = parse_dbref(room_name);
  }
  
  /* check room */
  if(room < 0 || room >= db_top || Typeof(room)==TYPE_EXIT) {
    /* !!! if Wizard and unsafe do it any ways !!! */
    /*    if (power(player, TYPE_DIRECTOR) && unsafe)
	  return(room);*/
    if(room<0 || room>=db_top)
      notify(player,
	     tprintf("#% is not a valid object.",room));
    else
      notify(player,
	     tprintf("%s is an exit!",unparse_object(player,room)));
    return NOTHING;
  } else if(!can_link_to(player, room, POW_MODIFY)) {
    /* !!! ... !!! XX */
    /*    if (power(player, TYPE_DIRECTOR) && unsafe)
	  return(room);*/
    notify(player, tprintf("You can't link to %s.",
			   unparse_object(player,room)));
    return NOTHING;
  } else {
    return room;
  }
}

/* use this to create an exit */
void do_open(player,direction,linkto,pseudo)
     dbref player;
     char *direction;
     char *linkto;
     dbref pseudo;  /* a phony location for a player if a back exit is needed */
{
  dbref loc=(pseudo!=NOTHING) ? pseudo : db[player].location;
  dbref exit;
  dbref loczone;
  dbref linkzone;
  
  if ((loc==NOTHING) || (Typeof(loc)==TYPE_PLAYER))
    {
      notify(player,"Sorry you can't make an exit there.");
      return;
    }
  
#ifdef RESTRICTED_BUILDING
   if(!Builder(player)) {
    notify(player, "That command is restricted to authorized builders.");
    return;
  }
#endif /* RESTRICTED_BUILDING */
  
  if(!*direction) {
    notify(player, "Open where?");
    return;
  } else if(!ok_exit_name(direction)) {
    notify(player, tprintf("%s is a strange name for an exit!",direction));
    return;
  }
  
  if(!controls(player, loc, POW_MODIFY)) {
    notify(player, "Permission denied.");
  } else if ( can_pay_fees(def_owner(player), EXIT_COST, QUOTA_COST) ) {
    /* create the exit */
    exit = new_object();
    
    /* initialize everything */
    SET(db[exit].name,direction);
    db[exit].owner = def_owner(player);
    db[exit].zone = NOTHING;
    db[exit].flags = TYPE_EXIT|SEE_OK;
    db[exit].flags |= (db[db[exit].owner].flags & INHERIT_POWERS);
    check_spoofobj(player, exit);
    
    /* link it in */
    PUSH(exit, Exits(loc));
    db[exit].location = loc;
    db[exit].link = NOTHING;
    /* and we're done */
    notify(player, tprintf("%s opened.",direction));
    
    /* check second arg to see if we should do a link */
    if (*linkto != '\0') {
      if ((loc = parse_linkable_room(player, linkto)) != NOTHING) {
	if (!payfor(player, LINK_COST)) {
	  notify(player, "You don't have enough Credits to link.");
        } else {
	  loczone = get_zone_first(player);
	  linkzone = get_zone_first(loc);

	  /* it's ok, link it */
	  db[exit].link = loc;
	  notify(player, tprintf("Linked to %s.", unparse_object(player,loc)));
	}
      }
    }
  }
}

/* use this to link to a room that you own */
/* it seizes ownership of the exit */
/* costs 1 penny */
/* plus a penny transferred to the exit owner if they aren't you */
/* you must own the linked-to room AND specify it by room number */
void do_link(player,name,room_name)
     dbref player;
     char *name;
     char *room_name;
{
  dbref thing;
  dbref room;
  
  init_match(player, name, TYPE_EXIT);
  match_everything();
  
  if((thing = noisy_match_result()) != NOTHING) {
    switch(Typeof(thing)) {
    case TYPE_EXIT:
      if ( (room = parse_linkable_room(player, room_name)) == NOTHING)
	return;

      if ( (room!=HOME) && !controls(player,room,POW_MODIFY) &&
	  ! (db[room].flags & LINK_OK)) {
	notify(player,"Permission denied.");
	break;
      }
      
      /* we're ok, check the usual stuff */
      if(db[thing].link != NOTHING) {
	if(controls(player, thing, POW_MODIFY)) {
	  /*	  if(Typeof(db[thing].link) == TYPE_PLAYER)
		  notify(player, "That exit is being carried.");
		  else*/
	  notify(player, tprintf("%s is already linked.",
				 unparse_object(player,thing)));
	} else {
	  notify(player, "Permission denied.");
	}
      } else {
	/* handle costs */
	if(db[thing].owner == db[player].owner) {
	  if(!payfor(player, LINK_COST)) {
	    notify(player,
		   "It costs a Credit to link this exit.");
	    return;
	  }
	} else {
	  if ( ! can_pay_fees(def_owner(player),
			      LINK_COST+EXIT_COST, QUOTA_COST) )
	    return;
#ifdef RESTRICTED_BUILDING
	  else if(!Builder(player))
	    notify(player,
		   "Only authorized builders may seize exits.");
#endif /* RESTRICTED_BUILDING */
	  else {
	    /* pay the owner for his loss */
	    giveto(db[thing].owner, EXIT_COST);
	    add_quota(db[thing].owner, QUOTA_COST);
	  }
	}
	
	/* link has been validated and paid for; do it */
	db[thing].owner = def_owner(player);
	db[thing].link = room;
	
	/* notify the player */
	notify(player, tprintf("%s linked to %s.",
			       unparse_object_a(player,thing),
			       unparse_object_a(player,room)));
      }
      break;
    case TYPE_PLAYER:
    case TYPE_THING:
      init_match(player, room_name, NOTYPE);
      match_exit();
      match_neighbor();
      match_possession();
      match_me();
      match_here();
      match_absolute();
      match_player();
      if ((room=noisy_match_result())<0)
	{
	  /*	  notify(player,"No match."); noisy_match_result talks bout it */
	  return;
	}
      if (Typeof(room)==TYPE_EXIT)
	{
	  notify(player,tprintf("%s is an exit.",unparse_object(player,room)));
	  return;
	}
      /* abode */
      if (!controls(player,room,POW_MODIFY) &&
	  !(db[room].flags&LINK_OK)) {
	notify(player,"Permission denied.");
	break;
      }
      if(!controls(player, thing, POW_MODIFY)
	 && ((db[thing].location!=player) || !(db[thing].flags & LINK_OK ))) {
	notify(player, "Permission denied.");
      } else if(room == HOME) {
	notify(player, "Can't set home to home.");
      } else {
	/* do the link */
	db[thing].link = room; /* home */
	notify(player, tprintf("Home set to %s.",unparse_object(player,room)));
      }
      break;
    case TYPE_ROOM:
      if((room = parse_linkable_room(player, room_name)) == NOTHING) return;
      
      if (Typeof(room)!=TYPE_ROOM)
	{
	  notify(player,tprintf("%s is not a room!",
				unparse_object(player,room)));
	  return;
	}
      if ((room!=HOME) && !controls(player,room,POW_MODIFY) &&
	  !(db[room].flags & LINK_OK)) {                                    
	notify(player,"Permission denied.");
	break;
      }
      if(!controls(player, thing, POW_MODIFY)) {
	notify(player, "Permission denied.");
      } else {
	/* do the link, in location....no, in link! yay! */
	db[thing].link = room; /* dropto */
	notify(player, tprintf("Dropto set to %s.",
			       unparse_object(player,room)));
      }
      break;
    default:
      notify(player, "Internal error: weird object type.");
      log_error(tprintf("PANIC weird object: Typeof(%d) = %d",
			thing, Typeof(thing)));
      report();
      break;
    }
  }
}

/* Links a room to a "zone object" */
void do_zlink(player, arg1, arg2)
     dbref player;
     char *arg1;
     char *arg2;
{
  dbref room;
  dbref object;
  dbref old_zone;

  init_match(player, arg1, TYPE_ROOM);
  match_here();
  match_absolute();
  if ((room = noisy_match_result()) != NOTHING) {
    init_match(player, arg2, TYPE_THING);
    match_neighbor();
    match_possession();
    match_absolute();
    old_zone = get_zone_first(room);
    if ((object = noisy_match_result()) != NOTHING) {
      if ((!(controls(player,room,POW_MODIFY) &&
          controls(player,object,POW_MODIFY)))
	  || (Typeof(room)!=TYPE_ROOM && Typeof(room)!=TYPE_THING &&
	      !power(player,POW_SECURITY))) {
        notify(player, "Permission denied.");
      } else if (is_in_zone(object, room)) {
	notify(player,"I think you're feeling a bit loopy.");
      } else {
	if (db[object].zone == NOTHING && object != db[0].zone)
	  db[object].zone = db[0].zone; /* silly person doesn't know
					 * how to set up a zone
					 * right.. */
        db[room].zone = object;
        notify(player, tprintf("%s zone set to %s", db[room].name,
               db[object].name));
      }
    }
  }
}

void do_unzlink(player, arg1)
     dbref player;
     char *arg1;
{
  dbref room;

  init_match(player, arg1, TYPE_ROOM);
  match_here();
  match_absolute();
  if ((room = noisy_match_result()) != NOTHING) {
    if (!controls(player, room, POW_MODIFY)) {
      notify(player, "Permission denied.");
    } else {
      if (Typeof(room) == TYPE_ROOM)
	db[room].zone = db[0].zone;
      else
	db[room].zone = NOTHING;
      notify(player, "Zone unlinked.");
    }
  }
  return;
}

/* special link - sets the universal zone */
void do_ulink(player, arg1)
dbref player;
char *arg1;
{
  dbref thing, p, oldu;

  if (player != GOD) {
    notify(player, "You don't have the authority. So sorry.");
    return;
  }
  init_match(player, arg1, TYPE_THING);
  match_possession();
  match_neighbor();
  match_absolute();
  if ((thing = noisy_match_result()) != NOTHING) {
    oldu = db[0].zone;
    db[0].zone = thing;
    for (p = 0; p < db_top; p++)
      if ((Typeof(p) == TYPE_ROOM) && !(db[p].flags & GOING) &&
          ((db[p].zone == oldu) || (db[p].zone == NOTHING)))
         db[p].zone = thing;
  }
  db[thing].zone = NOTHING;
  notify(player, tprintf("Universal zone set to %s.", db[thing].name));
}

/* use this to create a room */
void do_dig(player,name,argv)
     dbref player;
     char *name;          
     char *argv[];
{
  dbref room;
  dbref where;
  
#ifdef RESTRICTED_BUILDING
  if(!Builder(player)) {
    notify(player, "That command is restricted to authorized builders.");
    return;
  }
#endif /* RESTRICTED_BUILDING */
  
  /* we don't need to know player's location!  hooray! */
  where = db[player].location;  /* MMZ */
  if(*name == '\0') {
    notify(player, "Dig what?");
  } else if(!ok_room_name(name)) {
    notify(player, "That's a silly name for a room!");
  } else if ( can_pay_fees(def_owner(player), ROOM_COST, QUOTA_COST) ) {
    room = new_object();
    
    /* Initialize everything */
    SET(db[room].name,name);
    db[room].owner = def_owner(player);
    db[room].flags = TYPE_ROOM|SEE_OK;
    db[room].location = room;
    db[room].zone = db[where].zone;
    db[room].flags |= (db[db[room].owner].flags & INHERIT_POWERS);
    check_spoofobj(player,room);
    notify(player,
	   tprintf("%s created with room number %d.", name, room));
    if (argv[1] && *argv[1]) {
      char nbuff[50];
      sprintf(nbuff,"%d",room);
      do_open(player,argv[1],nbuff,NOTHING);
    } 
    if (argv[2] && *argv[2]) {
      char nbuff[50];
      sprintf(nbuff,"%d",db[player].location);
      do_open(player,argv[2],nbuff,room);
    }            
  }
}

void check_spoofobj(player, thing)
     dbref player, thing;
{
  dbref p;
  if ((p=starts_with_player(db[thing].name))!=NOTHING && !controls(player,p,POW_SPOOF) && !(db[thing].flags&HAVEN)) {
	notify(player,tprintf("Warning: %s can be used to spoof an existing player. It has as been set haven.",unparse_object(player,thing)));
	db[thing].flags |= HAVEN;
      }
}

/* use this to create an object */
void do_create(player,name,cost)
     dbref player;
     char *name;
     int cost;
{
  dbref loc;
  dbref thing;
  
#ifdef RESTRICTED_BUILDING
  if(!Builder(player)) {
    notify(player, "That command is restricted to authorized builders.");
    return;
  }
#endif /* RESTRICTED_BUILDING */
  
  if(*name == '\0') {
    notify(player, "Create what?");
    return;
  } else if(!ok_thing_name(name)) {
    notify(player, "That's a silly name for a thing!");
    return;
  } else if(cost < 0) {
    notify(player, "You can't create an object for less than nothing!");
    return;
  } else if(cost < OBJECT_COST)
    cost = OBJECT_COST;
  
  if ( can_pay_fees(def_owner(player), cost, QUOTA_COST) )  {
    /* create the object */
    thing = new_object();
    
    /* initialize everything */
    SET(db[thing].name,name);
    db[thing].location = player;
    db[thing].zone = NOTHING;
    db[thing].owner = def_owner(player);
    s_Pennies(thing,OBJECT_ENDOWMENT(cost));
    db[thing].flags = TYPE_THING|SEE_OK;
    db[thing].flags |= (db[db[thing].owner].flags & INHERIT_POWERS);
    check_spoofobj(player, thing);
    /* endow the object */
    if(Pennies(thing) > MAX_OBJECT_ENDOWMENT) {
      s_Pennies(thing,MAX_OBJECT_ENDOWMENT);
    }
    
    /* home is here (if we can link to it) or player's home */
    if((loc = db[player].location) != NOTHING
       && controls(player, loc, POW_MODIFY)) {
      db[thing].link = loc;
    } else {
      db[thing].link = db[player].link;
    }
    
    db[thing].exits = NOTHING;
    /* link it in */
    PUSH(thing, db[player].contents);
    
    /* and we're done */
    notify(player, tprintf("%s created.",unparse_object(player,thing)));
  }
}


void do_clone(player,arg1,arg2)
     dbref player;
     char *arg1;
     char *arg2;
{
  dbref clone,thing;
  
  if ( Guest(db[player].owner) )  {
    notify(player, "Guests can't clone objects\n");
    return;
  }
#ifdef RESTRICTED_BUILDING  
  if (!Builder(player)) {
    notify(player,"Command is for builders only.");
    return;
  }       
#endif   
  init_match(player, arg1, NOTYPE);
  match_everything();
  
  thing = noisy_match_result();
  if ((thing==NOTHING) || (thing==AMBIGUOUS))
    return;
  
  if( !controls(player, thing, POW_SEEATR)) {
    notify(player, "Permission denied.");
    return;
  }    
  if (Typeof(thing)!=TYPE_THING) {
    notify(player,"You can only clone things.");
    return;
  }
  if(!can_pay_fees(def_owner(player),OBJECT_COST,QUOTA_COST)) {
    notify(player,"you've not enough money.");
    return;
  }
  clone=new_object();
  memcpy(&db[clone],&db[thing],sizeof(struct object));
  db[clone].name=NULL;
  db[clone].owner = def_owner(player);
  db[clone].flags&=~(HAVEN|BEARING); /* common parent flags */
  if (!(db[player].flags&INHERIT_POWERS)) db[clone].flags&=~INHERIT_POWERS;
  SET(db[clone].name,(*arg2)?arg2:db[thing].name);
  check_spoofobj(player,clone);
  s_Pennies(clone,1);
  atr_cpy_noninh(clone,thing);	/* copies the noninherited attributes. */
  db[clone].contents=db[clone].location=db[clone].next=NOTHING;
  db[clone].atrdefs = NULL;
  db[clone].parents = NULL;
  db[clone].children = NULL;
  PUSH_L (db[clone].parents, thing);
  PUSH_L (db[thing].children, clone);
  notify(player,tprintf("%s cloned with number %d.",
			unparse_object(player,thing),clone));
  moveto(clone,db[player].location);
  did_it(player,clone,NULL,NULL,NULL,NULL,A_ACLONE);
}

void do_robot(player,name,pass)
     dbref player;
     char *name;
     char *pass;
{
  dbref thing;
#ifdef RESTRICTED_BUILDING
  if (!Builder(player)) {
    notify(player,"Only builders can make robots.");
    return;
  }       
#endif
  if (!power(player,POW_PCREATE)) {
    notify(player,"You can't make robots.");
    return;
  }
  if ( ! can_pay_fees(def_owner(player), ROBOT_COST, QUOTA_COST) ) {
    notify(player,"Sorry you don't have enough money to make a robot.");
    return;
  }
  if ((thing=create_player(name,pass,CLASS_VISITOR))==NOTHING) {
    giveto(player,ROBOT_COST);
    add_quota(player, QUOTA_COST);
    notify(player,tprintf("%s already exists.",name));
    return;
  }
  db[thing].owner=db[player].owner;
  atr_clr(thing, A_RQUOTA);
  enter_room(thing,db[player].location);
  notify(player,tprintf("%s has arrived.",unparse_object(player,thing)));
}