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/
/* move.c */
/* $Id: move.c,v 1.10 1993/09/18 19:04:11 nils Exp $ */

#include "copyright.h"

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

void moveto(what,where)
     dbref what;
     dbref where;
{
  enter_room(what,where);
}

void moveit(what,where)
     dbref what;
     dbref where;
{
  dbref loc,old;
  if(Typeof(what) == TYPE_EXIT && Typeof(where)==TYPE_PLAYER) {
    log_error("moving exit to player");
    report();
    return;
  }
  /* remove what from old loc */
  if((loc = old = db[what].location) != NOTHING) {
    if (Typeof(what) == TYPE_EXIT)
      db[loc].exits = remove_first(db[loc].exits, what);
    else
      db[loc].contents = remove_first(db[loc].contents, what);
    if (Hearer(what) && (old != where))
      did_it(what,loc,A_LEAVE,NULL,A_OLEAVE,Dark(old)?NULL:"has left.",A_ALEAVE);
    db[loc].contents = remove_first(db[loc].contents, what);
  }
  
  /* test for special cases */
  switch(where) {
  case NOTHING:
    db[what].location = NOTHING;
    return;			/* NOTHING doesn't have contents */
  case HOME:
    if(Typeof(what) == TYPE_EXIT || Typeof(what) == TYPE_ROOM)
      return;
    where = db[what].link;	/* home */
    break;
  }
  
  /* now put what in where */
  if (Typeof(what) == TYPE_EXIT)
    PUSH(what,db[where].exits);
  else
    PUSH(what, db[where].contents);
  
  db[what].location = where;
  if (Hearer(what) && (where!=NOTHING) && (old!=where))
    did_it(what,where,A_ENTER,NULL,A_OENTER,Dark(where)?NULL:"has arrived.",
	   A_AENTER);
}
extern void enter_room();

#define Dropper(thing) (Hearer(thing) && (db[db[thing].owner].flags & PLAYER_CONNECT))
    
void send_contents(loc,dest)
     dbref loc;
     dbref dest;
{
  dbref first;
  dbref rest;
  
  first = db[loc].contents;
  db[loc].contents = NOTHING;
  
  /* blast locations of everything in list */
  DOLIST(rest, first) {
    db[rest].location = NOTHING;
  }
  
  while(first != NOTHING) 
    {
      rest = db[first].next;
      if (Dropper(first))
	{
	  db[first].location=loc;
	  PUSH(first,db[loc].contents);
	}
      else 
	enter_room(first,(db[first].flags & STICKY) ? HOME : dest);
      first = rest;
    }
  
  db[loc].contents = reverse(db[loc].contents);
}

void maybe_dropto(loc,dropto)
     dbref loc;
     dbref dropto;
{
  dbref thing;
  
  if(loc == dropto) return;	/* bizarre special case */
  if (Typeof(loc)!=TYPE_ROOM)
    return;
  /* check for players */
  DOLIST(thing, db[loc].contents) {
    if(Dropper(thing))
      return;
  }
  
  /* no players, send everything to the dropto */
  send_contents(loc, dropto);
}

void enter_room(player,loc)
     dbref player;
     dbref loc;
{
  dbref old;
  dbref zon;
  dbref dropto;
  int a1=0,a2=0,a3=0,a4=0,a5=0,a6=0;
  static int deep=0;

  if(Typeof(player) == TYPE_ROOM) {
    notify(player, "Sorry, rooms aren't allowed to move.");
    return;
  }
  if (deep++>15)
    {
      deep--;
      return;
    }
  if (Typeof(loc)==TYPE_EXIT)
    {
      log_error(tprintf("Attempt to move %d to exit %d",player,loc));
      report();
      deep--;
      return;
    }
  /* check for room == HOME */
  if(loc == HOME) loc = db[player].link; /* home */
  
  /* get old location */
  old = db[player].location;
  
  /* check for self-loop */
  /* self-loops don't do move or other player notification */
  /* but you still get autolook and penny check */
  /*  if ((loc != old) && (old != NOTHING) && hear)
      {
      * notify others unless DARK *
      if(!Dark(old) && !Dark(player)) 
      {
      notify_in(old, player, 
      tprintf("%s has left.", db[player].name));
      }
      }*/
  
  /* go there */
  if (loc != old)
    did_it(player,player,A_MOVE,NULL,A_OMOVE,NULL,A_AMOVE);
  moveit(player, loc);
  if (loc != old)
    DOZONE(zon, player)
      did_it(player,zon,A_MOVE,NULL,A_OMOVE,NULL,A_AMOVE);
  
  /* if old location has STICKY dropto, send stuff through it */
  
  if((a1=(loc!=old)) && (a2=Dropper(player)) &&
     (a3=(old != NOTHING)) && (a4=(Typeof(old)==TYPE_ROOM))
     && (a5=((dropto = db[old].location) != NOTHING))
     && (a6=(db[old].flags & STICKY))) 
    maybe_dropto(old, dropto);
  
  
  /* autolook */
  look_room(player, loc);
  deep--;
}


/* teleports player to location while removing items they shouldnt take */
void safe_tel(player,dest)                                              
     dbref player;
     dbref dest;
{
  dbref first;
  dbref rest;                     
  if(Typeof(player)==TYPE_ROOM) return;
  if (dest==HOME)
    dest=db[player].link;
  if (db[db[player].location].owner==db[dest].owner)
    {
      enter_room(player,dest);
      return;
    }
  
  first = db[player].contents;
  db[player].contents = NOTHING;
  
  /* blast locations of everything in list */
  DOLIST(rest, first) {
    db[rest].location = NOTHING;
  }
  
  while(first != NOTHING) {
    rest = db[first].next;
    /* if thing is ok to take then move to player else send home */
    if (controls(player,first,POW_MODIFY) || 
	(!(IS(first,TYPE_THING,THING_KEY)) && !(db[first].flags & STICKY)))
      {
	PUSH(first,db[player].contents);
	db[first].location=player;
      }
    else                
      enter_room(first,HOME);
    first=rest;
  }
  db[player].contents = reverse(db[player].contents);
  enter_room(player,dest);
}

int can_move(player,direction)
     dbref player;
 char *direction;
{
  if(Typeof(player)==TYPE_ROOM) {
    return 0;
  }
  if(!string_compare(direction, "home"))
    return 1;
  
  /* otherwise match on exits */
  init_match(player, direction, TYPE_EXIT);
  match_exit();
  return(last_match_result() != NOTHING);
}

void do_move(player,direction)
     dbref player;
     char *direction;
{
  dbref exit;
  dbref loc;
  dbref zresult;
  dbref old=db[player].location;
  
  if(Typeof(player)==TYPE_ROOM) {
    notify(player, "Sorry, rooms aren't allowed to move.");
    return;
  }
  
  if(!string_compare(direction, "home")) {
    /* send him home */
    /* but steal all his possessions */
    if (Typeof(player) == TYPE_ROOM ||
	Typeof(player)==TYPE_EXIT)
      return;
    
    if (!check_zone(player, player, db[player].link, 2)) return;

    if(((loc = db[player].location) != NOTHING) &&
	 !IS(loc,TYPE_ROOM,ROOM_AUDITORIUM)) {
      /* tell everybody else */
      notify_in(loc, player, 
		    tprintf("%s goes home.",db[player].name));
    }
    /* give the player the messages */
    notify(player, "There's no place like home...");
    notify(player, "There's no place like home...");
    notify(player, "There's no place like home...");
    safe_tel(player,HOME);
  } else {
    /* find the exit */
    init_match_check_keys(player, direction, TYPE_EXIT);
    match_exit();
    switch(exit = match_result()) {
    case NOTHING:
      /* try to force the object */
      notify(player, "You can't go that way.");
      break;
    case AMBIGUOUS:
      notify(player, "I don't know which way you mean!");
      break;
    default:
      /* we got one */
      /* check to see if we got through */
      if(could_doit(player, exit, A_LOCK)) {
	if ((zresult = check_zone(player, player, db[exit].link, 0))) {
	  did_it(player,exit,A_SUCC,NULL,A_OSUCC,(db[exit].flags&DARK)?NULL:glurpdup(tprintf("goes through the exit marked %s.",main_exit_name(exit))),A_ASUCC);
	  switch(Typeof(db[exit].link)) {
	  case TYPE_ROOM:
	    enter_room(player, db[exit].link);
	    break;
	  case TYPE_PLAYER:
	  case TYPE_THING:
	    if (db[db[exit].link].flags & GOING) {
	      notify(player,"You can't go that way.");
	      return;
	    }
	    if (db[db[exit].link].location==NOTHING)
	      return;             
	    safe_tel(player,db[exit].link);
	    break;
	  case TYPE_EXIT:
	    notify(player,"This feature coming soon.");
	    break;
	  }
	  did_it(player,exit,A_DROP,NULL,A_ODROP,(db[exit].flags&DARK)?NULL:glurpdup(tprintf("arrives from %s.",db[old].name)),A_ADROP);
	  if (zresult > (dbref) 1)
	    /* we entered a new zone */
	    did_it(player,zresult,A_DROP,NULL,A_ODROP,NULL,A_ADROP);
	}
      } else
	did_it(player,exit,A_FAIL,"You can't go that way.",
	       A_OFAIL,NULL,A_AFAIL);
      break;
    }
  }
}

void do_get(player,what)
     dbref player;
 char *what;
{
  dbref thing;
  dbref loc=db[player].location;
  if(Typeof(player)==TYPE_EXIT) {
    notify(player,"You can't pick up things!");
    return;
  }
  if ((Typeof(loc)!=TYPE_ROOM) && !(db[loc].flags & ENTER_OK) &&
      !controls(player,loc,POW_TELEPORT)) {
    notify(player,"Permission denied.");
    return;
  }
  init_match_check_keys(player, what, TYPE_THING);
  match_neighbor();
  match_exit();
  if(power(player, POW_TELEPORT))
    match_absolute(); /* the wizard has long fingers */
  
  if((thing = noisy_match_result()) != NOTHING) {
    if(db[thing].location == player) {
      notify(player, "You already have that!");
      return;
    }
    switch(Typeof(thing)) {
    case TYPE_PLAYER:
    case TYPE_THING:
      if(could_doit(player, thing, A_LOCK)) {
	moveto(thing, player);
	notify(thing,tprintf("You have been picked up by %s.",
			     unparse_object(thing,player)));
	did_it(player,thing,A_SUCC,"Taken.",A_OSUCC,NULL,A_ASUCC);
      } else
	did_it(player,thing,A_FAIL,"You can't pick that up.",
	       A_OFAIL,NULL,A_AFAIL);
      break;
    case TYPE_EXIT:
      notify(player,"You can't pick up exits.");
      return;
    default:
      notify(player, "You can't take that!");
      break;
    }
  }
}


void do_drop(player,name)
     dbref player;
 char *name;
{
  dbref loc;
  dbref thing;
  char buf[BUFFER_LEN];
  int reward;
  
  if((loc = getloc(player)) == NOTHING) return;
  
  init_match(player, name, TYPE_THING);
  match_possession();
  
  switch(thing = match_result()) {
  case NOTHING:
    notify(player, "You don't have that!");
    return;
  case AMBIGUOUS:
    notify(player, "I don't know which you mean!");
    return;
  default:
    if(db[thing].location != player) {
      /* Shouldn't ever happen. */
      notify(player, "You can't drop that.");
    } else if(Typeof(thing) == TYPE_EXIT) {
      notify(player,"Sorry you can't drop exits.");
      return;
    } else if((db[loc].flags & ROOM_TEMPLE) &&
             (IS(thing,TYPE_THING,THING_SACROK))) {
      /* sacrifice time */
      notify(thing,"You dissolve forever into the wispy aether of space and time.");
      db[thing].flags = TYPE_THING|GOING;
      enter_room(thing,NOTHING);
      notify_in(loc,NOTHING,
		    tprintf("%s drops %s and it dissolves forever into the wispy aether of space and time.", db[player].name,db[thing].name));
      
      /* check for reward */
      if( db[player].owner != db[thing].owner) {
	reward = Pennies(thing);
	if(reward < 1 || (Pennies(db[player].owner) > MAX_PENNIES)) {
	  reward = 1;
	} else if(reward > MAX_OBJECT_ENDOWMENT) {
	  reward = MAX_OBJECT_ENDOWMENT;
	}
	if(payfor(db[thing].owner,reward)) {
	  giveto(db[player].owner,reward);
	  notify(player,
		 tprintf("You have received %d %s.",
			 reward, reward == 1 ? "credit" : "credits"));
	}
      }
      do_empty(thing);
      do_halt(thing,"");
    } else if(db[thing].flags & STICKY) {
      notify(thing,"Dropped.");
      safe_tel(thing,HOME);        
    } else if(db[loc].link != NOTHING && 
	      (Typeof(loc)==TYPE_ROOM) && !(db[loc].flags & STICKY)) {
      /* location has immediate dropto */
      notify(thing,"Dropped.");
      moveto(thing, db[loc].link);
    } else {                     
      notify(thing,"Dropped.");
      enter_room(thing, loc);
      /*	    sprintf(buf, "%s dropped %s.", db[player].name, db[thing].name);
		    notify_in(loc, player, buf);*/
    }
    break;
  }                                                      
  sprintf(buf,"dropped %s.",db[thing].name);    
  did_it(player,thing,A_DROP,"Dropped.",A_ODROP,buf,A_ADROP);   
}

void do_enter(player,what)
     dbref player;
 char *what;
{
  dbref thing;

  init_match_check_keys(player, what, TYPE_THING);
  match_neighbor();
  match_exit();
  if(power(player, POW_TELEPORT))
    match_absolute(); /* the wizard has long fingers */
  
  if((thing = noisy_match_result()) == NOTHING) 
    {
      /*  notify(player,"I don't see that here.");   */
      return;
    } 
  switch(Typeof(thing))
    {
    case TYPE_ROOM:
    case TYPE_EXIT:
      notify(player,"Permission denied.");
      break;
    default:
      if (!(db[thing].flags & ENTER_OK) && !controls(player,thing,POW_TELEPORT))
	{
	  did_it(player, thing, A_EFAIL, "You can't enter that.", A_OEFAIL,
		 NULL, A_AEFAIL);
	  return;
	}
      if(could_doit(player,thing,A_ELOCK) && 
	check_zone(player, player, thing, 0)) {
	safe_tel(player,thing);
      } else {
	did_it(player, thing, A_EFAIL, "You can't enter that.", A_OEFAIL,
	       NULL, A_AEFAIL);
      }
      break;
    }
}          

void do_leave(player)
     dbref player;
{
  if (Typeof(db[player].location)==TYPE_ROOM ||
      db[db[player].location].location == NOTHING)
    {
      notify(player,"You can't leave");
      return;
    }       
  if(could_doit(player, db[player].location, A_LLOCK)) {
    enter_room(player,db[db[player].location].location);
  } else {
    did_it(player, db[player].location, A_LFAIL, "You can't leave.", A_OLFAIL,
	   NULL, A_ALFAIL);
  }
}

/* Find the object holding thing */
dbref inside(thing)
  dbref thing;
  {
    int depth=10;
    dbref holder;
    for(holder = thing; depth; depth--, holder = thing, 
	thing = db[holder].location)
    if(Typeof(thing) == TYPE_ROOM) {
      return holder;
    }
    return (dbref) 0;
  }

/* Find the room the object/player is in */
dbref get_room(thing)
  dbref thing;
  {
    int depth=10;
    dbref holder;
    for(holder = thing; depth; depth--, holder = thing, 
	thing = db[holder].location)
    if(Typeof(thing) == TYPE_ROOM) {
      return thing;
    }
    return (dbref) 0;
  }

/* End move.c */