crodo_mud/cnf/
crodo_mud/lib/
crodo_mud/lib/house/
crodo_mud/lib/misc/
crodo_mud/lib/plralias/F-J/
crodo_mud/lib/plralias/U-Z/
crodo_mud/lib/plrobjs/
crodo_mud/lib/plrvars/A-E/
crodo_mud/lib/plrvars/F-J/
crodo_mud/lib/plrvars/K-O/
crodo_mud/lib/plrvars/P-T/
crodo_mud/lib/plrvars/U-Z/
crodo_mud/lib/text/
crodo_mud/lib/text/help/
crodo_mud/lib/world/
crodo_mud/src/
/* ************************************************************************
*   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, 94 by the Trustees of the Johns Hopkins University *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */

#include "conf.h"
#include "sysdep.h"


#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "spells.h"
#include "house.h"
#include "constants.h"
#include "dg_scripts.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 index_data *mob_index;

/* external functs */
void add_follower(struct char_data *ch, struct char_data *leader);
int special(struct char_data *ch, int cmd, char *arg);
void death_cry(struct char_data *ch);
int find_eq_pos(struct char_data * ch, struct obj_data * obj, char *arg);
void do_tracking(struct char_data * ch);

/* local functions */
int has_boat(struct char_data *ch);
int vehicle_pilot(struct char_data *ch);
int can_swim(struct char_data *ch);
int find_door(struct char_data *ch, const char *type, char *dir, const char *cmdname);
int has_key(struct char_data *ch, obj_vnum key);
void do_doorcmd(struct char_data *ch, struct obj_data *obj, int door, int scmd);
int ok_pick(struct char_data *ch, obj_vnum keynum, int pickproof, int scmd);
int can_fly(struct char_data *ch);

ACMD(do_gen_door);
ACMD(do_enter);
ACMD(do_leave);
ACMD(do_stand);
ACMD(do_sit);
ACMD(do_rest);
ACMD(do_sleep);
ACMD(do_wake);
ACMD(do_follow);
ACMD(do_fly);
ACMD(do_mount);
ACMD(do_dismount);
ACMD(do_board);


/* simple function to determine if char can walk on water */
int has_boat(struct char_data *ch)
{
  int i;
/*
  if (ROOM_IDENTITY(ch->in_room) == DEAD_SEA)
    return (1);
*/

  if (GET_LEVEL(ch) > LVL_IMMORT)
    return (1);

  if (AFF_FLAGGED(ch, AFF_WATERWALK) || AFF_FLAGGED(ch, AFF_FLY))
    return (1);

 /* Must be sitting in a valid craft for it to work */
  if (SITTING_IN(ch))
   if ((GET_OBJ_TYPE(SITTING_IN(ch)) == ITEM_BOAT) ||
       (GET_OBJ_TYPE(SITTING_IN(ch)) == ITEM_AIRPLANE))
    return (1);

  /* and any boat you're wearing will do it too */
  for (i = 0; i < NUM_WEARS; i++)
    if (GET_EQ(ch, i) && GET_OBJ_TYPE(GET_EQ(ch, i)) == ITEM_BOAT)
      return (1);

  /* If riding a mount perform checks for mount */
   if (RIDING(ch))
    if (has_boat(RIDING(ch)))
     return (1);

  return (0);
} 

/* simple function to determine if char is driving a vehicle */
int vehicle_pilot(struct char_data *ch) {

  if ((SITTING_IN(ch)) && IS_VEHICLE(SITTING_IN(ch)) &&
     (OBJ_SAT_IN_BY(SITTING_IN(ch)) == ch)) {

     if (GET_POS(ch) < POS_SITTING) {
      send_to_char("You're in no position to do anything now.\r\n", ch);
      return (0); } 

      return (1); }

/* Riding is considered riding a vehicle */
     if (RIDING(ch) || RIDDEN_BY(ch))
      return 1;

   return (0);
}

/* simple function to determine if char can fly */
int can_fly(struct char_data *ch)
{
  
  if (GET_LEVEL(ch) > LVL_IMMORT)
    return (1);

  if (AFF_FLAGGED(ch, AFF_FLY))
    return (1);

 /* Must be sitting in a valid craft for it to work */
  if (SITTING_IN(ch))
    if (GET_OBJ_TYPE(SITTING_IN(ch)) == ITEM_AIRPLANE)
    return (1);

  /* If riding a mount perform checks for mount */
   if (RIDING(ch))
    if (can_fly(RIDING(ch)))
     return (1);
   
    return (0);
}

/* simple function to determine if char can fly */
int can_swim(struct char_data *ch)
{
  
  if (GET_LEVEL(ch) > LVL_IMMORT)
    return (1);

  if (AFF_FLAGGED(ch, AFF_WATERLUNG))
    return (1);
  
  /* If riding a mount perform checks for mount */
   if (RIDING(ch))
    if (can_swim(RIDING(ch)))
     return (1);

    return (0);
}

/* do_simple_move assumes
 *    1. That there is no master and no followers.
 *    2. That the direction exists.
 *
 *   Returns :
 *   1 : If succes.
 *   0 : If fail
 */
int do_simple_move(struct char_data *ch, int dir, int need_specials_check)
{
  room_rnum was_in;
  int need_movement;

  /*
   * Check for special routines (North is 1 in command list, but 0 here) Note
   * -- only check if following; this avoids 'double spec-proc' bug
   */
  if (need_specials_check && special(ch, dir + 1, "")) /* XXX: Evaluate NULL */
    return (0);

  /* charmed? */
  if (AFF_FLAGGED(ch, AFF_CHARM) && ch->master && ch->in_room == ch->master->in_room) {

    if (GET_MOB_VNUM(ch) == 13) {
    send_to_char("You clack your bones as you become restless.\r\n", ch);
    act("$n clacks their bones together.", FALSE, ch, 0, 0, TO_ROOM);
   return (0); }

    send_to_char("The thought of leaving your master makes you weep.\r\n", ch);
    act("$n bursts into tears.", FALSE, ch, 0, 0, TO_ROOM);
    return (0);
  }

  /* If mount, use global direction checks for mount */

  if (RIDING(ch))
    if ((!CAN_GO(RIDING(ch),dir)) ||
       (!has_boat(RIDING(ch)) && (SECT(EXIT(ch, dir)->to_room) == SECT_WATER_NOSWIM)))  {
     send_to_char("Your mount looks in that direction and shakes it's head.\r\n", ch);
      return(0); }

  if (RIDING(ch))
    if (SECT(EXIT(ch, dir)->to_room) == SECT_INSIDE)  {
     send_to_char("You probably shouldn't just ride in- maybe dismount first?\r\n", ch);
      return(0); }

  if (RIDDEN_BY(ch))
    if ((!CAN_GO(ch ,dir)) ||
       (!has_boat(ch) && (SECT(EXIT(ch, dir)->to_room) == SECT_WATER_NOSWIM)))  {
     send_to_char("Your mount looks in that direction and shakes it's head.\r\n", RIDDEN_BY(ch));
      return(0); }

  if (RIDDEN_BY(ch))
    if (SECT(EXIT(ch, dir)->to_room) == SECT_INSIDE)  { 
     send_to_char("You probably shouldn't just mosey in with someone on your back!\r\n", ch);
      return(0); }  

  /* Check for dock situations */
  if ((SECT(ch->in_room) != SECT_WATER_NOSWIM) &&
      (SECT(EXIT(ch, dir)->to_room) != SECT_WATER_NOSWIM)) {

    if (SITTING_IN(ch) && (GET_OBJ_TYPE(SITTING_IN(ch)) == ITEM_BOAT) && vehicle_pilot(ch)) {

     switch (SECT(EXIT(ch, dir)->to_room)) {

      case SECT_FLYING:
       send_to_char("Your boat is too heavy to fly.\r\n", ch);        
      break;
      case SECT_UNDERWATER:
       send_to_char("Real good, drag your boat underwater!\r\n", ch);        
      break;
      default:
       send_to_char("Boats may come to shore but not travel on land!\r\n", ch); 
      break;
						}
      return (0);
    }
  }

    /* if this room is up and the air, check for fly spell */
  if ((SECT(ch->in_room) == SECT_FLYING) ||
      (SECT(EXIT(ch, dir)->to_room) == SECT_FLYING)) {

  if ((RIDING(ch)) && (!can_fly(RIDING(ch))) ) {
      send_to_char("Your mount looks at you and shakes it's head.\r\n", ch);
      return (0);                    } else
  if (!can_fly(ch)) {
      send_to_char("Your appendages resemble more an arm than a wing!\r\n", ch);
      return (0);                    }
                                                       }

   /* if ths room is underwater, check for waterlung spell */
  if ((SECT(ch->in_room) == SECT_UNDERWATER) ||
      (SECT(EXIT(ch, dir)->to_room) == SECT_UNDERWATER)) {
  
  if (!can_swim(ch)) {
      send_to_char("You have a fish face, but not the gills!\r\n", ch);
      return (0);                    }
                                                       }

  /* move points needed is avg. move loss for src and destination sect 
type */
  need_movement = (movement_loss[SECT(ch->in_room)] +
		   movement_loss[SECT(EXIT(ch, dir)->to_room)]) / 2;

  if (GET_POS(ch) == POS_SWIMMING)
    need_movement = (need_movement * 13);

    if (RIDING(ch)) {
     if ((GET_MOVE(RIDING(ch)) < need_movement) && (!IS_NPC(ch))) {
       send_to_char("Your mount is too exhausted.\r\n", ch);
       return 0;
     }
 } else {
  if (GET_MOVE(ch) < need_movement && !IS_NPC(ch)) {
    if (need_specials_check && 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 (0);
  }
}

  if (ROOM_FLAGGED(ch->in_room, ROOM_ATRIUM)) {
    if (!House_can_enter(ch, GET_ROOM_VNUM(EXIT(ch, dir)->to_room))) {
      send_to_char("That's private property -- no trespassing!\r\n", ch);
      return (0);
    }
  }
  if (ROOM_FLAGGED(EXIT(ch, dir)->to_room, ROOM_TUNNEL) &&
      num_pc_in_room(&(world[EXIT(ch, dir)->to_room])) > 1) {
    send_to_char("There isn't enough room there for more than one person!\r\n", ch);
    return (0);
  }
  /* Mortals and low level gods cannot enter greater god rooms. */
  if (ROOM_FLAGGED(EXIT(ch, dir)->to_room, ROOM_GODROOM) &&
	GET_LEVEL(ch) < LVL_GRGOD) {
    send_to_char("You aren't godly enough to use that room!\r\n", ch);
    return (0);
  }

  /* see if an entry trigger disallows the move */
  if (!entry_mtrigger(ch))
    return 0;
  if (!enter_wtrigger(&world[EXIT(ch, dir)->to_room], ch, dir))
    return 0;

  /* Now we know we're allow to go into the room. */
  if (GET_LEVEL(ch) < LVL_IMMORT && !IS_NPC(ch) && !RIDING(ch))
    GET_MOVE(ch) -= need_movement;
  else if (RIDING(ch) && !IS_NPC(ch))
    GET_MOVE(RIDING(ch)) -= need_movement;

  was_in = ch->in_room;

/* Positional adustments */
/* Swim if diving into water */
  if ((GET_POS(ch) != POS_SWIMMING) && (GET_LEVEL(ch) < LVL_IMMORT) &&
     ((SECT(EXIT(ch, dir)->to_room) == SECT_UNDERWATER) ||
      (SECT(EXIT(ch, dir)->to_room) == SECT_WATER_SWIM) ||  
      (SECT(EXIT(ch, dir)->to_room) == SECT_WATER_NOSWIM)) ) {

/* Jumping into water? */
  if ( (SITTING_IN(ch) == NULL) && (!AFF_FLAGGED(ch, AFF_WATERWALK)) && (!AFF_FLAGGED(ch, AFF_FLY)) )  {
   GET_POS(ch) = POS_SWIMMING;
   act("$n jumps head first into the water.", FALSE, ch, 0, 0, TO_ROOM);
   send_to_char("You jump head first into the water.\r\n", ch);
                        }

  if (SITTING_IN(ch))
   if (SECT(EXIT(ch, dir)->to_room) == SECT_UNDERWATER) {
        act("$n jumps from $p into the water.", FALSE, ch, SITTING_IN(ch), 0, TO_ROOM);
        char_from_chair(ch);
	GET_POS(ch) = POS_SWIMMING;
	send_to_char("You dive down into the water.\r\n", ch); }
}


/* Positional adustments */
/* Stand if exiting water */
  if ((GET_POS(ch) == POS_SWIMMING) &&
     ((SECT(EXIT(ch, dir)->to_room) != SECT_UNDERWATER) &&
      (SECT(EXIT(ch, dir)->to_room) != SECT_WATER_SWIM) &&
      (SECT(EXIT(ch, dir)->to_room) != SECT_WATER_NOSWIM)) ) {

   send_to_char("You crawl up out of the water.\r\n", ch);
   GET_POS(ch) = POS_STANDING;   
}

/* Build entrance and exit messages */

   if ( (!IS_AFFECTED(ch, AFF_SNEAK)) &&
       ( (!RIDING(ch)) || (!IS_AFFECTED(RIDING(ch), AFF_SNEAK))) ) {

    sprintf(buf2, "$n ");

/* Type of movement */

  /* Vehicle support */
  if (SITTING_IN(ch) && vehicle_pilot(ch)) {

   if (GET_OBJ_TYPE(SITTING_IN(ch)) == ITEM_BOAT)
     sprintf(buf2 + strlen(buf2), "sails ");
   else
    if (GET_OBJ_TYPE(SITTING_IN(ch)) == ITEM_AIRPLANE)   
     sprintf(buf2 + strlen(buf2), "flies ");
   else
    if (GET_OBJ_TYPE(SITTING_IN(ch)) == ITEM_WAGON)   
     sprintf(buf2 + strlen(buf2), "rides "); 

  /* Object Name */
    sprintf(buf2 + strlen(buf2), "%s ", SITTING_IN(ch)->short_description);
} else {

  /* Positional movement types */
  switch (GET_POS(ch)) {
   case POS_FLYING:
    sprintf(buf2+ strlen(buf2), "flies ");
    break;
   case POS_SWIMMING:
    sprintf(buf2+ strlen(buf2), "swims ");
    break;
   default:
    if (RIDING(ch))
     sprintf(buf2+ strlen(buf2), "rides ");
    else {
    if (dg_var_value(ch, "MovementOut") != NULL)
     sprintf(buf2+ strlen(buf2), "%s ",
       dg_var_value(ch, "MovementOut"));
    else
     sprintf(buf2+ strlen(buf2), "walks ");
         }
    break;		} 

  /* Mount name? */
  if (RIDING(ch))
    sprintf(buf2 + strlen(buf2), "%s ", GET_NAME(RIDING(ch))); 

	}
   
 /* Direction of travel */
    sprintf(buf2 + strlen(buf2), "%s%s.", (dir < UP || dir > DOWN  ? "to the " : ""), dirs[dir]);

/* Send leaving message */
   act(buf2, TRUE, ch, 0, 0, TO_ROOM); }

/* Move character */
  char_from_room(ch);
  char_to_room(ch, world[was_in].dir_option[dir]->to_room);

/* Build Entrance Message */

   if ( (!IS_AFFECTED(ch, AFF_SNEAK)) &&
       ( (!RIDING(ch)) || (!IS_AFFECTED(RIDING(ch), AFF_SNEAK))) ) {

     sprintf(buf2, "$n ");

  /* Vehicle Support */
  if (SITTING_IN(ch) && vehicle_pilot(ch)) {

   if (GET_OBJ_TYPE(SITTING_IN(ch)) == ITEM_BOAT)
     sprintf(buf2 + strlen(buf2), "has sailed in from ");
   else
   if (GET_OBJ_TYPE(SITTING_IN(ch)) == ITEM_AIRPLANE)    
     sprintf(buf2 + strlen(buf2), "has flown in from ");
   else
   if (GET_OBJ_TYPE(SITTING_IN(ch)) == ITEM_WAGON)    
     sprintf(buf2 + strlen(buf2), "has ridden in from ");
 } else {
  
  /* Positional movement types */

  switch (GET_POS(ch)) {
   case POS_FLYING:
    sprintf(buf2+ strlen(buf2), "has flown in from ");
    break;
   case POS_SWIMMING:
    sprintf(buf2+ strlen(buf2), "has swam in from ");
    break;
   default:
    if (RIDING(ch))
     sprintf(buf2+ strlen(buf2), "has arrived from ");
    else {
    if (dg_var_value(ch, "MovementIn") != NULL)
     sprintf(buf2+ strlen(buf2), "has %s in from ",
       dg_var_value(ch, "MovementIn"));
    else
     sprintf(buf2+ strlen(buf2), "has walked in from ");  
     }
    break;  }
	}

/* Direction of entrance */
     sprintf(buf2 + strlen(buf2), "%s%s",
       (dir < UP || dir > DOWN  ? "the " : ""),
       (dir == UP ? "below": dir == DOWN ? "above" : dirs[rev_dir[dir]]));

  /* Object Name */
    if (SITTING_IN(ch))
    sprintf(buf2 + strlen(buf2), " %s %s",
	 sit_types[GET_OBJ_VAL(SITTING_IN(ch), 3)],
	 SITTING_IN(ch)->short_description);

  /* Mount name */
  if (RIDING(ch))
    sprintf(buf2 + strlen(buf2), " riding %s", GET_NAME(RIDING(ch))); 

    sprintf(buf2 + strlen(buf2), ".");

/* Send arriving message */
   act(buf2, TRUE, ch, 0, 0, TO_ROOM);
}

/* Move vehicle and passengers */
   if (SITTING_IN(ch))
   move_vehicle(SITTING_IN(ch), world[was_in].dir_option[dir]->to_room);
 
 /* Move mount? */
   if ( (RIDING(ch)) && (was_in == IN_ROOM(RIDING(ch))) ) {
    char_from_room(RIDING(ch));
    char_to_room(RIDING(ch), IN_ROOM(ch));   }

/* Move Rider? */
   if ( (RIDDEN_BY(ch)) && (was_in == IN_ROOM(RIDDEN_BY(ch))) ) {
    char_from_room(RIDDEN_BY(ch));
    char_to_room(RIDDEN_BY(ch), IN_ROOM(ch));   }
  
  if (ch->desc != NULL)
    look_at_room(ch, 0);
  
  /* If PC is tracking a victim */
  if (!IS_NPC(ch) && (HUNTING(ch) != NULL))
   do_tracking(ch);

  if (ROOM_FLAGGED(ch->in_room, ROOM_DEATH) && GET_LEVEL(ch) < LVL_IMMORT) {

    if (!IS_NPC(ch))
     GET_DT_CNT(ch)++;

    if (RIDING(ch)) {
     death_cry(RIDING(ch));
     extract_char(RIDING(ch));
		   }

    if (RIDDEN_BY(ch)) {
     death_cry(RIDDEN_BY(ch));
     extract_char(RIDDEN_BY(ch));
		   }

    log_death_trap(ch);
    death_cry(ch);
    extract_char(ch);
    return (0);
  }

  entry_memory_mtrigger(ch);
  if (!greet_mtrigger(ch, dir)) {
    char_from_room(ch);
    char_to_room(ch, was_in);
    look_at_room(ch, 0);
  } else greet_memory_mtrigger(ch);

  return (1);
}


int perform_move(struct char_data *ch, int dir, int need_specials_check)
{
  room_rnum was_in;
  struct follow_type *k, *next;

  if (ch == NULL || dir < 0 || dir >= NUM_OF_DIRS) {
   if (FIGHTING(ch) && (!vehicle_pilot(ch)) )
    return (0);   }
  else if (!EXIT(ch, dir) || EXIT(ch, dir)->to_room == NOWHERE ||
           (EXIT_FLAGGED(EXIT(ch, dir), EX_HIDDEN)))
    send_to_char("Alas, you cannot go that way...\r\n", ch);
  else if (EXIT_FLAGGED(EXIT(ch, dir), EX_CLOSED)) {
    if (EXIT(ch, dir)->keyword) {
      sprintf(buf2, "The %s seems to be closed.\r\n", fname(EXIT(ch, dir)->keyword));
      send_to_char(buf2, ch);
    } else
      send_to_char("It seems to be closed.\r\n", ch);
  } else {
    if (!ch->followers)
      return (do_simple_move(ch, dir, need_specials_check));

    was_in = ch->in_room;
    if (!do_simple_move(ch, dir, need_specials_check))
      return (0);

    if (SITTING_IN(ch) == NULL)
     for (k = ch->followers; k; k = next) {
      next = k->next;
      if ((k->follower->in_room == was_in) &&
	  (GET_POS(k->follower) >= POS_STANDING)) {
	act("You follow $N.\r\n", FALSE, k->follower, 0, ch, TO_CHAR);
	perform_move(k->follower, dir, 1);
      }
    }
    return (1);
  }
  return (0);
}


ACMD(do_move)
{
  /*
   * This is basically a mapping of cmd numbers to perform_move indices.
   * It cannot be done in perform_move because perform_move is called
   * by other functions which do not require the remapping.
   */
  perform_move(ch, subcmd - 1, 0);
}


int find_door(struct char_data *ch, const char *type, char *dir, const char *cmdname)
{
  int door;

  if (*dir) {			/* a direction was specified */
    if ((door = search_block(dir, dirs, FALSE)) == -1) /* Partial Match */
      if ((door = search_block(dir, abbr_dirs, FALSE)) == -1) {
      send_to_char("That's not a direction.\r\n", ch);
      return (-1);
    }
    if (EXIT(ch, door)) {	/* Braces added according to indent. -gg */
      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 {
      sprintf(buf2, "I really don't see how you can %s anything there.\r\n", cmdname);
      send_to_char(buf2, ch);
      return (-1);
    }
  } else {			/* try to locate the keyword */
    if (!*type) {
      sprintf(buf2, "What is it you want to %s?\r\n", cmdname);
      send_to_char(buf2, ch);
      return (-1);
    }
    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, "There doesn't seem to be %s %s here.\r\n", AN(type), type);
    send_to_char(buf2, ch);
    return (-1);
  }
}


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

  for (o = ch->carrying; o; o = o->next_content)
    if (GET_OBJ_VNUM(o) == key)
      return (1);

  if (GET_EQ(ch, WEAR_HOLD))
    if (GET_OBJ_VNUM(GET_EQ(ch, WEAR_HOLD)) == key)
      return (1);

  return (0);
}



#define NEED_OPEN	(1 << 0)
#define NEED_CLOSED	(1 << 1)
#define NEED_UNLOCKED	(1 << 2)
#define NEED_LOCKED	(1 << 3)

const char *cmd_door[] =
{
  "open",
  "close",
  "unlock",
  "lock",
  "pick"
};

const int flags_door[] =
{
  NEED_CLOSED | NEED_UNLOCKED,
  NEED_OPEN,
  NEED_CLOSED | NEED_LOCKED,
  NEED_CLOSED | NEED_UNLOCKED,
  NEED_CLOSED | NEED_LOCKED
};


#define EXITN(room, door)		(world[room].dir_option[door])
#define OPEN_DOOR(room, obj, door)	((obj) ?\
		(TOGGLE_BIT(GET_OBJ_VAL(obj, 1), CONT_CLOSED)) :\
		(TOGGLE_BIT(EXITN(room, door)->exit_info, EX_CLOSED)))
#define LOCK_DOOR(room, obj, door)	((obj) ?\
		(TOGGLE_BIT(GET_OBJ_VAL(obj, 1), CONT_LOCKED)) :\
		(TOGGLE_BIT(EXITN(room, door)->exit_info, EX_LOCKED)))

void do_doorcmd(struct char_data *ch, struct obj_data *obj, int door, int scmd)
{
  int other_room = 0;
  struct room_direction_data *back = 0;

  sprintf(buf, "$n %ss ", cmd_door[scmd]);
  if (!obj && ((other_room = EXIT(ch, door)->to_room) != NOWHERE))
    if ((back = world[other_room].dir_option[rev_dir[door]]) != NULL)
      if (back->to_room != ch->in_room)
	back = 0;

  switch (scmd) {
  case SCMD_OPEN:
  case SCMD_CLOSE:
    OPEN_DOOR(ch->in_room, obj, door);
    if (back)
      OPEN_DOOR(other_room, obj, rev_dir[door]);
    send_to_char(OK, ch);
    break;
  case SCMD_UNLOCK:
  case SCMD_LOCK:
    LOCK_DOOR(ch->in_room, obj, door);
    if (back)
      LOCK_DOOR(other_room, obj, rev_dir[door]);
    send_to_char("*Click*\r\n", ch);
    break;
  case SCMD_PICK:
    LOCK_DOOR(ch->in_room, obj, door);
    if (back)
      LOCK_DOOR(other_room, obj, rev_dir[door]);
    send_to_char("The lock quickly yields to your skills.\r\n", ch);
    strcpy(buf, "$n skillfully picks the lock on ");
    break;
  }

  /* Notify the room */
  sprintf(buf + strlen(buf), "%s%s.", ((obj) ? "" : "the "), (obj) ? "$p" :
	  (EXIT(ch, door)->keyword ? "$F" : "door"));
  if (!(obj) || (obj->in_room != NOWHERE))
    act(buf, FALSE, ch, obj, obj ? 0 : EXIT(ch, door)->keyword, TO_ROOM);

  /* Notify the other room */
  if ((scmd == SCMD_OPEN || scmd == SCMD_CLOSE) && back) {
    sprintf(buf, "The %s is %s%s from the other side.",
	 (back->keyword ? fname(back->keyword) : "door"), cmd_door[scmd],
	    (scmd == SCMD_CLOSE) ? "d" : "ed");
    if (world[EXIT(ch, door)->to_room].people) {
      act(buf, FALSE, world[EXIT(ch, door)->to_room].people, 0, 0, TO_ROOM);
      act(buf, FALSE, world[EXIT(ch, door)->to_room].people, 0, 0, TO_CHAR);
    }
  }
}


int ok_pick(struct char_data *ch, obj_vnum keynum, int pickproof, int scmd)
{
  int percent;

  percent = number(1, 101);

  if (scmd == SCMD_PICK) {
    if (keynum < 0)
      send_to_char("Odd - you can't seem to find a keyhole.\r\n", ch);
    else if (pickproof)
      send_to_char("It resists your attempts to pick it.\r\n", ch);
    else if (percent > GET_SKILL(ch, SKILL_PICK_LOCK))
      send_to_char("You failed to pick the lock.\r\n", ch);
    else
      return (1);
    return (0);
  }
  return (1);
}


#define DOOR_IS_OPENABLE(ch, obj, door)	((obj) ? \
			((GET_OBJ_TYPE(obj) == ITEM_CONTAINER) && \
			OBJVAL_FLAGGED(obj, CONT_CLOSEABLE)) :\
			(EXIT_FLAGGED(EXIT(ch, door), EX_ISDOOR)))
#define DOOR_IS_OPEN(ch, obj, door)	((obj) ? \
			(!OBJVAL_FLAGGED(obj, CONT_CLOSED)) :\
			(!EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED)))
#define DOOR_IS_UNLOCKED(ch, obj, door)	((obj) ? \
			(!OBJVAL_FLAGGED(obj, CONT_LOCKED)) :\
			(!EXIT_FLAGGED(EXIT(ch, door), EX_LOCKED)))
#define DOOR_IS_PICKPROOF(ch, obj, door) ((obj) ? \
			(OBJVAL_FLAGGED(obj, CONT_PICKPROOF)) : \
			(EXIT_FLAGGED(EXIT(ch, door), EX_PICKPROOF)))

#define DOOR_IS_CLOSED(ch, obj, door)	(!(DOOR_IS_OPEN(ch, obj, door)))
#define DOOR_IS_LOCKED(ch, obj, door)	(!(DOOR_IS_UNLOCKED(ch, obj, door)))
#define DOOR_KEY(ch, obj, door)		((obj) ? (GET_OBJ_VAL(obj, 2)) : \
					(EXIT(ch, door)->key))
#define DOOR_LOCK(ch, obj, door)	((obj) ? (GET_OBJ_VAL(obj, 1)) : \
					(EXIT(ch, door)->exit_info))

ACMD(do_gen_door)
{
  int door = -1;
  obj_vnum keynum;
  char type[MAX_INPUT_LENGTH], dir[MAX_INPUT_LENGTH];
  struct obj_data *obj = NULL;
  struct char_data *victim = NULL;

  skip_spaces(&argument);
  if (!*argument) {
    sprintf(buf, "%s what?\r\n", cmd_door[subcmd]);
    send_to_char(CAP(buf), ch);
    return;
  }
  two_arguments(argument, type, dir);
  if (!generic_find(type, FIND_OBJ_INV | FIND_OBJ_ROOM, ch, &victim, &obj))
    door = find_door(ch, type, dir, cmd_door[subcmd]);

  if ((obj) || (door >= 0)) {
    keynum = DOOR_KEY(ch, obj, door);
    if (!(DOOR_IS_OPENABLE(ch, obj, door)))
      act("You can't $F that!", FALSE, ch, 0, cmd_door[subcmd], TO_CHAR);
    else if (!DOOR_IS_OPEN(ch, obj, door) &&
	     IS_SET(flags_door[subcmd], NEED_OPEN))
      send_to_char("But it's already closed!\r\n", ch);
    else if (!DOOR_IS_CLOSED(ch, obj, door) &&
	     IS_SET(flags_door[subcmd], NEED_CLOSED))
      send_to_char("But it's currently open!\r\n", ch);
    else if (!(DOOR_IS_LOCKED(ch, obj, door)) &&
	     IS_SET(flags_door[subcmd], NEED_LOCKED))
      send_to_char("Oh.. it wasn't locked, after all..\r\n", ch);
    else if (!(DOOR_IS_UNLOCKED(ch, obj, door)) &&
	     IS_SET(flags_door[subcmd], NEED_UNLOCKED))
      send_to_char("It seems to be locked.\r\n", ch);
    else if (!has_key(ch, keynum) && (GET_LEVEL(ch) < LVL_GOD) &&
	     ((subcmd == SCMD_LOCK) || (subcmd == SCMD_UNLOCK)))
      send_to_char("You don't seem to have the proper key.\r\n", ch);
    else if (ok_pick(ch, keynum, DOOR_IS_PICKPROOF(ch, obj, door), subcmd))
      do_doorcmd(ch, obj, door, subcmd);
  }
  return;
}



ACMD(do_enter)
{
  int door;

  one_argument(argument, buf);

  if (!strcmp(buf,"water")) {
    /* Was char sitting in a boat and are they in a water sector? */
    if ((SITTING_IN(ch))&&((SECT(ch->in_room) == SECT_WATER_SWIM)||(SECT(ch->in_room) == SECT_WATER_NOSWIM))) {
      char_from_chair(ch);
      GET_POS(ch) = POS_SWIMMING;
      send_to_char("You jump head first into the water.\r\n", ch);
      act("$n jumps into the water, abandoning $s vessel.", TRUE, ch, 0, 0, TO_ROOM);
    }
    /* Are they in the water already? */
    else if ((SECT(ch->in_room) == SECT_WATER_SWIM)||(SECT(ch->in_room) == SECT_WATER_NOSWIM)||(SECT(ch->in_room) == SECT_UNDERWATER)) {
      if (GET_POS(ch) == POS_SWIMMING) 
        { send_to_char("You're already in the water.\r\n", ch); }
      else {
        GET_POS(ch) = POS_SWIMMING;
        send_to_char("You begin swimming arround.\r\n", ch);
      act("$n enters the water and begins swimming arround.", TRUE, ch, 0, 0, TO_ROOM);
      }
    }
    else {
      if ( (!SITTING_IN(ch)) || ( (SITTING_IN(ch)) && (GET_OBJ_TYPE(SITTING_IN(ch)) != ITEM_BOAT) ) )
        { send_to_char("Maybe you should get on your feet first?\r\n", ch); return; }
      send_to_char("There is no water here.\r\n", ch);
    }
  } 
  else  if (*buf) {		/* an argument was supplied, search for door
				 * keyword */
  if(GET_POS(ch) != POS_STANDING)
    { send_to_char("Maybe you should get on your feet first?\r\n", ch); return; }
    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)) {
	    perform_move(ch, door, 1);
	    return;
	  }
    sprintf(buf2, "There is no %s here.\r\n", buf);
    send_to_char(buf2, ch);
  } else if (ROOM_FLAGGED(ch->in_room, ROOM_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 (!EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED) &&
	      ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_INDOORS)) {
	    perform_move(ch, door, 1);
	    return;
	  }
    send_to_char("You can't seem to find anything to enter.\r\n", ch);
  }
}


ACMD(do_leave)
{
  int door;

  if (OUTSIDE(ch))
    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 (!EXIT_FLAGGED(EXIT(ch, door), EX_CLOSED) &&
	    !ROOM_FLAGGED(EXIT(ch, door)->to_room, ROOM_INDOORS)) {
	    perform_move(ch, door, 1);
	    return;
	  }
    send_to_char("I see no obvious exits to the outside.\r\n", ch);
  }
}


ACMD(do_stand)
{
  if(RIDING(ch))
    { send_to_char("Your mount probably wouldn't like you standing on it.\r\n", ch); return;}
  else if(RIDDEN_BY(ch) && GET_POS(ch)!=POS_STANDING)
    { send_to_char("It's mighty hard to stand up with someone on your back.\r\n", ch); 
return;}

  switch (GET_POS(ch)) {
  case POS_STANDING:
    send_to_char("You are already standing.\r\n", ch);
    break;
  case POS_SITTING:

    if((SECT(ch->in_room) == SECT_WATER_NOSWIM) &&
       (!AFF_FLAGGED(ch, AFF_WATERWALK)) ) {
     send_to_char("Jesus could walk on water, not you!\r\n", ch);
     break; }

    if((SECT(ch->in_room) == SECT_WATER_SWIM) && (SITTING_IN(ch))) {
     send_to_char("Maybe you should enter the water before you go standing up...\r\n", ch);
     break; }

    send_to_char("You stand up.\r\n", ch);
    act("$n clambers to $s feet.", TRUE, ch, 0, 0, TO_ROOM);
    
    /* Was char sitting in a chair/vehicle? */
     if (SITTING_IN(ch))
      char_from_chair(ch);

    /* Will be sitting after a successful bash and may still be fighting. */
    GET_POS(ch) = FIGHTING(ch) ? POS_FIGHTING : POS_STANDING;
    break;
  case POS_RESTING:

    if((SECT(ch->in_room) == SECT_WATER_NOSWIM) &&  
       (!AFF_FLAGGED(ch, AFF_WATERWALK)) ) {
     send_to_char("Jesus could walk on water, not you!\r\n", ch);
     break; }

    send_to_char("You stop resting, and stand up.\r\n", ch);
    act("$n stops resting, and clambers on $s feet.", TRUE, ch, 0, 0, TO_ROOM);

    /* Was char sitting in a chair/vehicle? */
     if (SITTING_IN(ch))
      char_from_chair(ch);

   GET_POS(ch) = POS_STANDING;
    break;
  case POS_SLEEPING:
    send_to_char("You have to wake up first!\r\n", ch);
    break;
  case POS_FIGHTING:
    send_to_char("Do you not consider fighting as standing?\r\n", ch);
    break;
  case POS_FLYING:
   if (SECT(ch->in_room) == SECT_FLYING) {
    send_to_char("If there were something to stand on, maybe!\r\n", ch);
    break;                                }

    send_to_char("You stop flying about, and put your feet on the ground.\r\n",ch);
    act("$n stops flying about, and puts $s feet on the ground.", TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_STANDING;
    break;
  default:
    send_to_char("You stop floating around, and put your feet on the ground.\r\n", ch);
    act("$n stops floating around, and puts $s feet on the ground.",
	TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_STANDING;
    break;
  }
}


ACMD(do_sit)
{
  struct obj_data *chair = NULL;
  struct char_data *tempch;
  int found;
   
  if(RIDING(ch))  
    { send_to_char("You're mounted, what position do you think your in?\r\n", ch); return;}
  else if(RIDDEN_BY(ch) && GET_POS(ch)!=POS_SITTING)
    { send_to_char("It's mighty hard to sit down with someone on your back.\r\n", ch); 
return;}

  one_argument(argument, arg);
    
  if (!*arg)
     found = 0;
  if (!(chair = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents)))
     found = 0;
  else {   
     found = 1;
  }

  switch (GET_POS(ch)) {
  case POS_STANDING:
if (found == 0 ) {
      send_to_char("You sit down.\r\n", ch);
      act("$n sits down.", FALSE, ch, 0, 0, TO_ROOM);
      GET_POS(ch) = POS_SITTING;
     } else {
       if (!OBJ_FLAGGED(chair, ITEM_SEAT))  {
         send_to_char("You can't sit in that!\r\n", ch);
         return;
       } else if (GET_OBJ_VAL(chair, 1) > GET_OBJ_VAL(chair, 0)) {
         /* val 1 is current number in chair, 0 is max in chair */
         act("$p looks like it's all full.", TRUE, ch, chair, 0, TO_CHAR);
         sprintf(buf, "SYSERR: chair %d holding too many people.", GET_OBJ_VNUM(chair));
         return;
       } else if (GET_OBJ_VAL(chair, 1) == GET_OBJ_VAL(chair, 0)) {
         act("There is nowhere left to sit upon $p.", TRUE, ch, chair, 0, TO_CHAR);
         return;
       } else {
         if (OBJ_SAT_IN_BY(chair) == NULL)
           OBJ_SAT_IN_BY(chair) = ch;

         for (tempch = OBJ_SAT_IN_BY(chair); tempch != ch ; tempch = NEXT_IN_SEAT(tempch)) {
           if (NEXT_IN_SEAT(tempch))
              continue;
           NEXT_IN_SEAT(tempch) = ch;         }

      sprintf(buf, "You sit %s %s.\r\n",
             sit_types[GET_OBJ_VAL(chair, 3)],
             chair->short_description);
	 send_to_char(buf, ch);

  if (IS_NPC(ch)) {
    strcpy(buf, ch->player.short_descr);
    CAP(buf);
  } else
    sprintf(buf, "%s", ch->player.name);

      sprintf(buf + strlen(buf), " sits %s %s.",    
             sit_types[GET_OBJ_VAL(chair, 3)],        
             chair->short_description);
         act(buf, FALSE, ch, 0, 0, TO_ROOM);
         SITTING_IN(ch) = chair;
         NEXT_IN_SEAT(ch) = NULL;
         GET_OBJ_VAL(chair, 1) += 1;
         GET_POS(ch) = POS_SITTING;
     }
    }
    break;
  case POS_SITTING:
    send_to_char("You're sitting already.\r\n", ch);
    break;
  case POS_RESTING:
    send_to_char("You stop resting, and sit up.\r\n", ch);
    act("$n stops resting.", TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_SITTING;
    break;
  case POS_SLEEPING:
    send_to_char("You have to wake up first.\r\n", ch);
    break;
  case POS_FIGHTING:
    send_to_char("Sit down while fighting? Are you MAD?\r\n", ch);
    break;
  case POS_FLYING:
   if (SECT(ch->in_room) == SECT_FLYING) {
    send_to_char("If there were something to sit on, maybe!\r\n", ch);
    break;                                }

    send_to_char("You stop flying about, landing with your rump on the ground.\r\n",ch);
    act("$n stops flying about, and lands with his $s rump on the ground.",
     TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_SITTING;
    break;
 case POS_SWIMMING:
   send_to_char("You are supposed to swim in water, not sit.\r\n", ch);
   break;
  default:
    send_to_char("You stop floating around, and sit down.\r\n", ch);
    act("$n stops floating around, and sits down.", TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_SITTING;
    break;
  }
}


ACMD(do_rest)
{
  struct obj_data *chair = NULL;
  struct char_data *tempch;
  int found;

  if(RIDING(ch))  
    { send_to_char("You can't find a comfortable way to rest while mounted.\r\n", ch); return;}
  else if(RIDDEN_BY(ch) && GET_POS(ch)!=POS_RESTING)
    { send_to_char("It's mighty hard to rest with someone on your back.\r\n", ch); 
return;}
  
  one_argument(argument, arg);

  if (!*arg)
     found = 0;
   else {
  if (!(chair = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents)))
     found = 0;
  else    
     found = 1;
 }

  switch (GET_POS(ch)) {
  case POS_STANDING:
 if (found == 0) {
    send_to_char("You sit down and rest your tired bones.\r\n", ch);
    act("$n sits down and rests.", TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_RESTING;
    } else {
       if (!OBJ_FLAGGED(chair, ITEM_SEAT))  {
         send_to_char("You can't sit in that!\r\n", ch);
         return;
       } else if (GET_OBJ_VAL(chair, 1) > GET_OBJ_VAL(chair, 0)) {
         /* val 1 is current number in chair, 0 is max in chair */
         act("$p looks like it's all full.", TRUE, ch, chair, 0, TO_CHAR);
         sprintf(buf, "SYSERR: chair %d holding too many people.", GET_OBJ_VNUM(chair));
         return;
       } else if (GET_OBJ_VAL(chair, 1) == GET_OBJ_VAL(chair, 0)) {
         act("There is nowhere left to sit upon $p.", TRUE, ch, chair, 0, TO_CHAR);
         return;
       } else {
         if (OBJ_SAT_IN_BY(chair) == NULL)
           OBJ_SAT_IN_BY(chair) = ch;
         for (tempch = OBJ_SAT_IN_BY(chair); tempch != ch ; tempch = NEXT_IN_SEAT(tempch)) {
           if (NEXT_IN_SEAT(tempch))
              continue;
           NEXT_IN_SEAT(tempch) = ch;
         }

      sprintf(buf, "You rest your bones %s %s.\r\n",
             sit_types[GET_OBJ_VAL(chair, 3)],
             chair->short_description);
         send_to_char(buf, ch);

  if (IS_NPC(ch)) {
    strcpy(buf, ch->player.short_descr);
    CAP(buf);
  } else
    sprintf(buf, "%s", ch->player.name);

      sprintf(buf + strlen(buf), " rests %s bones %s %s.",
	     HSHR(ch),
             sit_types[GET_OBJ_VAL(chair, 3)],
             chair->short_description);
         act(buf, FALSE, ch, 0, 0, TO_ROOM);


         SITTING_IN(ch) = chair;
         NEXT_IN_SEAT(ch) = NULL;
         GET_OBJ_VAL(chair, 1)  = 1;
         GET_POS(ch) = POS_RESTING;
     }
    }
    break;
  case POS_SITTING:
    send_to_char("You rest your tired bones.\r\n", ch);
    act("$n rests.", TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_RESTING;
    break;
  case POS_RESTING:
    send_to_char("You are already resting.\r\n", ch);
    break;
  case POS_SLEEPING:
    send_to_char("You have to wake up first.\r\n", ch);
    break;
  case POS_FIGHTING:
    send_to_char("Rest while fighting?  Are you MAD?\r\n", ch);
    break;
 case POS_SWIMMING:
   send_to_char("Calgon take me away...\r\n", ch);
   break;
  default:
    send_to_char("You stop floating around, and stop to rest your tired bones.\r\n", ch);
    act("$n stops floating around, and rests.", FALSE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_SITTING;
    break;
  }
}


ACMD(do_sleep)
{
  if(RIDING(ch)) {
    act("You try to sleep on $N and fall right off.", FALSE, ch, 0, RIDING(ch), TO_CHAR);  
    act("$n tries to sleep and falls right off of you.", FALSE, ch, 0, RIDING(ch), TO_VICT);
    act("$n tries to sleep, but falls right off of $N.", TRUE, ch, 0, RIDING(ch), TO_NOTVICT);
    dismount_char(ch);
    GET_POS(ch) = POS_SITTING;
    return;
  }
  else if(RIDDEN_BY(ch) && GET_POS(ch)!=POS_SLEEPING)
    { send_to_char("It's mighty hard to sleep with someone on your back.\r\n", ch); 
return;}

  switch (GET_POS(ch)) {
  case POS_STANDING:
  case POS_SITTING:
  case POS_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) = POS_SLEEPING;
    break;
  case POS_SLEEPING:
    send_to_char("You are already sound asleep.\r\n", ch);
    break;
  case POS_FIGHTING:
    send_to_char("Sleep while fighting?  Are you MAD?\r\n", ch);
    break;
  case POS_FLYING:
    send_to_char("You stop floating around, and lie down to sleep.\r\n", ch);
    act("$n stops floating around, and lie down to sleep.",
        TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_SLEEPING;
    break;
  case POS_SWIMMING:
    send_to_char("Snoring and water don't quite mix!\r\n", ch);
    break;
  default:
    send_to_char("You stop floating around, and lie down to sleep.\r\n", ch);
    act("$n stops floating around, and lie down to sleep.",
	TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_SLEEPING;
    break;
  }
}


ACMD(do_wake)
{
  struct char_data *vict;
  int self = 0;

  if(RIDING(ch))  
    { send_to_char("It probably wouldn't be wise sleeping while mounted.\r\n", ch); return; }
  else if(RIDDEN_BY(ch)) {
    send_to_char("You wake up to find someone mounted on your back.\r\n", ch);
    send_to_char("It's struggle to sit up, but slowly and painfuly you do.\r\n", ch);
    act("$n awakens with a heavy load on his back.", TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_SITTING;
    return; 
  }

  one_argument(argument, arg);
  if (*arg) {
    if (GET_POS(ch) == POS_SLEEPING)
      send_to_char("Maybe you should wake yourself up first.\r\n", ch);
    else if ((vict = get_char_vis(ch, arg, FIND_CHAR_ROOM)) == NULL)
      send_to_char(NOPERSON, ch);
    else if (vict == ch)
      self = 1;
    else if (AWAKE(vict))
      act("$E is already awake.", FALSE, ch, 0, vict, TO_CHAR);
    else if (AFF_FLAGGED(vict, AFF_SLEEP))
      act("You can't wake $M up!", FALSE, ch, 0, vict, TO_CHAR);
    else if (GET_POS(vict) < POS_SLEEPING)
      act("$E's in pretty bad shape!", FALSE, ch, 0, vict, TO_CHAR);
    else {
      act("You wake $M up.", FALSE, ch, 0, vict, TO_CHAR);
      act("You are awakened by $n.", FALSE, ch, 0, vict, TO_VICT | TO_SLEEP);
      GET_POS(vict) = POS_SITTING;
    }
    if (!self)
      return;
  }
  if (AFF_FLAGGED(ch, AFF_SLEEP))
    send_to_char("You can't wake up!\r\n", ch);
  else if (GET_POS(ch) > POS_SLEEPING)
    send_to_char("You are already awake...\r\n", ch);
  else {
    send_to_char("You awaken, and sit up.\r\n", ch);
    act("$n awakens.", TRUE, ch, 0, 0, TO_ROOM);
    GET_POS(ch) = POS_SITTING;
  }
}


ACMD(do_follow)
{
  struct char_data *leader;

  one_argument(argument, buf);

  if (*buf) {
    if (!(leader = get_char_vis(ch, buf, FIND_CHAR_ROOM))) {
      send_to_char(NOPERSON, ch);
      return;
    }
  } else {
    send_to_char("Whom do you wish to follow?\r\n", ch);

    return;
  }

  if (ch->master == leader) {
    act("You are already following $M.", FALSE, ch, 0, leader, TO_CHAR);
    return;
  }
  if (AFF_FLAGGED(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)) {
	send_to_char("Sorry, but following in loops is not allowed.\r\n", ch);
	return;
      }
      if (ch->master)
	stop_follower(ch);
      REMOVE_BIT(AFF_FLAGS(ch), AFF_GROUP);
      add_follower(ch, leader);
    }
  }
}

ACMD(do_fly) {

  if (GET_POS(ch) == POS_FLYING) {
     send_to_char("You are allready flying about.\r\n", ch);
     return; }

  if (!AFF_FLAGGED(ch, AFF_FLY)) {
     send_to_char("You flap your arms but don't rise an inch.\r\n",ch);
     act("$n flaps his arms like a chicken.", FALSE, ch, 0, 0, TO_ROOM);
     return; }

  if (SITTING_IN(ch))
  char_from_chair(ch);

  GET_POS(ch) = POS_FLYING;
  send_to_char("You rise up into the air with ease.\r\n", ch);
  act("$n rises up into the air.", FALSE, ch, 0, 0, TO_ROOM);
             }

 ACMD(do_mount) {

   char arg[MAX_INPUT_LENGTH];
   struct char_data *vict;

   one_argument(argument, arg);

   if (!arg || !*arg) {
     send_to_char("Mount who?\r\n", ch);
     return;
   } else if (!(vict = get_char_room_vis(ch, arg))) {
     send_to_char("There is no-one by that name here.\r\n", ch);
     return;
   } else if (ch == vict) {
     send_to_char("Don't hurt yourself!\r\n", ch);
     return;
   } else if (!IS_NPC(vict) && GET_LEVEL(ch) < LVL_IMMORT) {
     send_to_char("That's not gonna happen- sorry bud.\r\n", ch);
     return;
   } else if (RIDING(ch) || RIDDEN_BY(ch)) {
     send_to_char("You are already mounted.\r\n", ch);
     return;
   } else if (RIDING(vict) || RIDDEN_BY(vict)) {
     send_to_char("It is already mounted.\r\n", ch);
     return;
   } else if (GET_LEVEL(ch) < LVL_IMMORT && IS_NPC(vict) && !MOB_FLAGGED(vict, MOB_MOUNTABLE)) {
     send_to_char("You can't mount that!\r\n", ch);
     return;
   } else if (!IS_NPC(ch) && (!GET_SKILL(ch, SKILL_RIDING))) {
     send_to_char("First you need to learn *how* to mount.\r\n", ch);
     return;
   } else if (!IS_NPC(ch) && (GET_SKILL(ch, SKILL_RIDING) <= number(1, 101))) {
     act("You try to mount $N, but slip and fall off.", FALSE, ch, 0, vict, TO_CHAR);
     act("$n tries to mount you, but slips and falls off.", FALSE, ch, 0, vict, TO_VICT);
     act("$n tries to mount $N, but slips and falls off.", TRUE, ch, 0, vict, TO_NOTVICT);
     damage(ch, ch, dice(1, 2), -1);
     return;
   }

   act("You mount $N.", FALSE, ch, 0, vict, TO_CHAR);
   act("$n mounts you.", FALSE, ch, 0, vict, TO_VICT);
   act("$n mounts $N.", TRUE, ch, 0, vict, TO_NOTVICT);
   mount_char(ch, vict);
   GET_POS(ch) = POS_SITTING;
}

 ACMD(do_dismount) {
   if (!RIDING(ch)) {
     send_to_char("You aren't even riding anything.\r\n", ch);
     return;
   }
     
   act("You dismount $N.", FALSE, ch, 0, RIDING(ch), TO_CHAR);
   act("$n dismounts from you.", FALSE, ch, 0, RIDING(ch), TO_VICT);
   act("$n dismounts $N.", TRUE, ch, 0, RIDING(ch), TO_NOTVICT);
   dismount_char(ch);
   GET_POS(ch) = POS_STANDING; 
 }

ACMD(do_board)
{
  struct obj_data *chair = NULL;
  struct char_data *tempch;
  int found; 
       
  if(RIDING(ch))
    { send_to_char("Take your mount on a boat? HAH!\r\n", ch); return;}
  else if(RIDDEN_BY(ch) && GET_POS(ch)!=POS_SITTING)
    { send_to_char("It's mighty hard to board anything with someone on your back.\r\n", ch);
return;}
         
  one_argument(argument, arg);
       
  if (!*arg)
     found = 0; 
  if (!(chair = get_obj_in_list_vis(ch, arg, world[ch->in_room].contents)))
     found = 0;
  else {
     found = 1;
  }

  switch (GET_POS(ch)) {
  case POS_STANDING:
  case POS_SWIMMING:
     if (found == 0 ) {
      send_to_char("I don't see that here...\r\n", ch);
     } else {
       if (!GET_OBJ_TYPE(chair) == ITEM_BOAT)  {
         send_to_char("That's not a boat!\r\n", ch);
         return;
       } else if (!OBJ_FLAGGED(chair, ITEM_SEAT))  {
         send_to_char("You can't board that!\r\n", ch);
         return;
       } else if (GET_OBJ_VAL(chair, 1) > GET_OBJ_VAL(chair, 0)) {
         /* val 1 is current number in chair, 0 is max in chair */
         act("$p looks like it's all full.", TRUE, ch, chair, 0, TO_CHAR);
         sprintf(buf, "SYSERR: chair %d holding too many people.", GET_OBJ_VNUM(chair));
         return;
       } else if (GET_OBJ_VAL(chair, 1) == GET_OBJ_VAL(chair, 0)) {
         act("There is no room to board $p.", TRUE, ch, chair, 0, TO_CHAR);
         return;
       } else {
         if (OBJ_SAT_IN_BY(chair) == NULL)
           OBJ_SAT_IN_BY(chair) = ch;
         
         for (tempch = OBJ_SAT_IN_BY(chair); tempch != ch ; tempch = NEXT_IN_SEAT(tempch)) {
           if (NEXT_IN_SEAT(tempch))
              continue;
           NEXT_IN_SEAT(tempch) = ch;         }
  
      sprintf(buf, "You board %s.\r\n", chair->short_description);
         send_to_char(buf, ch);
  
  if (IS_NPC(ch)) {
    strcpy(buf, ch->player.short_descr);
    CAP(buf);
  } else
    sprintf(buf, "%s", ch->player.name);
  
      sprintf(buf + strlen(buf), " boards %s.", chair->short_description);
         act(buf, FALSE, ch, 0, 0, TO_ROOM);
         SITTING_IN(ch) = chair;
         NEXT_IN_SEAT(ch) = NULL;
         GET_OBJ_VAL(chair, 1) += 1;
         GET_POS(ch) = POS_SITTING;
     }
    }
    break;
  case POS_SITTING:
  case POS_RESTING:
    send_to_char("You're gonna have to stand up to do this.\r\n", ch);
    break;
  case POS_SLEEPING:
    send_to_char("You have to wake up first.\r\n", ch);
    break;
  case POS_FIGHTING:
    send_to_char("Sit down and board a vessel while fighting? Are you MAD?\r\n", ch);
    break;
  default:
    send_to_char("You better get your feet on the ground or your body in the water first!\r\n", ch);
    break;
  }
}