/
Archipelago/
Archipelago/doc/
Archipelago/lib/misc/
Archipelago/lib/plrobjs/
Archipelago/lib/plrobjs/P-T/
Archipelago/lib/world/mob/
Archipelago/lib/world/obj/
Archipelago/lib/world/shp/
Archipelago/lib/world/wld/
Archipelago/lib/world/zon/
Archipelago/slave/
/* ************************************************************************
*   File: act.movement.c                                Part of CircleMUD *
*  Usage: movement commands, door handling, & sleep/rest/etc state        *
*                                                                         *
*  All rights reserved.  See license.doc for complete information.        *
*                                                                         *
*  Copyright (C) 1993 by the Trustees of the Johns Hopkins University     *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */
/* Archipelago changes by Alastair J. Neil Copyright (C) 1993, 94, 95, 96 */
#include <stdio.h>
#include <string.h>

#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"

/* external vars  */
extern struct room_data *world;
extern struct char_data *character_list;
extern struct descriptor_data *descriptor_list;
extern struct index_data *obj_index;
extern struct str_app_type str_app[];
extern int	rev_dir[];
extern char	*dirs[],*revdirs[];
extern int	movement_loss[];
extern int      top_of_world;
/* external functs */
char    *first_name(char *arg);
int	special(struct char_data *ch, int cmd, char *arg);
void	death_cry(struct char_data *ch);
void    add_event(int plse, int event, int inf1, int inf2, int inf3
	       , int inf4, char *arg, void *subj, void *vict);
void	rmdamage(struct char_data *victim, int dam);
bool    fall_down(struct char_data *ch);

bool    fall_down(struct char_data *ch)
{
  int fall, down_room;
  
  fall = number(0,30);
  fall -= (IS_CARRYING_W(ch)+GET_WEIGHT(ch))/100;
  fall += GET_DEX(ch)/2;              
  fall += GET_STR(ch)/2;
  fall += GET_FOC(ch)/2;
  fall += GET_SKILL(ch,SKILL_CLIMB);
  down_room = NOWHERE;
  if (CAN_GO(ch,5))
    down_room = EXIT(ch,5)->to_room;
  else
    return(FALSE);
  if (down_room != NOWHERE){
    if (IS_SET(world[ch->in_room].room_flags, CLIMB_MODERATE))
      {
	if (fall < 3 && !IS_AFFECTED(ch, AFF_FLY))
	  {
	    if (!number(0,5)){
	      act("Suddenly you nearly fall! but you catch yourself."
		  ,TRUE,ch,0,0,TO_CHAR);
	      act("Suddenly $n nearly falls! but catches $mself."
		  ,TRUE,ch,0,0,TO_ROOM);
	      if (!IS_AFFECTED(ch,AFF_FLY)){
		act("You learn a new climbing move.",TRUE,ch,0,0,TO_CHAR);
		SET_SKILL(ch,SKILL_CLIMB,MIN(30,GET_SKILL(ch,SKILL_CLIMB)
					     + number (0,1)));}
	      return(FALSE);
	    }
	    
	    act("\r\nSuddenly you fall!!",TRUE,ch,0,0,TO_CHAR);
	    act("\r\n$n falls!!",TRUE,ch,0,0,TO_ROOM);
	    if (down_room)
	      {
		char_from_room(ch);
		char_to_room(ch,down_room, TRUE);
		act("\r\n$n falls down from above!",TRUE,ch,0,0,TO_ROOM);
		do_look(ch,"",0,0);
		GET_POS(ch) = POSITION_SITTING;
	      }
	    SET_SKILL(ch,SKILL_CLIMB,GET_SKILL(ch,SKILL_CLIMB)
		      - number(0,1));
	    rmdamage(ch,4*GET_MAX_HIT(ch)/10 + number(5,20));
	    act("you lose some confidence",TRUE,ch,0,0,TO_CHAR);
	  }
      }
    if (IS_SET(world[ch->in_room].room_flags, CLIMB_HARD))
      {
	if (fall < 35 && !IS_AFFECTED(ch, AFF_FLY))
	  {
	    if (!number(0,5)){
	      act("Suddenly you nearly fall! but you catch yourself."
		  ,TRUE,ch,0,0,TO_CHAR);
	      act("Suddenly $n nearly falls! but catches $mself."
		  ,TRUE,ch,0,0,TO_ROOM);
	      if (!IS_AFFECTED(ch,AFF_FLY)){
		act("You learn a new climbing move.",TRUE,ch,0,0,TO_CHAR);
		SET_SKILL(ch,SKILL_CLIMB,MIN(30,GET_SKILL(ch,SKILL_CLIMB)
					     + number (0,1)));}
	      return(FALSE);
	    }
	    
	    act("\r\nSuddenly you fall!!",TRUE,ch,0,0,TO_CHAR);
	    act("\r\n$n falls!!",TRUE,ch,0,0,TO_ROOM);
	    if (down_room)
	      {
		char_from_room(ch);
		char_to_room(ch,down_room, TRUE);
		act("\r\n$n falls down from above!",TRUE,ch,0,0,TO_ROOM);
		do_look(ch,"",0,0);
		GET_POS(ch) = POSITION_SITTING;
	      }
	    SET_SKILL(ch,SKILL_CLIMB,GET_SKILL(ch,SKILL_CLIMB)
		      - number(0,1));
	    rmdamage(ch,6*GET_MAX_HIT(ch)/10 + number(20,50));
	    act("you lose some confidence",TRUE,ch,0,0,TO_CHAR);
	  }
      }
    if (IS_SET(world[ch->in_room].room_flags, CLIMB_SEVERE))
      {
	if (fall < 50 && !IS_AFFECTED(ch, AFF_FLY))
	  {
	    if (!number(0,5)){
	      act("Suddenly you nearly fall! but you catch yourself."
		  ,TRUE,ch,0,0,TO_CHAR);
	      act("Suddenly $n nearly falls! but catches $mself."
		  ,TRUE,ch,0,0,TO_ROOM);
	      if (!IS_AFFECTED(ch,AFF_FLY)){
	      act("You learn a new climbing move.",TRUE,ch,0,0,TO_CHAR);
	      SET_SKILL(ch,SKILL_CLIMB,MIN(30,GET_SKILL(ch,SKILL_CLIMB)
					   + number (0,1)));}
	      return (FALSE);
	    }
	    
	    act("\r\nSuddenly you fall!!",TRUE,ch,0,0,TO_CHAR);
	    act("\r\n$n falls!!",TRUE,ch,0,0,TO_ROOM);
	    if (down_room)
	      {
		char_from_room(ch);
		char_to_room(ch,down_room, TRUE);
		act("\r\n$n falls down from above!",TRUE,ch,0,0,TO_ROOM);
		do_look(ch,"",0,0);
		GET_POS(ch) = POSITION_SITTING;
	      }
	    SET_SKILL(ch,SKILL_CLIMB,GET_SKILL(ch,SKILL_CLIMB)
		      - number(0,1));
	    rmdamage(ch,9*GET_MAX_HIT(ch)/10 + number(50,100));
	    act("you lose some confidence",TRUE,ch,0,0,TO_CHAR);
	  }
      }
    if (IS_SET(world[ch->in_room].room_flags, CLIMB_EXTREME))
      {
	if (fall < 75 && !IS_AFFECTED(ch, AFF_FLY))
	  {
	    if (!number(0,5)){
	      act("Suddenly you nearly fall! but you catch yourself."
		  ,TRUE,ch,0,0,TO_CHAR);
	      act("Suddenly $n nearly falls! but catches $mself."
		  ,TRUE,ch,0,0,TO_ROOM);
	      if (!IS_AFFECTED(ch,AFF_FLY)){
		act("You learn a new climbing move.",TRUE,ch,0,0,TO_CHAR);
		SET_SKILL(ch,SKILL_CLIMB,MIN(30,GET_SKILL(ch,SKILL_CLIMB)
					     + number (0,2)));}
	      return(FALSE);
	    }
	    act("\r\nSuddenly you fall!!",TRUE,ch,0,0,TO_CHAR);
	    act("\r\n$n falls!!",TRUE,ch,0,0,TO_ROOM);
	    if (down_room)
	      {
		char_from_room(ch);
		char_to_room(ch,down_room, TRUE);
		act("\r\n$n falls down from above!",TRUE,ch,0,0,TO_ROOM);
		do_look(ch,"",0,0);
		GET_POS(ch) = POSITION_SITTING;
	      }
	    SET_SKILL(ch,SKILL_CLIMB,GET_SKILL(ch,SKILL_CLIMB)
		      - number(1,2));
	    rmdamage(ch,49*GET_MAX_HIT(ch)/50 + number(100,200));
	    act("you lose some confidence",TRUE,ch,0,0,TO_CHAR);
	  }
      }
    return(TRUE);
  }
  return(FALSE);   
}

bool throw_rider(struct char_data *ch) {
  int num;
  struct char_data *tmp;
  
  if (!ch->specials.mount)
    return(FALSE);
  
  if (GET_SKILL(ch, SKILL_RIDING) < (num = number(0,31)) && !number(0,31)) 
    if (GET_SKILL(ch, SKILL_RIDING) < (num = number(0,31))) {
      act("$N slips and throws $n!", FALSE,ch,0,ch->specials.mount,TO_ROOM);
      act("$N slips and throws you!", FALSE,ch,0,ch->specials.mount,TO_CHAR);
      act("You slip and throws $n!", FALSE,ch,0,ch->specials.mount,TO_VICT);
      GET_POS(ch) = POSITION_SITTING;
      rmdamage(ch,GET_HEIGHT(ch->specials.mount)/number(5,20));
      if (num == 0 && (number(0,31) == 0)
	  && (number(0,31) > GET_SKILL(ch, SKILL_RIDING))
	  && (GET_SKILL(ch, SKILL_RIDING) < 30)) {
	send_to_char("You realise how you can improve your riding technique\r\n.",ch);
	SET_SKILL(ch, SKILL_RIDING,(GET_SKILL(ch,SKILL_RIDING) + 1));
	rmdamage(ch,GET_HEIGHT(ch->specials.mount)/number(5,20));
      }
      tmp = ch->specials.mount;
      unmount(ch);
      if (!number(0,10) && IS_MOB(tmp) && (GET_INT(tmp) < 10))
	do_flee(tmp,"",0,0);
      return(TRUE);
    }
  return(FALSE);
}

int	do_simple_move(struct char_data *ch, int cmd, int following)

/* Assumes, 
	1. That there is no master and no followers.
	2. That the direction exists. 

   Returns :
   1 : If succes.
   0 : If fail
  -1 : If dead.
*/
{
  int	special(struct char_data *ch, int cmd, char *arg);
  int	need_movement, target_sect, curr_sect, nteam, total_weight;
  int delay,num;
  struct char_data *tmp;
  struct obj_data *obj, *cart;
  struct room_data *target_room;
  struct follow_type *k;
  bool has_boat, cart_move;

  
  if (special(ch, cmd + 1, ""))  /* Check for special routines (North is 1) */
    return(FALSE);
  if (ch->specials.mount)
    if ((GET_POS(ch->specials.mount) != POSITION_STANDING)
	|| IS_AFFECTED(ch->specials.mount, AFF_PARALYSIS)
	|| MOB_FLAGGED(ch->specials.mount, MOB_TETHERED)
	){
      send_to_char("Your mount seems unable to move.\r\n",ch);
      return(FALSE);
    }
  if (IS_MOB(ch) && MOB_FLAGGED(ch,MOB_TETHERED))
    return(FALSE);
  
  if (IS_SET(world[real_room(world[ch->in_room].dir_option[cmd]->to_room)].room_flags,UNFINISHED) && GET_LEVEL(ch) < LEVEL_BUILDER){
    send_to_char("A strange force bars your movement in that direction.\r\n",ch);
    return(FALSE);
  }
  if ((world[ch->in_room].dir_option[cmd]->to_room == 0) &&
      world[ch->in_room].dir_option[cmd]->general_description){
    send_to_char( world[ch->in_room].dir_option[cmd]->general_description,ch);
    return(FALSE);
  }
  else if (world[ch->in_room].dir_option[cmd]->to_room == 0){
    send_to_char("A strange force bars your movement in that direction.\r\n",ch);
    return(FALSE);
  }
  target_room =&world[real_room(world[ch->in_room].dir_option[cmd]->to_room)];
  target_sect= target_room->sector_type;
  curr_sect = world[ch->in_room].sector_type;
  if (IS_PULLING(ch)
      && (target_sect != SECT_CITY
	  && target_sect != SECT_FIELD
	  && target_sect != SECT_HILLS
	  && target_sect != SECT_FOREST)){
    send_to_char("You can't drag cart there.\r\n",ch);
    return(FALSE);}
  if (ch->specials.mount && (target_sect == SECT_INSIDE)) {
    send_to_char("You can't ride indoors.\r\n",ch);
    return(FALSE);
  }
  if (IS_AFFECTED(ch, AFF_SLIPPY) && !number(0,1)){
    act("$n slips and falls down.", TRUE, ch, 0,0,TO_ROOM);
    send_to_char("You slip and fall down.\r\n",ch);
    GET_POS(ch) = POSITION_SITTING;
    if (ch->specials.rider)
      if(throw_rider(ch->specials.rider))
	;
    if (ch->specials.carrying)
      do_drop_mob(ch);
    return(FALSE);
  }
  need_movement = (movement_loss[curr_sect] + movement_loss[target_sect])/ 2;
  if (IS_AFFECTED(ch,AFF_FLY) &&
      ((curr_sect != SECT_UNDER_WATER) || (target_sect != SECT_UNDER_WATER)))
    need_movement = 1;
  /* 9-22-94: patch by Scarrow to make water rooms easier with a boat */
  has_boat = FALSE;
  /* See if char is carrying a boat */
  for (obj = ch->inventory; obj; obj = obj->next_content)
    if (obj->obj_flags.type_flag == ITEM_BOAT)
      has_boat = TRUE;
  /* if it's water (swim or noswim) and we have a boat and aren't flying */
  /* halve the computed cost of movement -- Scarrow (9-22-94) */
  if (((world[ch->in_room].sector_type == SECT_WATER_SWIM) || 
       (world[ch->in_room].sector_type == SECT_WATER_NOSWIM) ||
       (target_room->sector_type == SECT_WATER_SWIM) ||
       (target_room->sector_type == SECT_WATER_NOSWIM)) &&
      has_boat && (!IS_AFFECTED(ch, AFF_FLY) ||
		   (ch->specials.mount && !IS_AFFECTED(ch->specials.mount, AFF_FLY)))) {
    need_movement /= 2;
  }
  if ((world[ch->in_room].sector_type == SECT_WATER_NOSWIM) || 
      (target_room->sector_type == SECT_WATER_NOSWIM)) {
    if (!has_boat && !IS_AFFECTED(ch,AFF_FLY) && !ch->specials.carried_by &&
	!IS_AFFECTED(ch, AFF_WATER_BREATH)
	&& !(ch->specials.mount &&(IS_AFFECTED(ch->specials.mount,AFF_FLY) ||
				   IS_AFFECTED(ch->specials.mount, AFF_WATER_BREATH)))) {
      send_to_char("You thrash about trying to stay afloat.\r\n", ch);
      need_movement *= 2;
    }
  }
  
  if ((world[ch->in_room].sector_type == SECT_FLY) || 
      (target_room->sector_type == SECT_FLY)) {
    if (!IS_AFFECTED(ch,AFF_FLY) && !ch->specials.carried_by
	&& !(ch->specials.mount && IS_AFFECTED(ch->specials.mount,AFF_FLY))) {
      send_to_char("You would need wings to go there.\r\n", ch);
      return(FALSE);
    }
  }
  if ((world[ch->in_room].sector_type == SECT_THICKET) || 
      (world[real_room(world[ch->in_room].dir_option[cmd]->to_room)].sector_type == SECT_THICKET)) {
    if (GET_LEVEL(ch) < LEVEL_BUILDER  && GET_SIZE(ch) < 6) {
      send_to_char("Ouch! you are raked by briar thorns.\r\n", ch);
      if (ch->specials.mount) {
	rmdamage(ch,number(4,32));
	rmdamage(ch->specials.mount,number(4,32));	     
      }
      else
	rmdamage(ch,number(2,16));
      
    }
    else
      send_to_char("The briar thorns bounce harmlessly off your skin.\r\n", ch);	
  }
   
  if ((world[ch->in_room].sector_type == SECT_UNDER_WATER) || 
      (target_room->sector_type == SECT_UNDER_WATER)) {
    if (!IS_AFFECTED(ch,AFF_WATER_BREATH) && !ch->specials.carried_by &&
	!(ch->specials.mount
	  && IS_AFFECTED(ch->specials.mount,AFF_WATER_BREATH))) {
      send_to_char("You thrash about. You are Drowning!\r\n", ch);
      need_movement *= 2;

    }
  }
  
  if (IS_SET(target_room->room_flags,SMALL))
    if ((GET_SIZE(ch) < 4) ||
	(ch->specials.mount && (GET_SIZE(ch->specials.mount) < 4))){
      send_to_char("You bump your head.\r\n",ch);
      send_to_char("You can't go there, you are too big.\r\n",ch);
      return(FALSE);}
    else if ( (GET_SIZE(ch) < 5) ||
	      (ch->specials.mount && (GET_SIZE(ch->specials.mount) < 5)))
      send_to_char("You bump your head.\r\n",ch);
  if (IS_SET(target_room->room_flags,TINY))
    if ( (GET_SIZE(ch) < 5) ||
	 (ch->specials.mount && (GET_SIZE(ch->specials.mount) < 5))){
      send_to_char("You bump your head.\r\n",ch);	   
      send_to_char("You can't go there, you are too big.\r\n",ch);
      return(FALSE);}
    else if ((GET_SIZE(ch) < 6) ||
	     (ch->specials.mount && (GET_SIZE(ch->specials.mount) < 6)))
      send_to_char("You bump your head.\r\n",ch);

  if ((cmd == 4 || cmd ==5) && !ch->specials.carried_by &&
      !(IS_AFFECTED(ch,AFF_FLY) ||
	(ch->specials.mount && IS_AFFECTED(ch->specials.mount,AFF_FLY))) &&
      (((IS_SET(world[TO_RM(ch,cmd)].room_flags,CLIMB_MODERATE) ||
	 IS_SET(world[ch->in_room].room_flags, CLIMB_MODERATE))
	&& (GET_SKILL(ch,SKILL_CLIMB) < 8) && number(0,3)) ||
       ((IS_SET(world[TO_RM(ch,cmd)].room_flags,CLIMB_HARD) ||
	 IS_SET(world[ch->in_room].room_flags, CLIMB_HARD))
	&& (GET_SKILL(ch,SKILL_CLIMB) < 18) && number(0,6)) ||
       ((IS_SET(world[TO_RM(ch,cmd)].room_flags,CLIMB_SEVERE) ||
	 IS_SET(world[ch->in_room].room_flags, CLIMB_SEVERE))
	&& (GET_SKILL(ch,SKILL_CLIMB) < 26) && number(0,8)) ||
       ((IS_SET(world[TO_RM(ch,cmd)].room_flags,CLIMB_EXTREME) ||
	 IS_SET(world[ch->in_room].room_flags, CLIMB_EXTREME))
	&& (GET_SKILL(ch,SKILL_CLIMB) < 29) && number(0,15))))
    {
      if (ch->specials.mount) {
	act("$N cannot manage the climb.",FALSE,ch,0,ch->specials.mount,TO_CHAR);
	return(FALSE);
      }
      send_to_char("You aren't a good enough climber.\r\n",ch);
      if (IS_CLIMB(ch, cmd))
	 fall_down(ch);
      if (cmd != 5){
	send_to_char("You fall back onto your backside.\r\n",ch);
	GET_POS(ch) = POSITION_SITTING;
	if (!IS_AFFECTED(ch,AFF_FLY) && !ch->specials.carried_by){
	  if ((IS_SET(world[ch->in_room].room_flags, CLIMB_MODERATE) && (number(0,20) <= 1)) || (IS_SET(world[ch->in_room].room_flags, CLIMB_HARD) && (number(0,20) <= 3)) || (IS_SET(world[ch->in_room].room_flags, CLIMB_SEVERE) && (number(0,20) <= 5)) || (IS_SET(world[ch->in_room].room_flags, CLIMB_EXTREME) && (number(0,20) <= 8))){
	    act("You learn a new climbing move.",TRUE,ch,0,0,TO_CHAR);
	    SET_SKILL(ch,SKILL_CLIMB,MIN(30,GET_SKILL(ch,SKILL_CLIMB) + number (0,2)));
	  }
	}
      }
      return(FALSE);
    }
   
  if (IS_PULLING(ch)){
    total_weight = 0;
    for (k = IS_PULLING(ch)->pulled_by;k;k = k->next)
      total_weight += GET_WEIGHT(k->follower);
    need_movement += (need_movement*GET_OBJ_WEIGHT(IS_PULLING(ch))/
		      total_weight);}
  need_movement *= encumberance_level(ch);
  if (ch->specials.mount) 
    if ((GET_MOVE(ch->specials.mount) < 2*need_movement) &&
	(GET_HIT(ch->specials.mount) < GET_MAX_HIT(ch->specials.mount)/4)) {
      send_to_char("Your mount is too exhausted.\r\n", ch);
      return(FALSE);
    }
  if ((GET_MOVE(ch) < need_movement) &&
      (GET_HIT(ch)  < GET_MAX_HIT(ch)/4)
      ) {
    if (following && !ch->master)
      send_to_char("You are too exhausted to follow.\r\n", ch);
    else
      send_to_char("You are too exhausted.\r\n", ch);

    return(FALSE);
  }
  if (!ch->specials.carried_by) {
    if (ch->specials.mount) {
      GET_MOVE(ch) -= need_movement/4;
      GET_MOVE(ch->specials.mount) -=
	need_movement*(2*CAN_CARRY_W(ch->specials.mount)
		       /(GET_WEIGHT(ch)+ IS_CARRYING_W(ch)));
      if (GET_MOVE(ch) < 0)
	GET_HIT(ch) -= MAX(1,GET_HIT(ch)/4);
    }
    else {
      if (GET_LEVEL(ch) < LEVEL_BUILDER || IS_NPC(ch)){
	GET_MOVE(ch) -= need_movement;
	if (GET_MOVE(ch) < 0){
	  send_to_char("You are wracked with pain as you overexert yourself.\r\n",ch);
	  act("Though exhausted $n manages to move.",FALSE,ch,0,0,TO_NOTCHAR);
	  GET_HIT(ch) -= MAX(1,GET_HIT(ch)/4);
	}
      }
    }
  }
  if (ch->specials.mount) 
    delay = (need_movement*GET_MAX_MOVE(ch->specials.mount))
      /(MAX(1,GET_MOVE(ch->specials.mount))
	*(10 + GET_STR(ch->specials.mount)/2));
  else
    delay = need_movement/10;
  if (ch->specials.mount)
    if (throw_rider(ch))
      return(FALSE);
   
  if ((cart = IS_PULLING(ch))){
    /* add leave events for all hitched  */
    cart_move = TRUE;
    nteam = 0;
    for (k = cart->pulled_by;k;k = k->next)
      if (GET_MOVE(k->follower) < 0) {
	nteam++;
	cart_move = FALSE;
      }
    if(cart_move){
      for (k = cart->pulled_by;k;k = k->next){
	WAIT_STATE(k->follower,delay);
	add_event(0, EVENT_LEAVE, cmd,has_boat,0,0,0,k->follower,0);}
      /* and the cart itself */
      add_event(0, EVENT_CART_LEAVE,cmd,cart->in_room,0,0,0,cart,0);
    }
    else{
      if (nteam > 1){
	act("The team strains to move $p."
	    ,TRUE,cart->pulled_by->follower,cart,0,TO_ROOM);
	act("But they are too exhausted."
	    ,TRUE,cart->pulled_by->follower,cart,0,TO_ROOM);}
      else{
	act("$n strains to move $p."
	    ,TRUE,cart->pulled_by->follower,cart,0,TO_ROOM);
	act("But $e is too exhausted."
	    ,TRUE,cart->pulled_by->follower,cart,0,TO_ROOM);}
    }
  }
  else
    add_event(0, EVENT_LEAVE, cmd,has_boat,0,0,0,ch,0);

  WAIT_STATE(ch,delay);
  if (ch->desc)
    ch->desc->prompt_mode =0;
  if ((cart = IS_PULLING(ch))){
    if(cart_move){
      for (k = cart->pulled_by;k;k = k->next)
	add_event(delay, EVENT_ARRIVE,
		  cmd,world[ch->in_room].dir_option[cmd]->to_room
		  ,0,0,0,k->follower,0);
      /* and the cart itself */
      add_event(delay, EVENT_CART_ARRIVE,cmd
		,world[ch->in_room].dir_option[cmd]->to_room
		,0,0,0,cart,0);
    }
  }
  else   
    add_event(delay, EVENT_ARRIVE, cmd,world[ch->in_room].dir_option[cmd]->to_room,0,0,0,ch,0);
  return(1);
}


ACMD(do_move)
{
  int	was_in,ex,nexits,which;
  struct follow_type *k, *next_dude;
  
  
  if (ch->specials.carried_by) {
    act("Ask $N to drop you first.",
	FALSE,ch,0,ch->specials.carried_by,TO_CHAR);
    return;
  }
  if (IS_SET(world[ch->in_room].room_flags, SPIN)){
    nexits=0;       
    for (ex=0;ex < NUM_OF_DIRS;ex++)
      {
	if (EXIT(ch,ex))
	  nexits++;
      }
    if (nexits >1) {
      which = number(1,nexits);
      nexits=0;
      for (ex=0;ex < NUM_OF_DIRS && nexits < which;ex++)
	{
	  if (EXIT(ch,ex))
	    nexits++;
	}
      cmd = ex;
    }
  }
  --cmd;
   
  if (!world[ch->in_room].dir_option[cmd]) {
    send_to_char("Alas, you cannot go that way...\r\n", ch);
  } else {          /* Direction is possible */
    if (IS_SET(EXIT(ch, cmd)->exit_info, EX_CLOSED)
	&& !IS_SET(EXIT(ch,cmd)->exit_info,EX_SECRET)
	&& !IS_SET(EXIT(ch,cmd)->exit_info,EX_DARK)) {
      if (EXIT(ch, cmd)->keyword) {
	sprintf(buf2, "The %s seems to be closed.\r\n",
	        fname(EXIT(ch, cmd)->keyword));
	send_to_char(buf2, ch);
      }
      else
	send_to_char("It seems to be closed.\r\n", ch);
    }
    else if (IS_SET(EXIT(ch, cmd)->exit_info, EX_CLOSED)
	     && (IS_SET(EXIT(ch,cmd)->exit_info,EX_SECRET)
		 || IS_SET(EXIT(ch,cmd)->exit_info,EX_DARK)))
      send_to_char("Alas, you cannot go that way...\r\n", ch);
    else if (EXIT(ch, cmd)->to_room == NOWHERE)
      send_to_char("Alas, you cannot go that way...\r\n", ch);
    else if (!ch->followers && !ch->master)
      do_simple_move(ch, cmd, FALSE);
    else {
      was_in = ch->in_room;
      if (do_simple_move(ch, cmd, TRUE) == 1) { /* Move the character */
	if (ch->followers) { /* If succes move followers */
	  for (k = ch->followers; k; k = next_dude) {
	    next_dude = k->next;
	    if ((was_in == k->follower->in_room) && 
		(GET_POS(k->follower) >= POSITION_STANDING) &&
		!k->follower->specials.fighting){
	      if(IS_NPC(ch) && !number(0,3) && GET_LEVEL(k->follower) < LEVEL_BUILDER && !IS_NPC(k->follower)){
		act("You lost track of $n.",TRUE,ch,0,k->follower,TO_VICT);
		break;}
	      else {
		act("You follow $N.\r\n", FALSE, k->follower, 0, ch, TO_CHAR);
		do_move(k->follower, argument, cmd + 1, 0);
	      }
	    }
	  }
	}
      }
    }
  }
}



int	find_door(struct char_data *ch, char *type, char *dir)
{
   int	door;
   char	*dirs[] = 
    {
      "north",
      "east",
      "south",
      "west",
      "up",
      "down",
      "\n"
   };

   if (*dir) /* a direction was specified */ {
      if ((door = search_block(dir, dirs, FALSE)) == -1) /* Partial Match */ {
	 send_to_char("That's not a direction.\r\n", ch);
	 return(-1);
      }

      if (EXIT(ch, door))
	 if (EXIT(ch, door)->keyword)
	    if (isname(type, EXIT(ch, door)->keyword))
	       return(door);
	    else {
	       sprintf(buf2, "I see no %s there.\r\n", type);
	       send_to_char(buf2, ch);
	       return(-1);
	    }
	 else
	    return(door);
      else {
	 send_to_char("I really don't see how you can close anything there.\r\n", ch);
	 return(-1);
      }
   }
   else /* try to locate the keyword */	 {
       for (door = 0; door < NUM_OF_DIRS; door++)
	   if (EXIT(ch, door))
	       if (EXIT(ch, door)->keyword)
		   if (isname(type, EXIT(ch, door)->keyword))
		       return(door);
       
       sprintf(buf2, "I see no %s here.\r\n", type);
       send_to_char(buf2, ch);
       return(-1);
   }
}


ACMD(do_open)
{
   int	door, other_room;
   char	type[MAX_INPUT_LENGTH], dir[MAX_INPUT_LENGTH];
   struct room_direction_data *back;
   struct obj_data *obj;
   struct char_data *victim;

   argument_interpreter(argument, type, dir);

   if (!*type)
      send_to_char("Open what?\r\n", ch);
   else if (generic_find(argument,FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP
			 ,ch, &victim, &obj))

      /* this is an object */

      if (obj->obj_flags.type_flag != ITEM_CONTAINER)
	 send_to_char("That's not a container.\r\n", ch);
      else if (!IS_SET(obj->obj_flags.value[1], CONT_CLOSED))
	 send_to_char("But it's already open!\r\n", ch);
      else if (!IS_SET(obj->obj_flags.value[1], CONT_CLOSEABLE))
	 send_to_char("You can't do that.\r\n", ch);
      else if (IS_SET(obj->obj_flags.value[1], CONT_LOCKED))
	 send_to_char("It seems to be locked.\r\n", ch);
      else
       {
	 REMOVE_BIT(obj->obj_flags.value[1], CONT_CLOSED);
	 act("$n opens $p.", FALSE, ch, obj, 0, TO_ROOM);
	 act("you open $p.", FALSE, ch, obj, 0, TO_CHAR);	 
      }
   else if ((door = find_door(ch, type, dir)) >= 0)

      /* perhaps it is a door */

      if (!IS_SET(EXIT(ch, door)->exit_info, EX_ISDOOR))
	 send_to_char("That's impossible, I'm afraid.\r\n", ch);
      else if (!IS_SET(EXIT(ch, door)->exit_info, EX_CLOSED))
	 send_to_char("It's already open!\r\n", ch);
      else if (IS_SET(EXIT(ch, door)->exit_info, EX_LOCKED))
	 send_to_char("It seems to be locked.\r\n", ch);
      else {
	 REMOVE_BIT(EXIT(ch, door)->exit_info, EX_CLOSED);
	 if (EXIT(ch, door)->keyword ){
	     if (IS_SET(EXIT(ch,door)->exit_info, EX_SECRET))
		 act("$n opens a hidden passage.", FALSE, ch, 0,0, TO_ROOM);
	     else
		 act("$n opens the $F.", FALSE, ch, 0,
		     EXIT(ch, door)->keyword, TO_ROOM);
	 act("You open the $F.", FALSE, ch, 0,
	     EXIT(ch, door)->keyword, TO_CHAR);
	 }
	 else if (IS_SET(EXIT(ch,door)->exit_info, EX_SECRET)){
	     act("$n opens a hidden passage.", FALSE, ch, 0,0, TO_ROOM);
	     act("you open the door.", FALSE, ch, 0,0, TO_CHAR);
	 }
	 else{
	    act("$n opens a door.", FALSE, ch, 0, 0, TO_ROOM);
	    act("you open the door.", FALSE, ch, 0,0, TO_CHAR);
	 }
	 /* now for opening the OTHER side of the door! */
	 if ((other_room = real_room(EXIT(ch, door)->to_room)) != NOWHERE)
	    if ((back = world[other_room].dir_option[rev_dir[door]]))
	       if (world[ch->in_room].number == back->to_room) {
		  REMOVE_BIT(back->exit_info, EX_CLOSED);
		  if (back->keyword) {
		      if (IS_SET(back->exit_info, EX_SECRET))
			  sprintf(buf, "A hidden passage is opened from the other side.\r\n");
		      else
			  sprintf(buf, "The %s is opened from the other side.\r\n",fname(back->keyword));
		      send_to_room(buf, EXIT(ch, door)->to_room, TRUE);
		  }
		  else if (IS_SET(back->exit_info, EX_SECRET))
		      send_to_room("A hidden passage is opened from the other side.\r\n", EXIT(ch, door)->to_room, TRUE);
		  else
		      send_to_room("The door is opened from the other side.\r\n",
		         EXIT(ch, door)->to_room, TRUE);
	       }
      }
}


ACMD(do_close)
{
   int	door, other_room;
   char	type[MAX_INPUT_LENGTH], dir[MAX_INPUT_LENGTH];
   struct room_direction_data *back;
   struct obj_data *obj;
   struct char_data *victim;

   argument_interpreter(argument, type, dir);

   if (!*type)
      send_to_char("Close what?\r\n", ch);
   else if (generic_find(argument,FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP
			 ,ch, &victim, &obj))

      /* this is an object */

      if (obj->obj_flags.type_flag != ITEM_CONTAINER)
	 send_to_char("That's not a container.\r\n", ch);
      else if (IS_SET(obj->obj_flags.value[1], CONT_CLOSED))
	 send_to_char("But it's already closed!\r\n", ch);
      else if (!IS_SET(obj->obj_flags.value[1], CONT_CLOSEABLE))
	 send_to_char("That's impossible.\r\n", ch);
      else {
	 SET_BIT(obj->obj_flags.value[1], CONT_CLOSED);
	 act("$n closes $p.", FALSE, ch, obj, 0, TO_ROOM);
	 act("You close $p.", FALSE, ch, obj, 0, TO_CHAR);	 
      }
   else if ((door = find_door(ch, type, dir)) >= 0)

      /* Or a door */

      if (!IS_SET(EXIT(ch, door)->exit_info, EX_ISDOOR))
	 send_to_char("That's absurd.\r\n", ch);
      else if (IS_SET(EXIT(ch, door)->exit_info, EX_CLOSED))
	 send_to_char("It's already closed!\r\n", ch);
      else {
	 SET_BIT(EXIT(ch, door)->exit_info, EX_CLOSED);
	 if (EXIT(ch, door)->keyword){
	     if (IS_SET(EXIT(ch,door)->exit_info, EX_SECRET))
		 act("$n closes a hidden passage.", 0, ch, 0,0,TO_ROOM);
	     else
		 act("$n closes the $F.", 0, ch, 0, EXIT(ch, door)->keyword,
		     TO_ROOM);
	     act("You close the $F.", 0, ch, 0, EXIT(ch, door)->keyword,TO_CHAR);
	 }
	 else if (IS_SET(EXIT(ch,door)->exit_info, EX_SECRET)){
	     act("$n closes a hidden passage.", 0, ch, 0,0,TO_ROOM);
	     act("You close a hidden passage.", 0, ch, 0,0,TO_CHAR);	     
	 }
	 else{
	     act("$n closes the door.", FALSE, ch, 0, 0, TO_ROOM);
	     act("You close the door.", FALSE, ch, 0, 0, TO_CHAR);
	 }
	 /* now for closing the other side, too */
	 if ((other_room = real_room(EXIT(ch, door)->to_room)) != NOWHERE)
	    if ((back = world[other_room].dir_option[rev_dir[door]]))
	       if (world[ch->in_room].number == back->to_room) {
		  SET_BIT(back->exit_info, EX_CLOSED);
		  if (back->keyword) {
		      if (IS_SET(back->exit_info, EX_SECRET))
			  sprintf(buf, "A hidden passage closes quietly.\r\n");
		      else
			  sprintf(buf, "The %s closes quietly.\r\n", fname(back->keyword));
		     send_to_room(buf, EXIT(ch, door)->to_room, TRUE);
		  } else
		      if (IS_SET(back->exit_info, EX_SECRET))
			  send_to_room("A hidden passage closes quietly.\r\n", EXIT(ch, door)->to_room, TRUE);
		      else
			  send_to_room("The door closes quietly.\r\n", EXIT(ch, door)->to_room, TRUE);
	       }
      }
}


int	has_key(struct char_data *ch, int key)
{
   struct obj_data *o;

   for (o = ch->inventory; o; o = o->next_content)
      if (obj_index[o->item_number].virtual == key)
	 return(1);

   if (ch->equipment[HOLD])
      if (obj_index[ch->equipment[HOLD]->item_number].virtual == key)
	 return(1);

   return(0);
}


ACMD(do_lock)
{
   int	door, other_room;
   char	type[MAX_INPUT_LENGTH], dir[MAX_INPUT_LENGTH];
   struct room_direction_data *back;
   struct obj_data *obj;
   struct char_data *victim;


   argument_interpreter(argument, type, dir);
  if (ch->specials.mount) {
    send_to_char("You had better dismount first.\r\n", ch);
    return;}    
   if (!*type)
      send_to_char("Lock what?\r\n", ch);
   else if (generic_find(argument,FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP
			 ,ch, &victim, &obj))

      /* this is an object */

      if (obj->obj_flags.type_flag != ITEM_CONTAINER)
	 send_to_char("That's not a container.\r\n", ch);
      else if (!IS_SET(obj->obj_flags.value[1], CONT_CLOSED))
	 send_to_char("Maybe you should close it first...\r\n", ch);
      else if (obj->obj_flags.value[2] < 0)
	 send_to_char("That thing can't be locked.\r\n", ch);
      else if (!has_key(ch, obj->obj_flags.value[2]))
	 send_to_char("You don't seem to have the proper key.\r\n", ch);
      else if (IS_SET(obj->obj_flags.value[1], CONT_LOCKED))
	 send_to_char("It is locked already.\r\n", ch);
      else {
	 SET_BIT(obj->obj_flags.value[1], CONT_LOCKED);
	 send_to_char("*Cluck*\r\n", ch);
	 act("$n locks $p - 'cluck', it says.", FALSE, ch, obj, 0, TO_ROOM);
      }
   else if ((door = find_door(ch, type, dir)) >= 0)

      /* a door, perhaps */

      if (!IS_SET(EXIT(ch, door)->exit_info, EX_ISDOOR))
	 send_to_char("That's absurd.\r\n", ch);
      else if (!IS_SET(EXIT(ch, door)->exit_info, EX_CLOSED))
	 send_to_char("You have to close it first, I'm afraid.\r\n", ch);
      else if (EXIT(ch, door)->key < 0)
	 send_to_char("There does not seem to be any keyholes.\r\n", ch);
      else if (!has_key(ch, EXIT(ch, door)->key))
	 send_to_char("You don't have the proper key.\r\n", ch);
      else if (IS_SET(EXIT(ch, door)->exit_info, EX_LOCKED))
	 send_to_char("It's already locked!\r\n", ch);
      else {
	 SET_BIT(EXIT(ch, door)->exit_info, EX_LOCKED);
	 if (EXIT(ch, door)->keyword)
	     if (IS_SET(EXIT(ch,door)->exit_info, EX_SECRET))
		 act("$n locks a hidden door.", FALSE, ch, 0,0, TO_ROOM);
	     else
		 act("$n locks the $F.", 0, ch, 0,  EXIT(ch, door)->keyword,
		     TO_ROOM);
	 else if (IS_SET(EXIT(ch,door)->exit_info, EX_SECRET))
	     act("$n locks a hidden door.", FALSE, ch, 0,0, TO_ROOM);
	 else
	     act("$n locks the door.", FALSE, ch, 0, 0, TO_ROOM);
	 send_to_char("*Click*\r\n", ch);
	 /* now for locking the other side, too */
	 if ((other_room = real_room(EXIT(ch, door)->to_room)) != NOWHERE)
	    if ((back = world[other_room].dir_option[rev_dir[door]]))
	       if (back->to_room == world[ch->in_room].number)
		  SET_BIT(back->exit_info, EX_LOCKED);
      }
}


ACMD(do_unlock)
{
   int	door, other_room;
   char	type[MAX_INPUT_LENGTH], dir[MAX_INPUT_LENGTH];
   struct room_direction_data *back;
   struct obj_data *obj;
   struct char_data *victim;


   argument_interpreter(argument, type, dir);
   
  if (ch->specials.mount) {
    send_to_char("You had better dismount first.\r\n", ch);
    return;}    

   if (!*type)
      send_to_char("Unlock what?\r\n", ch);
   else if (generic_find(argument,FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP
			 ,ch, &victim, &obj))

      /* this is an object */

      if (obj->obj_flags.type_flag != ITEM_CONTAINER)
	 send_to_char("That's not a container.\r\n", ch);
      else if (!IS_SET(obj->obj_flags.value[1], CONT_CLOSED))
	 send_to_char("Silly - it ain't even closed!\r\n", ch);
      else if (obj->obj_flags.value[2] < 0)
	 send_to_char("Odd - you can't seem to find a keyhole.\r\n", ch);
      else if (!has_key(ch, obj->obj_flags.value[2]))
	 send_to_char("You don't seem to have the proper key.\r\n", ch);
      else if (!IS_SET(obj->obj_flags.value[1], CONT_LOCKED))
	 send_to_char("Oh.. it wasn't locked, after all.\r\n", ch);
      else {
	 REMOVE_BIT(obj->obj_flags.value[1], CONT_LOCKED);
	 send_to_char("*Click*\r\n", ch);
	 act("$n unlocks $p.", FALSE, ch, obj, 0, TO_ROOM);
      }
   else if ((door = find_door(ch, type, dir)) >= 0)

      /* it is a door */

      if (!IS_SET(EXIT(ch, door)->exit_info, EX_ISDOOR))
	 send_to_char("That's absurd.\r\n", ch);
      else if (!IS_SET(EXIT(ch, door)->exit_info, EX_CLOSED))
	 send_to_char("Heck.. it ain't even closed!\r\n", ch);
      else if (EXIT(ch, door)->key < 0)
	 send_to_char("You can't seem to spot any keyholes.\r\n", ch);
      else if (!has_key(ch, EXIT(ch, door)->key))
	 send_to_char("You do not have the proper key for that.\r\n", ch);
      else if (!IS_SET(EXIT(ch, door)->exit_info, EX_LOCKED))
	 send_to_char("It's already unlocked, it seems.\r\n", ch);
      else {
	 REMOVE_BIT(EXIT(ch, door)->exit_info, EX_LOCKED);
	 if (EXIT(ch, door)->keyword)
	     if (IS_SET(EXIT(ch,door)->exit_info, EX_SECRET))
		 act("$n unlocks a hidden door.", FALSE, ch, 0,0, TO_ROOM);
	     else
		 act("$n unlocks the $F.", 0, ch, 0, EXIT(ch, door)->keyword,
	        TO_ROOM);
	 else if (IS_SET(EXIT(ch,door)->exit_info, EX_SECRET))
	     act("$n unlocks a hidden door.", FALSE, ch, 0,0, TO_ROOM);
	 else
	     act("$n unlocks the door.", FALSE, ch, 0, 0, TO_ROOM);
	 send_to_char("*click*\r\n", ch);
	 /* now for unlocking the other side, too */
	 if ((other_room = real_room(EXIT(ch, door)->to_room)) != NOWHERE)
	    if ((back = world[other_room].dir_option[rev_dir[door]]))
	       if (back->to_room == world[ch->in_room].number)
		  REMOVE_BIT(back->exit_info, EX_LOCKED);
      }
}





ACMD(do_pick)
{
   byte percent;
   int	door, other_room;
   char	type[MAX_INPUT_LENGTH], dir[MAX_INPUT_LENGTH];
   struct room_direction_data *back;
   struct obj_data *obj;
   struct char_data *victim;

   argument_interpreter(argument, type, dir);

   percent = number(1, 31); /* 101% is a complete failure */

   if ((IS_NPC(ch) && percent > GET_LEVEL(ch)/10) ||
       (!IS_NPC(ch) && (percent > GET_SKILL(ch, SKILL_PICK_LOCK)))) {
     send_to_char("You failed to pick the lock.\r\n", ch);
     return;
   }
   if (ch->specials.mount) {
     send_to_char("Pick locks while riding?  Fat chance.\r\n", ch);
     return;}    
   
   if (!*type)
     send_to_char("Pick what?\r\n", ch);
   else if (generic_find(argument,FIND_OBJ_INV | FIND_OBJ_ROOM | FIND_OBJ_EQUIP
			 , ch, &victim, &obj))
     
     /* this is an object */
     
     if (obj->obj_flags.type_flag != ITEM_CONTAINER)
       send_to_char("That's not a container.\r\n", ch);
     else if (!IS_SET(obj->obj_flags.value[1], CONT_CLOSED))
       send_to_char("Silly - it isn't even closed!\r\n", ch);
     else if (obj->obj_flags.value[2] < 0)
       send_to_char("Odd - you can't seem to find a keyhole.\r\n", ch);
     else if (!IS_SET(obj->obj_flags.value[1], CONT_LOCKED))
       send_to_char("Oho! This thing is NOT locked!\r\n", ch);
     else if (IS_SET(obj->obj_flags.value[1], CONT_PICKPROOF))
       send_to_char("It resists your attempts at picking it.\r\n", ch);
     else {
       REMOVE_BIT(obj->obj_flags.value[1], CONT_LOCKED);
       send_to_char("*Click*\r\n", ch);
       act("$n fiddles with $p.", FALSE, ch, obj, 0, TO_ROOM);
     }
   else if ((door = find_door(ch, type, dir)) >= 0)
     if (!IS_SET(EXIT(ch, door)->exit_info, EX_ISDOOR))
       send_to_char("That's absurd.\r\n", ch);
     else if (!IS_SET(EXIT(ch, door)->exit_info, EX_CLOSED))
       send_to_char("You realize that the door is already open.\r\n", ch);
     else if (EXIT(ch, door)->key < 0)
       send_to_char("You can't seem to spot any lock to pick.\r\n", ch);
     else if (!IS_SET(EXIT(ch, door)->exit_info, EX_LOCKED))
       send_to_char("Oh.. it wasn't locked at all.\r\n", ch);
     else if (IS_SET(EXIT(ch, door)->exit_info, EX_PICKPROOF))
       send_to_char("You seem to be unable to pick this lock.\r\n", ch);
     else {
       REMOVE_BIT(EXIT(ch, door)->exit_info, EX_LOCKED);
       if (EXIT(ch, door)->keyword)
	 act("$n skillfully picks the lock of the $F.", 0, ch, 0,
	        EXIT(ch, door)->keyword, TO_ROOM);
       else
	    act("$n picks the lock of the door.", TRUE, ch, 0, 0, TO_ROOM);
       send_to_char("The lock quickly yields to your skills.\r\n", ch);
       /* now for unlocking the other side, too */
       if ((other_room = real_room(EXIT(ch, door)->to_room)) != NOWHERE)
	 if ((back = world[other_room].dir_option[rev_dir[door]]))
	   if (back->to_room == world[ch->in_room].number)
	     REMOVE_BIT(back->exit_info, EX_LOCKED);
     }
}


ACMD(do_enter)
{
   int	door, was_in;
   struct follow_type *k, *next_dude;
   struct obj_data *cont;

   ACMD(do_move);

   one_argument(argument, buf);

  if (ch->specials.carried_by) {
    act("Ask $N to drop you first.",
	FALSE,ch,0,ch->specials.carried_by,TO_CHAR);
    return;
  }
   
   if (*buf)  /* an argument was supplied, search for door keyword */ {
      for (door = 0; door < NUM_OF_DIRS; door++)
	 if (EXIT(ch, door))
	    if (EXIT(ch, door)->keyword)
	       if (!str_cmp(EXIT(ch, door)->keyword, buf)) {
		  do_move(ch, "", ++door, 0);
		  return;
	       }
      /* ok not a door how about an object */
      if ((cont = get_obj_in_list_vis(ch,buf,world[ch->in_room].contents)))
	  {
	      if (HASROOM(cont))
		  if (!IS_SET(cont->obj_flags.value[1],CONT_CLOSED))
		      {
			  if (GET_OBJ_SIZE(cont) - GET_SIZE(ch) > 1){
			      sprintf(buf1,
				      "The %s is too small you can't fit."
				      ,first_name(cont->name));
			      act(buf1,TRUE,ch,0,0,TO_CHAR);
			      return;
			  }				      
			  if ((GET_WEIGHT(ch)
			       + IS_CARRYING_W(ch) +
			       + GET_OBJ_WEIGHT(cont))
			       > cont->obj_flags.value[0])
			      {
				  sprintf(buf1,
					  "There is no room in the %s."
					  ,first_name(cont->name));
				  act(buf1,TRUE,ch,0,0,TO_CHAR);
				  return;
			      }
                          if(real_room(cont->obj_flags.value[3]) == -1){
		             send_to_char("You can't enter that!\r\n",ch);
                             return;
                          }
			  act("$n enters $p.",TRUE,ch,cont,0,TO_ROOM);
			  act("You enter $p.",TRUE,ch,cont,0,TO_CHAR);
			  was_in = ch->in_room;
			  char_from_room(ch);
			  char_to_room(ch,cont->obj_flags.value[3],
				       TRUE);
			  do_look(ch,"",0,0);
			  if (!IS_SET(world[ch->in_room]
			    .obj->obj_flags.value[1], CONT_ONEWAY))
			      act("$n enters $p.",TRUE,ch,cont,0,TO_ROOM);
			  else
			      act("Suddenly, $n arrives!",TRUE,ch,cont,0,TO_ROOM);
			  if (ch->followers) {
			    for (k = ch->followers; k; k = next_dude) {
			      next_dude = k->next;
			      if ((k->follower->in_room == was_in) &&
				  (GET_POS(k->follower) >= POSITION_STANDING)
				  && !k->follower->specials.fighting){
				if(IS_NPC(ch) && !number(0,3)
				   && GET_LEVEL(k->follower)
				   < LEVEL_BUILDER && !IS_NPC(k->follower)){
				  act("You lost track of $n.",TRUE,ch,0,k->follower,TO_VICT);
				  break;}
				else {
				  act("You follow $N.\r\n", FALSE, k->follower, 0, ch, TO_CHAR);
				  do_enter(k->follower, argument,0,0);
				}
			      }
			    }
			  }
			  return;
		      }
		  else
		      {
			  sprintf(buf1,"The %s seems to be closed."
				  ,first_name(cont->name));
			  act(buf1,TRUE,ch,cont,0,TO_CHAR);
			  return;
		      }
	      else{
		  send_to_char("You can't enter that!\r\n",ch);
		  return;
	      }
	  }
      sprintf(buf2, "There is no %s here.\r\n", buf);
      send_to_char(buf2, ch);
   } else if (IS_SET(world[ch->in_room].room_flags, INDOORS))
      send_to_char("You are already indoors.\r\n", ch);
   else {
      /* try to locate an entrance */
      for (door = 0; door < NUM_OF_DIRS; door++)
	 if (EXIT(ch, door))
	    if (EXIT(ch, door)->to_room != NOWHERE)
	       if (!IS_SET(EXIT(ch, door)->exit_info, EX_CLOSED) && 
	           IS_SET(world[real_room(EXIT(ch, door)->to_room)].room_flags,
	           INDOORS)) {
		  do_move(ch, "", ++door, 0);
		  return;
	       }
      /* ok not a door how about an object */
      if ((cont = get_obj_in_list_vis(ch,buf,world[ch->in_room].contents)))
	  {
	      if (HASROOM(cont))
		  if (!IS_SET(cont->obj_flags.value[1],CONT_CLOSED))
		      {
			  if (GET_OBJ_SIZE(cont) - GET_SIZE(ch) > 1){
			      sprintf(buf1,
				      "The %s is too small you can't fit."
				      ,first_name(cont->name));
			      act(buf1,TRUE,ch,0,0,TO_CHAR);
			      return;
			  }
			  if ((GET_WEIGHT(ch)+IS_CARRYING_W(ch)
			       + GET_OBJ_WEIGHT(cont))
			       > cont->obj_flags.value[0])
			      {
				  sprintf(buf1,
					  "There is no room in the %s."
					  ,first_name(cont->name));
				  act(buf1,TRUE,ch,0,0,TO_CHAR);
				  return;
			      }
                          if(real_room(cont->obj_flags.value[3]) == -1){
		             send_to_char("You can't enter that!\r\n",ch);
                             return;
                          }
/*			  sprintf(buf1,"$n enters the %s."
				  ,first_name(cont->name));*/
			  act("$n enters $p.",TRUE,ch,cont,0,TO_ROOM);
/*			  sprintf(buf1,"You enter the %s."
				  ,first_name(cont->name));  */
			  act("you enter $p.",TRUE,ch,cont,0,TO_CHAR);
			  char_from_room(ch);
			  char_to_room(ch,real_room(cont->obj_flags.value[3])
			      ,FALSE);
			  do_look(ch,"",0,0);
/*			  sprintf(buf1,"$n enters the %s."
				  ,first_name(cont->name)); */
			  act("$n enters $p.",TRUE,ch,cont,0,TO_ROOM);
			  return;
		      }
		  else
		      {
			  sprintf(buf1,"The %s seems to be closed."
				  ,first_name(cont->name));
			  act(buf1,TRUE,ch,cont,0,TO_CHAR);
			  return;
		      }
	      else
		  {
		      send_to_char("You can't enter that!\r\n",ch);
		      return;
		  }
	  }
      send_to_char("You can't seem to find anything to enter.\r\n", ch);
   }
}


ACMD(do_leave)
{
   int	door, to_room, was_in;
   struct follow_type *k, *next_dude;
   struct obj_data *cont;
   
   ACMD(do_move);

   if (ch->specials.carried_by) {
    act("Ask $N to drop you first.",
	FALSE,ch,0,ch->specials.carried_by,TO_CHAR);
    return;
  }

   if (world[ch->in_room].obj)
       {
	   cont = world[ch->in_room].obj;
	   if (GET_ITEM_TYPE(cont) == ITEM_CONTAINER &&
	       !IS_SET(cont->obj_flags.value[1], CONT_ONEWAY) &&
	       !IS_SET(cont->obj_flags.value[1],CONT_CLOSED)){
	       if (GET_OBJ_SIZE(cont) - GET_SIZE(ch) > 1){
		   sprintf(buf1,
			   "The %s is too small you are stuck!"
			   ,first_name(cont->name));
		   act(buf1,TRUE,ch,0,0,TO_CHAR);
		   return;
	       }				      

	       if (cont->in_room != NOWHERE){
		   act("You leave $p.",TRUE,ch,cont,0,TO_CHAR);
		   act("$n leaves $p.",TRUE,ch,cont,0,TO_ROOM); 	   
		   to_room = cont->in_room;
		   was_in = ch->in_room;
		   char_from_room(ch);
		   char_to_room(ch,to_room, FALSE);
		   do_look(ch,"",0,0);
		   act("$n leaves $p.",TRUE,ch,cont,0,TO_ROOM);
		   if (ch->followers) {
		     for (k = ch->followers; k; k = next_dude) {
		       next_dude = k->next;
		       if ((k->follower->in_room == was_in) &&
			   (GET_POS(k->follower) >= POSITION_STANDING)
			   && !k->follower->specials.fighting){
			 if(IS_NPC(ch) && !number(0,3)
			    && GET_LEVEL(k->follower)
			    < LEVEL_BUILDER && !IS_NPC(k->follower)){
			   act("You lost track of $n.",TRUE,ch,0,k->follower,TO_VICT);
			   break;}
			 else {
			   act("You follow $N.\r\n", FALSE, k->follower, 0, ch, TO_CHAR);
			   do_leave(k->follower, argument,0,0);
			 }
		       }
		     }
		   }
		   return;
	       }
	   }
	   else if (!IS_SET(cont->obj_flags.value[1], CONT_ONEWAY)){
	       sprintf(buf1,"The %s seems to be closed.",first_name(cont->name));
	       act(buf1,TRUE,ch,cont,0,TO_CHAR);
	       return;
	   }
	       
       }
   if (!IS_SET(world[ch->in_room].room_flags, INDOORS))
      send_to_char("You are outside.. where do you want to go?\r\n", ch);
   else {
      for (door = 0; door < NUM_OF_DIRS; door++)
	 if (EXIT(ch, door))
	    if (EXIT(ch, door)->to_room != NOWHERE)
	       if (!IS_SET(EXIT(ch, door)->exit_info, EX_CLOSED) && 
	           !IS_SET(world[real_room(EXIT(ch, door)->to_room)].room_flags, INDOORS)) {
		  do_move(ch, "", ++door, 0);
		  return;
	       }
      send_to_char("I see no obvious exits to the outside.\r\n", ch);
   }
}


ACMD(do_stand)
{
  if (IS_AFFECTED(ch, AFF_PARALYSIS)) {
    send_to_char("Lie still you can't move a muscle.\r\n",ch);
    return;
  }
  if (ch->specials.mount && GET_POS(ch) != POSITION_STANDING) {
    GET_POS(ch) = POSITION_STANDING;
    send_to_char("Stand? Your mount might not like that.\r\n", ch);
    return;}    
    if (GET_POS(ch) == POSITION_STANDING){
	send_to_char("You are already standing.\r\n",ch);
	return;
    }
    if (IS_AFFECTED(ch, AFF_SLIPPY))
      if((number(0,2) && IS_NPC(ch)) || (number(0,1) && !IS_NPC(ch))){
	act("$n tries to stand up but slips and falls!", TRUE, ch,0,0,TO_ROOM);
	send_to_char("You try to stand but you slip and fall.\r\n", ch);
	return;
      }
    if (IS_AFFECTED(ch, AFF_BASH)){
      if((number(0,2) && IS_NPC(ch)) || (number(0,1) && !IS_NPC(ch))){
	act("$n tries to stand up but is too winded!", TRUE, ch,0,0,TO_ROOM);
	act("You try to stand but you are unable to catch your breath.", FALSE, ch,0,0,TO_CHAR);
	return;
      }
      else
	affect_from_char(ch, SKILL_BASH);
    }
    switch (GET_POS(ch)) {
    case POSITION_SITTING	:
      act("You stand up.", FALSE, ch, 0, 0, TO_CHAR);
      act("$n clambers to $s feet.", TRUE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POSITION_STANDING;
      break;
    case POSITION_RESTING	:
      act("You stop resting, and stand up.", FALSE, ch, 0, 0, TO_CHAR);
      act("$n stops resting, and clambers on $s feet.", TRUE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POSITION_STANDING;
      break;
    case POSITION_SLEEPING :
	act("You have to wake up first!", FALSE, ch, 0, 0, TO_CHAR);
	break;
    default :
      act("You stop floating around, and put your feet on the ground.",
	  FALSE, ch, 0, 0, TO_CHAR);
      act("$n stops floating around, and puts $s feet on the ground.",
	  TRUE, ch, 0, 0, TO_ROOM);
      break;
    }
    
}


ACMD(do_sit)
{
  if (ch->specials.mount) {
    send_to_char("Sit where? you are riding?\r\n", ch);
    return;}    
    if (ch->specials.fighting){
	act("Sit down while fighting?  Are you MAD?", FALSE, ch, 0, 0, TO_CHAR);
	return;}
   switch (GET_POS(ch)) {
   case POSITION_STANDING :
      act("You sit down.", FALSE, ch, 0, 0, TO_CHAR);
      act("$n sits down.", FALSE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POSITION_SITTING;
      break;
   case POSITION_SITTING	:
      send_to_char("You'r sitting already.\r\n", ch);
      break;
   case POSITION_RESTING	:
      act("You stop resting, and sit up.", FALSE, ch, 0, 0, TO_CHAR);
      act("$n stops resting.", TRUE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POSITION_SITTING;
      break;
   case POSITION_SLEEPING :
      act("You have to wake up first.", FALSE, ch, 0, 0, TO_CHAR);
      break;
    default :
      act("You stop floating around, and sit down.", FALSE, ch, 0, 0, TO_CHAR);
      act("$n stops floating around, and sits down.", TRUE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POSITION_SITTING;
      break;
   }
}




ACMD(do_rest)
{
  if (ch->specials.mount) {
    send_to_char("Rest while riding?  Well you can try?\r\n", ch);
    return;}    
    if (ch->specials.fighting){
	act("Rest while fighting?  Are you MAD?", FALSE, ch, 0, 0, TO_CHAR);
	return;}
   switch (GET_POS(ch)) {
   case POSITION_STANDING :
      act("You lie down and rest your tired bones.", FALSE, ch, 0, 0, TO_CHAR);
      act("$n lies down and rests.", TRUE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POSITION_RESTING;
      break;
   case POSITION_SITTING :
      act("You rest your tired bones.", FALSE, ch, 0, 0, TO_CHAR);
      act("$n rests.", TRUE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POSITION_RESTING;
      break;
   case POSITION_RESTING :
      act("You are already resting.", FALSE, ch, 0, 0, TO_CHAR);
      break;
   case POSITION_SLEEPING :
      act("You have to wake up first.", FALSE, ch, 0, 0, TO_CHAR);
      break;
   default :
      act("You stop floating around, and stop to rest your tired bones.",
          FALSE, ch, 0, 0, TO_CHAR);
      act("$n stops floating around, and rests.", FALSE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POSITION_SITTING;
      break;
   }
}


ACMD(do_sleep)
{
  if (ch->specials.mount) {
    send_to_char("Sleep while riding?  Are you MAD?\r\n", ch);
    return;}    
    if (ch->specials.fighting){
	send_to_char("Sleep while fighting?  Are you MAD?\r\n", ch);
	return;}
   switch (GET_POS(ch)) {
   case POSITION_STANDING :
   case POSITION_SITTING  :
   case POSITION_RESTING  :
      send_to_char("You go to sleep.\r\n", ch);
      act("$n lies down and falls asleep.", TRUE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POSITION_SLEEPING;
      break;
   case POSITION_SLEEPING :
      send_to_char("You are already sound asleep.\r\n", ch);
      break;
   default :
      act("You stop floating around, and lie down to sleep.",
          FALSE, ch, 0, 0, TO_CHAR);
      act("$n stops floating around, and lie down to sleep.",
          TRUE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POSITION_SLEEPING;
      break;
   }
}


ACMD(do_wake)
{
   struct char_data *tmp_char;

   one_argument(argument, arg);
   if (*arg) {
      if (GET_POS(ch) == POSITION_SLEEPING) {
	 act("You can't wake people up if you are asleep yourself!",
	     FALSE, ch, 0, 0, TO_CHAR);
      } else {
	 tmp_char = get_char_room_vis(ch, arg);
	 if (tmp_char) {
	    if (tmp_char == ch) {
	       act("If you want to wake yourself up, just type 'wake'",
	           FALSE, ch, 0, 0, TO_CHAR);
	    } else {
	       if (GET_POS(tmp_char) == POSITION_SLEEPING) {
		  if (IS_AFFECTED(tmp_char, AFF_SLEEP) || GET_MOVE(tmp_char) < 0) {
		     act("You can not wake $M up!", FALSE, ch, 0, tmp_char, TO_CHAR);
		  } else {
		     act("You wake $M up.", FALSE, ch, 0, tmp_char, TO_CHAR);
		     GET_POS(tmp_char) = POSITION_SITTING;
		     act("You are awakened by $n.", FALSE, ch, 0, tmp_char, TO_VICT);
		  }
	       } else {
		  act("$N is already awake.", FALSE, ch, 0, tmp_char, TO_CHAR);
	       }
	    }
	 } else {
	    send_to_char("You do not see that person here.\r\n", ch);
	 }
      }
   } else {
      if (IS_AFFECTED(ch, AFF_SLEEP) || (GET_MOVE(ch) < 0 && number(0,3)) ) {
	 send_to_char("You can't wake up!\r\n", ch);
      } else {
	 if (GET_POS(ch) > POSITION_SLEEPING)
	    send_to_char("You are already awake...\r\n", ch);
	 else {
	    send_to_char("You wake, and sit up.\r\n", ch);
	    act("$n awakens.", TRUE, ch, 0, 0, TO_ROOM);
	    GET_POS(ch) = POSITION_SITTING;
	 }
      }
   }
}


ACMD(do_follow)
{
   struct char_data *leader;
   int result;

   void	stop_follower(struct char_data *ch);
   int	add_follower(struct char_data *ch, struct char_data *leader);

   one_argument(argument, buf);

   if (*buf) {
      if (!str_cmp(buf, "self"))
	 leader = ch;
      else if (!(leader = get_char_room_vis(ch, buf))) {
	 send_to_char("I see no person by that name here!\r\n", ch);
	 return;
      }
   } else {
      send_to_char("Whom do you wish to follow?\r\n", ch);
      return;
   }

   if (ch->master == leader) {
      sprintf(buf, "You are already following %s.\r\n", HMHR(leader));
      send_to_char(buf, ch);
      return;
   }

   if (IS_AFFECTED(ch, AFF_CHARM) && (ch->master)) {
      act("But you only feel like following $N!", FALSE, ch, 0, ch->master, TO_CHAR);
   } else { /* Not Charmed follow person */
      if (leader == ch) {
	 if (!ch->master) {
	    send_to_char("You are already following yourself.\r\n", ch);
	    return;
	 }
	 stop_follower(ch);
      } else {
	 if (circle_follow(ch, leader)) {
	    act("Sorry, but following in loops is not allowed.", FALSE, ch, 0, 0, TO_CHAR);
	    return;
	 }

	 if (ch->master)
	    stop_follower(ch);

	 REMOVE_BIT(ch->specials.affected_by, AFF_GROUP);

	 if (( result = add_follower(ch, leader)) == 0)
	   {
	     act("$N tried to follow you but you already have too many followers."
		 ,FALSE,leader,0,ch,TO_CHAR);
	     act("$n already has too many followers."
		 ,FALSE,leader,0,ch,TO_VICT);	       
	   }
      }
   }
}