ur/
ur/boards/
ur/clans/
ur/councils/
ur/homes/
ur/planets/
/***************************************************************************
*                           STAR WARS REALITY 1.0                          *
*--------------------------------------------------------------------------*
* Star Wars Reality Code Additions and changes from the Smaug Code         *
* copyright (c) 1997 by Sean Cooper                                        *
* -------------------------------------------------------------------------*
* Starwars and Starwars Names copyright(c) Lucas Film Ltd.                 *
*--------------------------------------------------------------------------*
* SMAUG 1.0 (C) 1994, 1995, 1996 by Derek Snider                           *
* SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,                    *
* Scryn, Rennard, Swordbearer, Gorog, Grishnakh and Tricops                *
* ------------------------------------------------------------------------ *
* Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
* Chastain, Michael Quan, and Mitchell Tse.                                *
* Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
* Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.     *
* ------------------------------------------------------------------------ *
*			   Player movement module			   *
****************************************************************************/


#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include "mud.h"



const	sh_int	movement_loss	[SECT_MAX]	=
{
    1, 2, 2, 3, 4, 6, 4, 1, 6, 10, 6, 5, 7, 4
};

char *	const	dir_name	[]		=
{
    "north", "east", "south", "west", "up", "down",
    "northeast", "northwest", "southeast", "southwest", "somewhere"
};

const	sh_int	rev_dir		[]		=
{
    2, 3, 0, 1, 5, 4, 9, 8, 7, 6, 10
};


ROOM_INDEX_DATA * vroom_hash [64];

/*
 * Local functions.
 */
OBJ_DATA	*has_key	args( ( CHAR_DATA *ch, int key ) );


char *	const		sect_names[SECT_MAX][2] =
{
    { "In a room","inside"	},	{ "In a city",	"cities"	},
    { "In a field","fields"	},	{ "In a forest","forests"	},
    { "hill",	"hills"		},	{ "On a mountain","mountains"	},
    { "In the water","waters"	},	{ "In rough water","waters"	},
    { "Underwater", "underwaters" },	{ "In the air",	"air"		},
    { "In a desert","deserts"	},	{ "Somewhere",	"unknown"	},
    { "ocean floor", "ocean floor" },	{ "underground", "underground"	}
};


const	int		sent_total[SECT_MAX]		=
{
    3, 5, 4, 4, 1, 1, 1, 1, 1, 2, 2, 25, 1, 1
};

char *	const		room_sents[SECT_MAX][25]	=
{
    {
	"rough hewn walls of granite with the occasional spider crawling around",
	"signs of a recent battle from the bloodstains on the floor",
	"a damp musty odour not unlike rotting vegetation"
    },

    {
	"the occasional stray digging through some garbage",
	"merchants trying to lure customers to their tents",
	"some street people putting on an interesting display of talent",
	"an argument between a customer and a merchant about the price of an item",
	"several shady figures talking down a dark alleyway"
    },

    {
	"sparce patches of brush and shrubs",
	"a small cluster of trees far off in the distance",
	"grassy fields as far as the eye can see",
	"a wide variety of weeds and wildflowers"
    },

    {
	"tall, dark evergreens prevent you from seeing very far",
	"many huge oak trees that look several hundred years old",
	"a solitary lonely weeping willow",
	"a patch of bright white birch trees slender and tall"
    },

    {
	"rolling hills lightly speckled with violet wildflowers"
    },

    {
	"the rocky mountain pass offers many hiding places"
    },

    {
	"the water is smooth as glass"
    },

    {
	"rough waves splash about angrily"
    },

    {
	"a small school of fish"
    },

    {
	"the land far below",
	"a misty haze of clouds"
    },

    {
	"sand as far as the eye can see",
	"an oasis far in the distance"
    },

    {
	"nothing unusual",	"nothing unusual",	"nothing unusual",
	"nothing unusual",	"nothing unusual",	"nothing unusual",
	"nothing unusual",	"nothing unusual",	"nothing unusual",
	"nothing unusual",	"nothing unusual",	"nothing unusual",
	"nothing unusual",	"nothing unusual",	"nothing unusual",
	"nothing unusual",	"nothing unusual",	"nothing unusual",
	"nothing unusual",	"nothing unusual",	"nothing unusual",
	"nothing unusual",	"nothing unusual",	"nothing unusual",
	"nothing unusual",
    },

    { 
        "rocks and coral which litter the ocean floor."
    },

    {
	"a lengthy tunnel of rock."
    }

};


int wherehome( CHAR_DATA *ch)
{
    if( ch->pcdata->plr_home )
      return ch->pcdata->plr_home->vnum;

    if( get_trust(ch) >= LEVEL_IMMORTAL )
       return ROOM_START_IMMORTAL;
       
    return ROOM_VNUM_TEMPLE;   
}

char *grab_word( char *argument, char *arg_first )
{
    char cEnd;
    sh_int count;

    count = 0;

    while ( isspace(*argument) )
	argument++;

    cEnd = ' ';
    if ( *argument == '\'' || *argument == '"' )
	cEnd = *argument++;

    while ( *argument != '\0' || ++count >= 255 )
    {
	if ( *argument == cEnd )
	{
	    argument++;
	    break;
	}
	*arg_first++ = *argument++;
    }
    *arg_first = '\0';

    while ( isspace(*argument) )
	argument++;

    return argument;
}

char *wordwrap( char *txt, sh_int wrap )
{
    static char buf[MAX_STRING_LENGTH];
    char *bufp;

    buf[0] = '\0';
    bufp = buf;
    if ( txt != NULL )
    {
        char line[MAX_STRING_LENGTH];
        char temp[MAX_STRING_LENGTH];
        char *ptr, *p;
        int ln, x;

	++bufp;
        line[0] = '\0';
        ptr = txt;
        while ( *ptr )
        {
	  ptr = grab_word( ptr, temp );
          ln = strlen( line );  x = strlen( temp );
          if ( (ln + x + 1) < wrap )
          {
	    if ( line[ln-1] == '.' )
              strcat( line, "  " );
	    else
              strcat( line, " " );
            strcat( line, temp );
            p = strchr( line, '\n' );
            if ( !p )
              p = strchr( line, '\r' );
            if ( p )
            {
                strcat( buf, line );
                line[0] = '\0';
            }
          }
          else
          {
            strcat( line, "\r\n" );
            strcat( buf, line );
            strcpy( line, temp );
          }
        }
        if ( line[0] != '\0' )
            strcat( buf, line );
    }
    return bufp;
}

void decorate_room( ROOM_INDEX_DATA *room )
{
    char buf[MAX_STRING_LENGTH];
    char buf2[MAX_STRING_LENGTH];
    int nRand;
    int iRand, len;
    int previous[8];
    int sector = room->sector_type;

    if ( room->name )
      STRFREE( room->name );
    if ( room->description )
      STRFREE( room->description );

    room->name	= STRALLOC( sect_names[sector][0] );
    buf[0] = '\0';
    nRand = number_range( 1, UMIN(8,sent_total[sector]) );

    for ( iRand = 0; iRand < nRand; iRand++ )
	previous[iRand] = -1;

    for ( iRand = 0; iRand < nRand; iRand++ )
    {
	while ( previous[iRand] == -1 )
	{
	    int x, z;

	    x = number_range( 0, sent_total[sector]-1 );

	    for ( z = 0; z < iRand; z++ )
		if ( previous[z] == x )
		  break;

	    if ( z < iRand )
		  continue;

	    previous[iRand] = x;

	    len = strlen(buf);
	    sprintf( buf2, "%s", room_sents[sector][x] );
	    if ( len > 5 && buf[len-1] == '.' )
	    {
		strcat( buf, "  " );
		buf2[0] = UPPER(buf2[0] );
	    }
	    else
	    if ( len == 0 )
	        buf2[0] = UPPER(buf2[0] );
	    strcat( buf, buf2 );
	}
    }
    sprintf( buf2, "%s\n\r", wordwrap(buf, 78) );
    room->description = STRALLOC( buf2 );
}

/*
 * Remove any unused virtual rooms				-Thoric
 */
void clear_vrooms( )
{
    int hash;
    ROOM_INDEX_DATA *room, *room_next, *prev;

    for ( hash = 0; hash < 64; hash++ )
    {
	while ( vroom_hash[hash]
	&&     !vroom_hash[hash]->first_person
	&&     !vroom_hash[hash]->first_content )
	{
	    room = vroom_hash[hash];
	    vroom_hash[hash] = room->next;
	    clean_room( room );
	    DISPOSE( room );
	    --top_vroom;
	}
	prev = NULL;
	for ( room = vroom_hash[hash]; room; room = room_next )
	{
	    room_next = room->next;
	    if ( !room->first_person && !room->first_content )
	    {
		if ( prev )
		  prev->next = room_next;
		clean_room( room );
		DISPOSE( room );
		--top_vroom;
	    }
	    if ( room )
	      prev = room;
	}
    }
}

char *rev_exit( sh_int vdir )
{
    switch( vdir )
    {
	default: return "somewhere";
	case 0:  return "the south";
	case 1:  return "the west";
	case 2:  return "the north";
	case 3:  return "the east";
	case 4:  return "below";
	case 5:  return "above";
	case 6:  return "the southwest";
	case 7:  return "the southeast";
	case 8:  return "the northwest";
	case 9:  return "the northeast";
    }

    return "<\?\?\?>";
}

/*
 * Function to get the equivelant exit of DIR 0-MAXDIR out of linked list.
 * Made to allow old-style diku-merc exit functions to work.	-Thoric
 */
EXIT_DATA *get_exit( ROOM_INDEX_DATA *room, sh_int dir )
{
    EXIT_DATA *xit;

    if ( !room )
    {
	bug( "Get_exit: NULL room", 0 );
	return NULL;
    }

    for (xit = room->first_exit; xit; xit = xit->next )
       if ( xit->vdir == dir )
         return xit;
    return NULL;
}

/*
 * Function to get an exit, leading the the specified room
 */
EXIT_DATA *get_exit_to( ROOM_INDEX_DATA *room, sh_int dir, int vnum )
{
    EXIT_DATA *xit;

    if ( !room )
    {
	bug( "Get_exit: NULL room", 0 );
	return NULL;
    }

    for (xit = room->first_exit; xit; xit = xit->next )
       if ( xit->vdir == dir && xit->vnum == vnum )
         return xit;
    return NULL;
}

/*
 * Function to get the nth exit of a room			-Thoric
 */
EXIT_DATA *get_exit_num( ROOM_INDEX_DATA *room, sh_int count )
{
    EXIT_DATA *xit;
    int cnt;

    if ( !room )
    {
	bug( "Get_exit: NULL room", 0 );
	return NULL;
    }

    for (cnt = 0, xit = room->first_exit; xit; xit = xit->next )
       if ( ++cnt == count )
         return xit;
    return NULL;
}


/*
 * Modify movement due to encumbrance				-Thoric
 */
sh_int encumbrance( CHAR_DATA *ch, sh_int move )
{
    int cur, max;

    max = can_carry_w(ch);
    cur = ch->carry_weight;
    if ( cur >= max )
      return move * 4;
    else
    if ( cur >= max * 0.95 )
      return move * 3.5;
    else
    if ( cur >= max * 0.90 )
      return move * 3;
    else
    if ( cur >= max * 0.85 )
      return move * 2.5;
    else
    if ( cur >= max * 0.80 )
      return move * 2;
    else
    if ( cur >= max * 0.75 )
      return move * 1.5;
    else
      return move;
}


/*
 * Check to see if a character can fall down, checks for looping   -Thoric
 */
bool will_fall( CHAR_DATA *ch, int fall )
{
    if ( xIS_SET( ch->in_room->room_flags, ROOM_NOFLOOR )
    &&   CAN_GO(ch, DIR_DOWN)
    && (!IS_AFFECTED( ch, AFF_FLYING )
    || ( ch->mount && !IS_AFFECTED( ch->mount, AFF_FLYING ) ) ) )
    {
	if ( fall > 80 )
	{
	   bug( "Falling (in a loop?) more than 80 rooms: vnum %d", ch->in_room->vnum );
	   char_from_room( ch );
	   char_to_room( ch, get_room_index( wherehome(ch) ) );
	   fall = 0;
	   return TRUE;
	}
	set_char_color( AT_FALLING, ch );
	send_to_char( "You're falling down...\n\r", ch );
	move_char( ch, get_exit(ch->in_room, DIR_DOWN), ++fall );
	return TRUE;
    }
    return FALSE;
}


/*
 * create a 'virtual' room					-Thoric
 */
ROOM_INDEX_DATA *generate_exit( ROOM_INDEX_DATA *in_room, EXIT_DATA **pexit )
{
    EXIT_DATA *xit, *bxit;
    EXIT_DATA *orig_exit = (EXIT_DATA *) *pexit;
    ROOM_INDEX_DATA *room, *backroom;
    int brvnum;
    int serial;
    int roomnum;
    int distance = -1;
    int vdir = orig_exit->vdir;
    sh_int hash;

/*    if ( in_room->vnum == -1)*/	/* room is virtual */
	if ( in_room->vnum > MAX_VNUMS )   /* room is virtual */    
    {
		serial = in_room->vnum;
		roomnum = 0;
		if ( (serial & MAX_VNUMS) == orig_exit->vnum )
		{
			brvnum = serial >> 16;
			--roomnum;
			distance = roomnum;
		}
		else
		{
			brvnum = serial & MAX_VNUMS;
			++roomnum;
			distance = orig_exit->distance - 1;
		}
		backroom = get_room_index( brvnum );
	}
    else
    {
	int r1 = in_room->vnum;
	int r2 = orig_exit->vnum;

	brvnum = r1;
	backroom = in_room;
	serial = (UMAX( r1, r2 ) << 16) | UMIN( r1, r2 );
	distance = orig_exit->distance - 1;
	roomnum = r1 < r2 ? 1 : distance;
    }
    hash = serial % 64;
    
    if ( (xit=get_exit(room, vdir))==NULL )
    {
	xit = make_exit(room, orig_exit->to_room, vdir);
	xit->keyword		= STRALLOC( "" );
	xit->description	= STRALLOC( "" );
	xit->key		= -1;
	xit->distance = distance;
    }
    {
	bxit = make_exit(room, backroom, rev_dir[vdir]);
	bxit->keyword		= STRALLOC( "" );
	bxit->description	= STRALLOC( "" );
	bxit->key		= -1;
	if ( (serial & MAX_VNUMS) != orig_exit->vnum )
		bxit->distance = roomnum;
	else
	{
	  EXIT_DATA *tmp = get_exit( backroom, vdir );
	  int fulldist = tmp->distance;
	  
	  bxit->distance = fulldist - distance;
	}
    }
    (EXIT_DATA *) pexit = xit;
    return room;
}
/* return rNONE replaced with return rSTOP - 01/21/01 by Drraagh */
ch_ret move_char( CHAR_DATA *ch, EXIT_DATA *pexit, int fall )
{
    ROOM_INDEX_DATA *in_room;
    ROOM_INDEX_DATA *to_room;
    ROOM_INDEX_DATA *from_room;
    char buf[MAX_STRING_LENGTH];
    char *txt;
    char *dtxt;
    ch_ret retcode;
    sh_int door, distance;
    bool drunk = FALSE;
	bool nuisance = FALSE;
    bool brief = FALSE;

    if ( !IS_NPC( ch ) )
    {
		if ( IS_DRUNK( ch, 2 ) && ( ch->position != POS_SHOVE )
			&& ( ch->position != POS_DRAG ) && ( ch->position != POS_CARRIED ) )
			drunk = TRUE;

	/* Nuisance flag, makes them walk in random directions 50% of the time
	 * -Shaddai
	 */
		if ( ch->pcdata->nuisance && ch->pcdata->nuisance->flags > 8 
			&& ( ch->position != POS_SHOVE ) && ( ch->position != POS_DRAG ) 
			&& ( ch->position != POS_CARRIED ) 
			&& number_percent() > (ch->pcdata->nuisance->flags*ch->pcdata->nuisance->power))
			nuisance = TRUE;
    }

    if ( (nuisance || drunk) && !fall )
    {
		door = number_door();
		pexit = get_exit( ch->in_room, door );
    }

#ifdef DEBUG
    if ( pexit )
    {
		sprintf( buf, "move_char: %s to door %d", ch->name, pexit->vdir );
		log_string( buf );
    }
#endif

    retcode = rNONE;
    txt = NULL;

    if ( IS_NPC(ch) && IS_SET( ch->act, ACT_MOUNTED ) )
		return retcode;

	if ( !IS_NPC(ch) && !fall && ch->pcdata->birth_wait > 0 && ch->position != POS_CARRIED )
	{
		act(AT_ACTION, "You try and move, but relise that your giving birth.", ch, NULL, NULL, TO_CHAR );
		act(AT_ACTION, "$n tries to move, but suddenly stops.", ch, NULL, NULL, TO_ROOM );
		return rSTOP;
	}

    in_room = ch->in_room;
    from_room = in_room;
	if ( !pexit || (to_room = pexit->to_room) == NULL )
    {
		if ( drunk && ch->position != POS_MOUNTED
			&&   ch->in_room->sector_type != SECT_WATER_SWIM
			&&   ch->in_room->sector_type != SECT_WATER_NOSWIM
			&&   ch->in_room->sector_type != SECT_UNDERWATER
			&&   ch->in_room->sector_type != SECT_OCEANFLOOR )
		{
			switch ( number_bits( 4 ) )
			{
			default:
				act( AT_ACTION, "You drunkenly stumble into some obstacle.", ch, NULL, NULL, TO_CHAR );
				act( AT_ACTION, "$g drunkenly stumbles into a nearby obstacle.", ch, NULL, NULL, TO_ROOM );
				break;
			case 3:
				act( AT_ACTION, "In your drunken stupor you trip over your own feet and tumble to the ground.", ch, NULL, NULL, TO_CHAR );
				act( AT_ACTION, "$g stumbles drunkenly, trips and tumbles to the ground.", ch, NULL, NULL, TO_ROOM );
				ch->position = POS_RESTING;
				if ( number_percent() > 50 && !IS_IMMORTAL(ch) )
				{
					if ( !IS_NPC(ch) && !IS_SET( ch->pcdata->cyber, CYBER_LEGS ) )
					{
						if ( !xIS_SET(ch->bodyparts,BODY_L_LEG ) )
							xSET_BIT(ch->bodyparts, BODY_L_LEG);
						else if ( !xIS_SET(ch->bodyparts,BODY_R_LEG) )
							xSET_BIT(ch->bodyparts, BODY_R_LEG);
					}
				}
				break;
			case 4:
				act( AT_SOCIAL, "You utter a string of slurred obscenities.", ch, NULL, NULL, TO_CHAR) ;
				act( AT_ACTION, "Something blurry and immovable has intercepted you as you stagger along.", ch, NULL, NULL, TO_CHAR );
				act( AT_HURT, "Oh geez... THAT really hurt.  Everything slowly goes dark and numb...", ch, NULL, NULL, TO_CHAR );
				act( AT_ACTION, "$g drunkenly staggers into something.", ch, NULL, NULL, TO_ROOM );
				act( AT_SOCIAL, "$g utters a string of slurred obscenities: @*&^%@*&!", ch, NULL, NULL, TO_ROOM );
				act( AT_ACTION, "$g topples to the ground with a thud.", ch, NULL, NULL, TO_ROOM );
				ch->position = POS_INCAP;
				if ( number_percent() > 50 && !IS_IMMORTAL(ch) )
				{
					if ( !IS_NPC(ch) && !IS_SET( ch->pcdata->cyber, CYBER_LEGS ) )
					{
						if ( !xIS_SET(ch->bodyparts,BODY_L_LEG ) )
							xSET_BIT(ch->bodyparts, BODY_L_LEG);
						else if ( !xIS_SET(ch->bodyparts,BODY_R_LEG) )
							xSET_BIT(ch->bodyparts, BODY_R_LEG);
					}
				}
				break;
			}
		}
		else if ( nuisance )
			act( AT_ACTION, "You stare around trying to remember where you where going.", ch, NULL, NULL, TO_CHAR );
		else if ( drunk )
			act( AT_ACTION, "You stare around trying to make sense of things through your drunken stupor.", ch, NULL, NULL, TO_CHAR );
        else
			send_to_char( "Alas, you cannot go that way.\n\r", ch );
		return rSTOP;
    }

    door = pexit->vdir;
    distance = pexit->distance;

    /*
	 * Exit is only a "window", there is no way to travel in that direction
     * unless it's a door with a window in it		-Thoric
	 */
    if ( IS_SET( pexit->exit_info, EX_WINDOW )
		&&  !IS_SET( pexit->exit_info, EX_ISDOOR ) )
    {
		send_to_char( "Alas, you cannot go that way.\n\r", ch );
		return rSTOP;
    }

    if (  IS_SET(pexit->exit_info, EX_PORTAL) 
       && IS_NPC(ch) )
    {
        act( AT_PLAIN, "Mobs can't use portals.", ch, NULL, NULL, TO_CHAR );
	return rSTOP;
    }

    if ( IS_SET(pexit->exit_info, EX_NOMOB)
	&& IS_NPC(ch) )
    {
	act( AT_PLAIN, "Mobs can't enter there.", ch, NULL, NULL, TO_CHAR );
	return rSTOP;
    }

    if ( IS_SET(pexit->exit_info, EX_CLOSED)
    && (!IS_AFFECTED(ch, AFF_PASS_DOOR)
    ||   IS_SET(pexit->exit_info, EX_NOPASSDOOR)) )
    {
	if ( !IS_SET( pexit->exit_info, EX_SECRET )
	&&   !IS_SET( pexit->exit_info, EX_DIG ) )
	{
	  if ( drunk )
	  {
	    act( AT_PLAIN, "$g runs into the $d in $s drunken state.", ch,
		NULL, pexit->keyword, TO_ROOM );
	    act( AT_PLAIN, "You run into the $d in your drunken state.", ch,
		NULL, pexit->keyword, TO_CHAR ); 
	  }
	 else
	  act( AT_PLAIN, "The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR );
	}
       else
	{
	  if ( drunk )
	    send_to_char( "You hit a wall in your drunken state.\n\r", ch );
	   else
	    send_to_char( "Alas, you cannot go that way.\n\r", ch );
	}

	return rSTOP;
    }

/*
     * Crazy virtual room idea, created upon demand.		-Thoric
     */
    if ( distance > 1 )
	if ( (to_room=generate_exit(in_room, &pexit)) == NULL )
	    send_to_char( "Alas, you cannot go that way.\n\r", ch );

    if ( !fall
    &&   IS_AFFECTED(ch, AFF_CHARM)
    &&   ch->master
    &&   in_room == ch->master->in_room )
    {
	send_to_char( "What?  And leave your beloved master?\n\r", ch );
	return rSTOP;
    }

	if ( !fall 
		&& ch->position == POS_CARRIED 
		&& ch->char_carriedby 
		&& in_room == ch->char_carriedby->in_room )
    {
		return rSTOP;
    }
	if ( !IS_NPC(ch) && !fall && ch->pcdata->birth_wait > 0 && ch->position != POS_CARRIED )
		return rSTOP;


/*    if ( room_is_private( ch,to_room ) )*/
	if ( room_is_private( ch,to_room ) && get_trust( ch ) < sysdata.level_override_private )
    {
	send_to_char( "That room is private right now.\n\r", ch );
	return rSTOP;
    }

    if ( room_is_dnd(ch, to_room) )
    {
	send_to_char( "That room is \"do not disturb\" right now.\n\r", ch );
	return rSTOP;
    }

    if ( !IS_IMMORTAL(ch)
    &&  !IS_NPC(ch)
    &&  ch->in_room->area != to_room->area )
    {
	if ( ch->top_level < to_room->area->low_hard_range )
	{
	    set_char_color( AT_TELL, ch );
	    switch( to_room->area->low_hard_range - ch->top_level )
	    {
		case 1:
		  send_to_char( "A voice in your mind says, 'You are nearly ready to go that way...'", ch );
		  break;
		case 2:
		  send_to_char( "A voice in your mind says, 'Soon you shall be ready to travel down this path... soon.'", ch );
		  break;
		case 3:
		  send_to_char( "A voice in your mind says, 'You are not ready to go down that path... yet.'.\n\r", ch);
		  break;
		default:
		  send_to_char( "A voice in your mind says, 'You are not ready to go down that path.'.\n\r", ch);
	    }
	    return rSTOP;
	}
	else
	if ( ch->top_level > to_room->area->hi_hard_range )
	{
	    set_char_color( AT_TELL, ch );
	    send_to_char( "A voice in your mind says, 'There is nothing more for you down that path.'", ch );
	    return rSTOP;
	}          
    }

    if ( !fall && !IS_NPC(ch) )
    {
	int move;

	if ( in_room->sector_type == SECT_AIR
	||   to_room->sector_type == SECT_AIR
	||   IS_SET( pexit->exit_info, EX_FLY ) )
	{
	    if ( ch->mount && !IS_AFFECTED( ch->mount, AFF_FLYING ) )
	    {
		send_to_char( "Your mount can't fly.\n\r", ch );
		return rSTOP;
	    }
	    if ( !ch->mount && !IS_AFFECTED(ch, AFF_FLYING) )
	    {
		send_to_char( "You'd need to fly to go there.\n\r", ch );
		return rSTOP;
	    }
	}

	if ( in_room->sector_type == SECT_WATER_NOSWIM
	||   to_room->sector_type == SECT_WATER_NOSWIM )
	{
	    if ( (ch->mount && !IS_FLOATING(ch->mount)) || !IS_FLOATING(ch) )
	    {
		/*
		 * Look for a boat.
		 * We can use the boat obj for a more detailed description.
		 */
		{
		    if ( ch->mount )
			send_to_char( "Your mount would drown!\n\r", ch );
		    else
			send_to_char( "You'd need a boat to go there.\n\r", ch );
		    return rSTOP;
		}
	    }
	}

	if ( IS_SET( pexit->exit_info, EX_CLIMB ) )
	{
	    bool found;

	    found = FALSE;
	    if ( ch->mount && IS_AFFECTED( ch->mount, AFF_FLYING ) )
	      found = TRUE;
	    else
	    if ( IS_AFFECTED(ch, AFF_FLYING) )
	      found = TRUE;

	    if ( !found && !ch->mount )
	    {
		if ( ( !IS_NPC(ch) && number_percent( ) > ch->pcdata->learned[gsn_climb] )
		||      drunk || ch->mental_state < -90 )
		{
			send_to_char( "You start to climb... but lose your grip and fall!\n\r", ch);
			learn_from_failure( ch, gsn_climb );
			if ( pexit->vdir == DIR_DOWN )
			{
				retcode = move_char( ch, pexit, 1 );
				return retcode;
			}
			if ( number_percent() > 50 && !IS_IMMORTAL(ch) )
			{
				if ( !IS_NPC(ch) && !IS_SET( ch->pcdata->cyber, CYBER_LEGS ) )
				{
					if ( !xIS_SET(ch->bodyparts,BODY_L_LEG ) )
						xSET_BIT(ch->bodyparts, BODY_L_LEG);
					else if ( !xIS_SET(ch->bodyparts,BODY_R_LEG) )
						xSET_BIT(ch->bodyparts, BODY_R_LEG);
				}
			}
			set_char_color( AT_HURT, ch );
			send_to_char( "OUCH! You hit the ground!\n\r", ch );
			WAIT_STATE( ch, 20 );
			retcode = damage( ch, ch, (pexit->vdir == DIR_UP ? 10 : 5), TYPE_UNDEFINED );
			return retcode;
		}
		found = TRUE;
		learn_from_success( ch, gsn_climb );
		WAIT_STATE( ch, skill_table[gsn_climb]->beats );
		txt = "climbs";
	    }

	    if ( !found )
	    {
		send_to_char( "You can't climb.\n\r", ch );
		return rSTOP;
	    }
	}

	if ( ch->mount )
	{
		switch (ch->mount->position)
		{
			case POS_DEAD:
				send_to_char( "Your mount is dead!\n\r", ch );
				return rSTOP;
			break;
			
            case POS_MORTAL:
			case POS_INCAP:
				send_to_char( "Your mount is hurt far too badly to move.\n\r", ch );
				return rSTOP;
			break;
            
            case POS_STUNNED:
				send_to_char( "Your mount is too stunned to do that.\n\r", ch );
				return rSTOP;
            break;
       
            case POS_SLEEPING:
				send_to_char( "Your mount is sleeping.\n\r", ch );
				return rSTOP;
            break;
         
            case POS_RESTING:
				send_to_char( "Your mount is resting.\n\r", ch);
				return rSTOP;
            break;
        
            case POS_SITTING:
				send_to_char( "Your mount is sitting down.\n\r", ch);
				return rSTOP;
            break;

			case POS_CARRIED:
				send_to_char( "Your mount is being carried.\n\r", ch);
				return rSTOP;
            break;



	    default:
	    break;
  	  }

	  	  if ( !IS_FLOATING(ch->mount) )
	    move = movement_loss[UMIN(SECT_MAX-1, in_room->sector_type)];
	  else
	    move = 1;
	  if ( ch->mount->move < move )
	  {
	    send_to_char( "Your mount is too exhausted.\n\r", ch );
	    return rSTOP;
	  }
	}
	else
	{
	  if ( !IS_FLOATING(ch) )
	    move = encumbrance( ch, movement_loss[UMIN(SECT_MAX-1, in_room->sector_type)] );
	  else
	    move = 1;
	  if ( ch->move < move )
	  {
	    send_to_char( "You are too exhausted.\n\r", ch );
	    return rSTOP;
	  }
	}

	WAIT_STATE( ch, move );
	if ( ch->char_carriedby == NULL )
	{
		if ( ch->mount )
			ch->mount->move -= move;
		else
		{
			ch->move -= move;
			if ( !IS_NPC(ch) && IS_SET(ch->act2, EXTRA_PREGNANT) )
				ch->move -= move;
			if ( !IS_NPC(ch) && IS_SET(ch->act2, EXTRA_LABOUR) )
				ch->move -= move;
			if ( xIS_SET(ch->bodyparts,BODY_R_LEG) && !xIS_SET(ch->bodyparts,BODY_L_LEG) )
				ch->move -= (10*move);
			if ( xIS_SET(ch->bodyparts,BODY_L_LEG) && !xIS_SET(ch->bodyparts,BODY_R_LEG) )
				ch->move -= (10*move);
			if ( xIS_SET(ch->bodyparts,BODY_L_LEG) && xIS_SET(ch->bodyparts,BODY_R_LEG) )
				ch->move = 0;
		}
	}
    }

    /*
     * Check if player can fit in the room
     */
    if ( to_room->tunnel > 0 )
    {
	CHAR_DATA *ctmp;
	int count = ch->mount ? 1 : 0;
	
	for ( ctmp = to_room->first_person; ctmp; ctmp = ctmp->next_in_room )
	  if ( ++count >= to_room->tunnel )
	  {
		if ( ch->mount && count == to_room->tunnel )
		  send_to_char( "There is no room for both you and your mount in there.\n\r", ch );
		else
		  send_to_char( "There is no room for you in there.\n\r", ch );
		return rSTOP;
	  }
    }

    /* check for traps on exit - later */

    if ( !IS_AFFECTED(ch, AFF_SNEAK)
    && ( IS_NPC(ch) || !IS_SET(ch->act, PLR_WIZINVIS) )
	&& ( ch->position != POS_CARRIED ))
    {
      if ( fall )
        txt = "falls";
      else
      if ( !txt )
      {
        if ( ch->mount )
        {
	  if ( IS_AFFECTED( ch->mount, AFF_FLOATING ) )
	    txt = "floats";
 	  else
	  if ( IS_AFFECTED( ch->mount, AFF_FLYING ) )
	    txt = "flys";
	  else
	    txt = "rides";
        }
        else
        {
	  if ( IS_AFFECTED( ch, AFF_FLOATING ) )
	  {
	    if ( drunk )
	      txt = "floats unsteadily";
	     else
	      txt = "floats";
	  }
	  else
	  if ( IS_AFFECTED( ch, AFF_FLYING ) )
	  {
	    if ( drunk )
	      txt = "flys shakily";
	     else
	      txt = "flys";
	  }
	  else
          if ( ch->position == POS_SHOVE )
            txt = "is shoved";
 	  else
	  if ( ch->position == POS_DRAG )
            txt = "is dragged";
  	  else
	  {
	    if ( drunk )
	      txt = "stumbles drunkenly";
	     else
	      txt = "leaves";
	  }
        }
      }
      if ( ch->mount )
      {
	sprintf( buf, "$g %s %s upon $N.", txt, dir_name[door] );
	act( AT_ACTION, buf, ch, NULL, ch->mount, TO_NOTVICT );
      }
      else
      {
	sprintf( buf, "$g %s $T.", txt );
	act( AT_ACTION, buf, ch, NULL, dir_name[door], TO_ROOM );
      }
    }

    rprog_leave_trigger( ch );
    if( char_died(ch) )
      return global_retcode;

    char_from_room( ch );
    if ( ch->mount )
    {
      rprog_leave_trigger( ch->mount );
      if( char_died(ch) )
        return global_retcode;
      if( ch->mount )
      {
        char_from_room( ch->mount );
        char_to_room( ch->mount, to_room );
      }
    }


    char_to_room( ch, to_room );
    if ( !IS_AFFECTED(ch, AFF_SNEAK)
    && ( IS_NPC(ch) || !IS_SET(ch->act, PLR_WIZINVIS) ) )
    {
      if ( fall )
        txt = "falls";
      else
      if ( ch->mount )
      {
	if ( IS_AFFECTED( ch->mount, AFF_FLOATING ) )
	  txt = "floats in";
	else
	if ( IS_AFFECTED( ch->mount, AFF_FLYING ) )
	  txt = "flys in";
	else
	  txt = "rides in";
      }
      else
      {
	if ( IS_AFFECTED( ch, AFF_FLOATING ) )
	{
	  if ( drunk )
	    txt = "floats in unsteadily";
	   else
	    txt = "floats in";
	}
	else
	if ( IS_AFFECTED( ch, AFF_FLYING ) )
	{
	  if ( drunk )
	    txt = "flys in shakily";
	   else
	    txt = "flys in";
	}
	else if ( ch->position == POS_SHOVE )
		txt = "is shoved in";
	else if ( ch->position == POS_DRAG )
		txt = "is dragged in";
	else if ( ch->position == POS_CARRIED )
		txt = "is carried in";
  	else
	{
	  if ( drunk )
	    txt = "stumbles drunkenly in";
	   else
	    txt = "arrives";
		}
      }
      dtxt = rev_exit(door);
      if ( ch->mount )
      {
	sprintf( buf, "$g %s from %s upon $N.", txt, dtxt );
	act( AT_ACTION, buf, ch, NULL, ch->mount, TO_ROOM );
      }
      else
      {
	sprintf( buf, "$g %s from %s.", txt, dtxt );
	act( AT_ACTION, buf, ch, NULL, NULL, TO_ROOM );
      }
    }

    if ( !IS_IMMORTAL(ch)
    &&  !IS_NPC(ch)
    &&  ch->in_room->area != to_room->area )
    {
	if ( ch->top_level < to_room->area->low_soft_range )
	{
	   set_char_color( AT_MAGIC, ch );
	   send_to_char("You feel uncomfortable being in this strange land...\n\r", ch);
	}
	else
	if ( ch->top_level > to_room->area->hi_soft_range )
	{
	   set_char_color( AT_MAGIC, ch );
	   send_to_char("You feel there is not much to gain visiting this place...\n\r", ch);
	}
    }

    do_look( ch, "auto" );
    if ( brief ) 
      SET_BIT( ch->act, PLR_BRIEF );


    /* BIG ugly looping problem here when the character is mptransed back
       to the starting room.  To avoid this, check how many chars are in 
       the room at the start and stop processing followers after doing
       the right number of them.  -- Narn
    */
	if ( !fall )
	{
		CHAR_DATA *fch;
		CHAR_DATA *nextinroom;
		int chars = 0, count = 0;

		for ( fch = from_room->first_person; fch; fch = fch->next_in_room )
			chars++;

		for ( fch = from_room->first_person; fch && ( count < chars ); fch = nextinroom )
		{
			nextinroom = fch->next_in_room;
			count++;
			if ( fch != ch		/* loop room bug fix here by Thoric */
				&& fch->master == ch
				&& fch->position == POS_STANDING )
			{
				act( AT_ACTION, "You follow $N.", fch, NULL, ch, TO_CHAR );
				move_char( fch, pexit, 0 );
			}
			if ( fch != ch		/* loop room bug fix here by Thoric */
				&& fch->char_carriedby != NULL
				&& fch->char_carriedby == ch
				&& ch->position == POS_CARRYING 
				&& fch->position == POS_CARRIED )
			{
				act( AT_ACTION, "You carry $N along.", ch, NULL, fch, TO_CHAR );
				move_char( fch, pexit, 0 );
			}

		}
	}

    if ( retcode != rNONE )
      return retcode;

    if ( char_died(ch) )
      return retcode;

    mprog_entry_trigger( ch );
    if ( char_died(ch) )
      return retcode;

    rprog_enter_trigger( ch );
    if ( char_died(ch) )
       return retcode;

    mprog_greet_trigger( ch );
    if ( char_died(ch) )
       return retcode;

    oprog_greet_trigger( ch );
    if ( char_died(ch) )
       return retcode;

    if (!will_fall( ch, fall )
    &&   fall > 0 )
    {
	if (!IS_AFFECTED( ch, AFF_FLOATING )
	|| ( ch->mount && !IS_AFFECTED( ch->mount, AFF_FLOATING ) ) )
	{
		if ( number_percent() > 50 && get_trust(ch) >= 6 && !IS_IMMORTAL(ch) )
		{
			if ( !IS_NPC(ch) && !IS_SET( ch->pcdata->cyber, CYBER_LEGS ) )
			{
				if ( !xIS_SET(ch->bodyparts,BODY_L_LEG ) )
					xSET_BIT(ch->bodyparts, BODY_L_LEG);
				else if ( !xIS_SET(ch->bodyparts,BODY_R_LEG) )
					xSET_BIT(ch->bodyparts, BODY_R_LEG);
			}
		}
		set_char_color( AT_HURT, ch );
		send_to_char( "OUCH! You hit the ground!\n\r", ch );
		WAIT_STATE( ch, 20 );
		retcode = damage( ch, ch, 50 * fall, TYPE_UNDEFINED );
	}
	else
	{
	  set_char_color( AT_MAGIC, ch );
	  send_to_char( "You lightly float down to the ground.\n\r", ch );
	}
    }
    return retcode;
}


void do_north( CHAR_DATA *ch, char *argument )
{
    move_char( ch, get_exit(ch->in_room, DIR_NORTH), 0 );
    return;
}


void do_east( CHAR_DATA *ch, char *argument )
{
    move_char( ch, get_exit(ch->in_room, DIR_EAST), 0 );
    return;
}


void do_south( CHAR_DATA *ch, char *argument )
{
    move_char( ch, get_exit(ch->in_room, DIR_SOUTH), 0 );
    return;
}


void do_west( CHAR_DATA *ch, char *argument )
{
    move_char( ch, get_exit(ch->in_room, DIR_WEST), 0 );
    return;
}


void do_up( CHAR_DATA *ch, char *argument )
{
    move_char( ch, get_exit(ch->in_room, DIR_UP), 0 );
    return;
}


void do_down( CHAR_DATA *ch, char *argument )
{
    move_char( ch, get_exit(ch->in_room, DIR_DOWN), 0 );
    return;
}

void do_northeast( CHAR_DATA *ch, char *argument )
{
    move_char( ch, get_exit(ch->in_room, DIR_NORTHEAST), 0 );
    return;
}

void do_northwest( CHAR_DATA *ch, char *argument )
{
    move_char( ch, get_exit(ch->in_room, DIR_NORTHWEST), 0 );
    return;
}

void do_southeast( CHAR_DATA *ch, char *argument )
{
    move_char( ch, get_exit(ch->in_room, DIR_SOUTHEAST), 0 );
    return;
}

void do_southwest( CHAR_DATA *ch, char *argument )
{
    move_char( ch, get_exit(ch->in_room, DIR_SOUTHWEST), 0 );
    return;
}



EXIT_DATA *find_door( CHAR_DATA *ch, char *arg, bool quiet )
{
    EXIT_DATA *pexit;
    int door;

    if (arg == NULL || !str_cmp(arg,""))
      return NULL;

    pexit = NULL;
	 if ( !str_cmp( arg, "n"  ) || !str_cmp( arg, "north"	  ) ) door = 0;
    else if ( !str_cmp( arg, "e"  ) || !str_cmp( arg, "east"	  ) ) door = 1;
    else if ( !str_cmp( arg, "s"  ) || !str_cmp( arg, "south"	  ) ) door = 2;
    else if ( !str_cmp( arg, "w"  ) || !str_cmp( arg, "west"	  ) ) door = 3;
    else if ( !str_cmp( arg, "u"  ) || !str_cmp( arg, "up"	  ) ) door = 4;
    else if ( !str_cmp( arg, "d"  ) || !str_cmp( arg, "down"	  ) ) door = 5;
    else if ( !str_cmp( arg, "ne" ) || !str_cmp( arg, "northeast" ) ) door = 6;
    else if ( !str_cmp( arg, "nw" ) || !str_cmp( arg, "northwest" ) ) door = 7;
    else if ( !str_cmp( arg, "se" ) || !str_cmp( arg, "southeast" ) ) door = 8;
    else if ( !str_cmp( arg, "sw" ) || !str_cmp( arg, "southwest" ) ) door = 9;
    else
    {
	for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next )
	{
	    if ( (quiet || IS_SET(pexit->exit_info, EX_ISDOOR))
	    &&    pexit->keyword
	    &&    nifty_is_name( arg, pexit->keyword ) )
		return pexit;
	}
	if ( !quiet )
	  act( AT_PLAIN, "You see no $T here.", ch, NULL, arg, TO_CHAR );
	return NULL;
    }

    if ( (pexit = get_exit( ch->in_room, door )) == NULL )
    {
	if ( !quiet)
	  act( AT_PLAIN, "You see no $T here.", ch, NULL, arg, TO_CHAR );
	return NULL;
    }

    if ( quiet )
	return pexit;

    if ( IS_SET(pexit->exit_info, EX_SECRET) )
    {
	act( AT_PLAIN, "You see no $T here.", ch, NULL, arg, TO_CHAR );
	return NULL;
    }

    if ( !IS_SET(pexit->exit_info, EX_ISDOOR) && !xIS_SET(pexit->to_room->room_flags,ROOM_PLR_HOME) )
    {
	send_to_char( "You can't do that.\n\r", ch );
	return NULL;
    }

    return pexit;
}


void toggle_bexit_flag( EXIT_DATA *pexit, int flag )
{
    EXIT_DATA *pexit_rev;

    TOGGLE_BIT(pexit->exit_info, flag);
    if ( (pexit_rev = pexit->rexit) != NULL
    &&   pexit_rev != pexit )
	TOGGLE_BIT( pexit_rev->exit_info, flag );
}

void set_bexit_flag( EXIT_DATA *pexit, int flag )
{
    EXIT_DATA *pexit_rev;

    SET_BIT(pexit->exit_info, flag);
    if ( (pexit_rev = pexit->rexit) != NULL
    &&   pexit_rev != pexit )
	SET_BIT( pexit_rev->exit_info, flag );
}

void remove_bexit_flag( EXIT_DATA *pexit, int flag )
{
    EXIT_DATA *pexit_rev;

    REMOVE_BIT(pexit->exit_info, flag);
    if ( (pexit_rev = pexit->rexit) != NULL
    &&   pexit_rev != pexit )
	REMOVE_BIT( pexit_rev->exit_info, flag );
}

void do_open( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    EXIT_DATA *pexit;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	do_openhatch( ch , "" );
	return;
    }

    if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL )
    {
	/* 'open door' */
	EXIT_DATA *pexit_rev;

	if ( !IS_SET(pexit->exit_info, EX_ISDOOR) )
	    { send_to_char( "You can't do that.\n\r",      ch ); return; }
	if ( !IS_SET(pexit->exit_info, EX_CLOSED) )
	    { send_to_char( "It's already open.\n\r",      ch ); return; }
	if (  IS_SET(pexit->exit_info, EX_LOCKED) )
	    { send_to_char( "It's locked.\n\r",            ch ); return; }

	if ( !IS_SET(pexit->exit_info, EX_SECRET)
	||   (pexit->keyword && nifty_is_name( arg, pexit->keyword )) )
	{
	    act( AT_ACTION, "$g opens the $d.", ch, NULL, pexit->keyword, TO_ROOM );
	    act( AT_ACTION, "You open the $d.", ch, NULL, pexit->keyword, TO_CHAR );
	    if ( (pexit_rev = pexit->rexit) != NULL
	    &&   pexit_rev->to_room == ch->in_room )
	    {
		CHAR_DATA *rch;

		for ( rch = pexit->to_room->first_person; rch; rch = rch->next_in_room )
		    act( AT_ACTION, "The $d opens.", rch, NULL, pexit_rev->keyword, TO_CHAR );
	        sound_to_room( pexit->to_room , "!!SOUND(door U=http://mercury.spaceports.com/~gavin1/)" );
	    }
	    remove_bexit_flag( pexit, EX_CLOSED );
            
            sound_to_room( ch->in_room , "!!SOUND(door U=http://mercury.spaceports.com/~gavin1/)" );
            return;
	}
    }

    if ( ( obj = get_obj_here( ch, arg ) ) != NULL )
    {
	/* 'open object' */
	if ( obj->item_type != ITEM_CONTAINER && ( obj->item_type != ITEM_FURNITURE && obj->value[4] != 1 ) )
	{ 
          ch_printf( ch, "%s isn't a container.\n\r", capitalize( obj->short_descr ) ); 
          return;
    } 
	if ( !IS_SET(obj->value[1], CONT_CLOSED) )
	{ 
          ch_printf( ch, "%s is already open.\n\r", capitalize( obj->short_descr ) ); 
          return;
        } 
	if ( !IS_SET(obj->value[1], CONT_CLOSEABLE) )
	{ 
          ch_printf( ch, "%s cannot be opened or closed.\n\r", capitalize( obj->short_descr ) ); 
          return;
        } 
	if ( IS_SET(obj->value[1], CONT_LOCKED) )
	{ 
          ch_printf( ch, "%s is locked.\n\r", capitalize( obj->short_descr ) ); 
          return;
        } 

	REMOVE_BIT(obj->value[1], CONT_CLOSED);
	act( AT_ACTION, "You open $p.", ch, obj, NULL, TO_CHAR );
	act( AT_ACTION, "$g opens $p.", ch, obj, NULL, TO_ROOM );
	return;
    }

    if ( !str_cmp(arg , "hatch") );
    {
      do_openhatch( ch , argument );
      return;
    }

    do_openhatch( ch , arg );
    return;
}



void do_close( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj;
    EXIT_DATA *pexit;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	do_closehatch(  ch , "" );
	return;
    }

    if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL )
    {
	/* 'close door' */
	EXIT_DATA *pexit_rev;

	if ( !IS_SET(pexit->exit_info, EX_ISDOOR) )
	    { send_to_char( "You can't do that.\n\r",      ch ); return; }
	if ( IS_SET(pexit->exit_info, EX_CLOSED) )
	    { send_to_char( "It's already closed.\n\r",    ch ); return; }

	act( AT_ACTION, "$g closes the $d.", ch, NULL, pexit->keyword, TO_ROOM );
	act( AT_ACTION, "You close the $d.", ch, NULL, pexit->keyword, TO_CHAR );

	/* close the other side */
	if ( ( pexit_rev = pexit->rexit ) != NULL
	&&   pexit_rev->to_room == ch->in_room )
	{
	    CHAR_DATA *rch;

	    SET_BIT( pexit_rev->exit_info, EX_CLOSED );
	    for ( rch = pexit->to_room->first_person; rch; rch = rch->next_in_room )
		act( AT_ACTION, "The $d closes.", rch, NULL, pexit_rev->keyword, TO_CHAR );
	}
	set_bexit_flag( pexit, EX_CLOSED );
        return;
    }

    if ( ( obj = get_obj_here( ch, arg ) ) != NULL )
    {
	/* 'close object' */
	if ( obj->item_type != ITEM_CONTAINER && ( obj->item_type != ITEM_FURNITURE && obj->value[4] != 1 ) )
	{ 
		ch_printf( ch, "%s isn't a container.\n\r", capitalize( obj->short_descr ) ); 
		return;
	} 
	if ( IS_SET(obj->value[1], CONT_CLOSED) )
	{ 
		ch_printf( ch, "%s is already closed.\n\r", capitalize( obj->short_descr ) ); 
		return;
	} 
	if ( !IS_SET(obj->value[1], CONT_CLOSEABLE) )
	{ 
		ch_printf( ch, "%s cannot be opened or closed.\n\r", capitalize( obj->short_descr ) ); 
		return;
	} 

	SET_BIT(obj->value[1], CONT_CLOSED);
	act( AT_ACTION, "You close $p.", ch, obj, NULL, TO_CHAR );
	act( AT_ACTION, "$g closes $p.", ch, obj, NULL, TO_ROOM );
	return;
    }

    if ( !str_cmp( arg , "hatch" ) )
    {
    	do_closehatch( ch , argument );
    	return;
    }

    	do_closehatch( ch , arg );
    return;
}


/*
 * Keyring support added by Thoric
 * Idea suggested by Onyx <MtRicmer@worldnet.att.net> of Eldarion
 *
 * New: returns pointer to key/NULL instead of TRUE/FALSE
 *
 * If you want a feature like having immortals always have a key... you'll
 * need to code in a generic key, and make sure extract_obj doesn't extract it
 */
OBJ_DATA *has_key( CHAR_DATA *ch, int key )
{
    OBJ_DATA *obj, *obj2;

    for ( obj = ch->first_carrying; obj; obj = obj->next_content )
    {
	if ( obj->pIndexData->vnum == key || (obj->item_type == ITEM_KEY && obj->value[0] == key) )
	    return obj;
	else
	if ( obj->item_type == ITEM_KEYRING )
	    for ( obj2 = obj->first_content; obj2; obj2 = obj2->next_content )
		if ( obj2->pIndexData->vnum == key || obj2->value[0] == key )
		    return obj2;
    }

    return NULL;
}


void do_lock( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj, *key;
    EXIT_DATA *pexit;
	int count;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	send_to_char( "Lock what?\n\r", ch );
	return;
    }

    if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL )
    {
	/* 'lock door' */

	if ( !IS_SET(pexit->exit_info, EX_ISDOOR) )
	    { send_to_char( "You can't do that.\n\r",      ch ); return; }
	if ( !IS_SET(pexit->exit_info, EX_CLOSED) )
	    { send_to_char( "It's not closed.\n\r",        ch ); return; }
	if ( pexit->key < 0 )
	    { send_to_char( "It can't be locked.\n\r",     ch ); return; }
	if ( (key=has_key(ch, pexit->key)) == NULL )
	    { send_to_char( "You lack the key.\n\r",       ch ); return; }
	if ( IS_SET(pexit->exit_info, EX_LOCKED) )
	    { send_to_char( "It's already locked.\n\r",    ch ); return; }

	if ( !IS_SET(pexit->exit_info, EX_SECRET)
	||   (pexit->keyword && nifty_is_name( arg, pexit->keyword )) )
	{
	    send_to_char( "*Click*\n\r", ch );
	    count = key->count;
	    key->count = 1;
	    act( AT_ACTION, "$g locks the $d with $p.", ch, key, pexit->keyword, TO_ROOM );
	    key->count = count;
	    set_bexit_flag( pexit, EX_LOCKED );
            return;
        }
    }

    if ( ( obj = get_obj_here( ch, arg ) ) != NULL )
    {
	/* 'lock object' */
	if ( obj->item_type != ITEM_CONTAINER )
	    { send_to_char( "That's not a container.\n\r", ch ); return; }
	if ( !IS_SET(obj->value[1], CONT_CLOSED) )
	    { send_to_char( "It's not closed.\n\r",        ch ); return; }
	if ( obj->value[2] < 0 )
	    { send_to_char( "It can't be locked.\n\r",     ch ); return; }
	if ( (key=has_key(ch, obj->value[2])) == NULL )
	    { send_to_char( "You lack the key.\n\r",       ch ); return; }
	if ( IS_SET(obj->value[1], CONT_LOCKED) )
	    { send_to_char( "It's already locked.\n\r",    ch ); return; }

	SET_BIT(obj->value[1], CONT_LOCKED);
	send_to_char( "*Click*\n\r", ch );
	count = key->count;
	key->count = 1;
	act( AT_ACTION, "$g locks $p with $P.", ch, obj, key, TO_ROOM );
	key->count = count;
	return;
    }

    ch_printf( ch, "You see no %s here.\n\r", arg );
    return;
}



void do_unlock( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    OBJ_DATA *obj, *key;
    EXIT_DATA *pexit;
    int count;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	send_to_char( "Unlock what?\n\r", ch );
	return;
    }

    if ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL )
    {
	/* 'unlock door' */

	if ( !IS_SET(pexit->exit_info, EX_ISDOOR) )
	    { send_to_char( "You can't do that.\n\r",      ch ); return; }
	if ( !IS_SET(pexit->exit_info, EX_CLOSED) )
	    { send_to_char( "It's not closed.\n\r",        ch ); return; }
	if ( pexit->key < 0 )
	    { send_to_char( "It can't be unlocked.\n\r",   ch ); return; }
	if ( (key=has_key(ch, pexit->key)) == NULL )
	    { send_to_char( "You lack the key.\n\r",       ch ); return; }
	if ( !IS_SET(pexit->exit_info, EX_LOCKED) )
	    { send_to_char( "It's already unlocked.\n\r",  ch ); return; }

		if ( !IS_SET(pexit->exit_info, EX_SECRET)
	||   (pexit->keyword && nifty_is_name( arg, pexit->keyword )) )
	{
	    send_to_char( "*Click*\n\r", ch );
	    count = key->count;
	    key->count = 1;
	    act( AT_ACTION, "$g unlocks the $d with $p.", ch, key, pexit->keyword, TO_ROOM );
	    key->count = count;
	    if ( IS_SET(pexit->exit_info, EX_EATKEY) )
	    {
		separate_obj(key);
		extract_obj(key);
	    }
	    remove_bexit_flag( pexit, EX_LOCKED );
            return;   
	}
    }

    if ( ( obj = get_obj_here( ch, arg ) ) != NULL )
    {
	/* 'unlock object' */
	if ( obj->item_type != ITEM_CONTAINER )
	    { send_to_char( "That's not a container.\n\r", ch ); return; }
	if ( !IS_SET(obj->value[1], CONT_CLOSED) )
	    { send_to_char( "It's not closed.\n\r",        ch ); return; }
	if ( obj->value[2] < 0 )
	    { send_to_char( "It can't be unlocked.\n\r",   ch ); return; }
	if ( (key=has_key(ch, obj->value[2])) == NULL )
	    { send_to_char( "You lack the key.\n\r",       ch ); return; }
	if ( !IS_SET(obj->value[1], CONT_LOCKED) )
	    { send_to_char( "It's already unlocked.\n\r",  ch ); return; }

	REMOVE_BIT(obj->value[1], CONT_LOCKED);
	send_to_char( "*Click*\n\r", ch );
	count = key->count;
	key->count = 1;
	act( AT_ACTION, "$g unlocks $p with $P.", ch, obj, key, TO_ROOM );
	key->count = count;
	if ( IS_SET(obj->value[1], CONT_EATKEY) )
	{
	    separate_obj(key);
	    extract_obj(key);
	}
	return;
    }

    ch_printf( ch, "You see no %s here.\n\r", arg );
    return;
}

void do_bashdoor( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *gch;
	EXIT_DATA *pexit;
	char       arg [ MAX_INPUT_LENGTH ];

	if ( !IS_NPC( ch )
	&&  ch->pcdata->learned[gsn_bashdoor] <= 0  )
	{
	    send_to_char( "You're not enough of a warrior to bash doors!\n\r", ch );
	    return;
	}

	one_argument( argument, arg );

	if ( arg[0] == '\0' )
	{
	    send_to_char( "Bash what?\n\r", ch );
	    return;
	}

	if ( ch->fighting )
	{
	    send_to_char( "You can't break off your fight.\n\r", ch );
	    return;
	}

	if ( ch->char_carriedby )
	{
	    send_to_char( "Your busy being carried.\n\r", ch );
	    return;
	}
	if ( ch->char_carrying )
	{
	    send_to_char( "Your busy carrying someone.\n\r", ch );
	    return;
	}

	if ( ( pexit = find_door( ch, arg, FALSE ) ) != NULL )
	{
	    ROOM_INDEX_DATA *to_room;
	    EXIT_DATA       *pexit_rev;
	    int              chance;
	    char	    *keyword;

	    if ( !IS_SET( pexit->exit_info, EX_CLOSED ) )
	    {
		send_to_char( "Calm down.  It is already open.\n\r", ch );
		return;
	    }

	    WAIT_STATE( ch, skill_table[gsn_bashdoor]->beats );

	    if ( IS_SET( pexit->exit_info, EX_SECRET ) )
		keyword = "wall";
	    else
		keyword = pexit->keyword;
	    if ( !IS_NPC(ch) )
		chance = ch->pcdata->learned[gsn_bashdoor] / 2;
	    else
		chance = 90;

	    if ( !IS_SET( pexit->exit_info, EX_BASHPROOF )
	    &&   ch->move >= 15
	    &&   number_percent( ) < ( chance + 4 * ( get_curr_str( ch ) - 19 ) ) )
	    {
		REMOVE_BIT( pexit->exit_info, EX_CLOSED );
		if ( IS_SET( pexit->exit_info, EX_LOCKED ) )
		REMOVE_BIT( pexit->exit_info, EX_LOCKED );
		SET_BIT( pexit->exit_info, EX_BASHED );

		act(AT_SKILL, "Crash!  You bashed open the $d!", ch, NULL, keyword, TO_CHAR );
		act(AT_SKILL, "$g bashes open the $d!",          ch, NULL, keyword, TO_ROOM );
		learn_from_success(ch, gsn_bashdoor);

		if ( (to_room = pexit->to_room) != NULL
		&&   (pexit_rev = pexit->rexit) != NULL
		&&    pexit_rev->to_room	== ch->in_room )
		{
			CHAR_DATA *rch;

			REMOVE_BIT( pexit_rev->exit_info, EX_CLOSED );
			if ( IS_SET( pexit_rev->exit_info, EX_LOCKED ) )
			  REMOVE_BIT( pexit_rev->exit_info, EX_LOCKED );
			SET_BIT( pexit_rev->exit_info, EX_BASHED );

			for ( rch = to_room->first_person; rch; rch = rch->next_in_room )
			{
			    act(AT_SKILL, "The $d crashes open!",
				rch, NULL, pexit_rev->keyword, TO_CHAR );
			}
		}
		damage( ch, ch, ( ch->max_hit / 20 ), gsn_bashdoor );

	    }
	    else
	    {
		act(AT_SKILL, "WHAAAAM!!!  You bash against the $d, but it doesn't budge.",
			ch, NULL, keyword, TO_CHAR );
		act(AT_SKILL, "WHAAAAM!!!  $g bashes against the $d, but it holds strong.",
			ch, NULL, keyword, TO_ROOM );
		damage( ch, ch, ( ch->max_hit / 20 ) + 10, gsn_bashdoor );
		learn_from_failure(ch, gsn_bashdoor);
	    }
	}    
	else
	{
	    act(AT_SKILL, "WHAAAAM!!!  You bash against the wall, but it doesn't budge.",
		ch, NULL, NULL, TO_CHAR );
	    act(AT_SKILL, "WHAAAAM!!!  $g bashes against the wall, but it holds strong.",
		ch, NULL, NULL, TO_ROOM );
	    damage( ch, ch, ( ch->max_hit / 20 ) + 10, gsn_bashdoor );
	    learn_from_failure(ch, gsn_bashdoor);
	}
	if ( !char_died( ch ) )
	   for ( gch = ch->in_room->first_person; gch; gch = gch->next_in_room )
	   {
		 if ( IS_AWAKE( gch )
		 && !gch->fighting
		 && ( IS_NPC( gch ) && !IS_AFFECTED( gch, AFF_CHARM ) )
		 && ( ch->top_level - gch->top_level <= 4 )
		 && number_bits( 2 ) == 0 )
		 multi_hit( gch, ch, TYPE_UNDEFINED );
	   }

        return;
}

/* Orginal furniture taken from Russ Walsh's Rot copyright 1996-1997
   Furniture 1.0 is provided by Xerves
   Allows you to stand/sit/rest/sleep on/at/in objects -- Xerves */
void do_stand( CHAR_DATA *ch, char *argument )
{
	OBJ_DATA *obj = NULL;
	int aon = 0;
	
	if (ch->position == POS_MOUNTED)
	{
		send_to_char("You are already sitting - on your mount.\n\r",ch);
		return;
	}

	if ( ch->char_carrying != NULL || ch->char_carriedby != NULL )
	{
		send_to_char("Not available while carrying or being carried ( ... Yet - Gavin )\n\r",ch);
		return;
	}
	
	/* okay, now that we know we can sit, find an object to sit on */
	if (argument[0] != '\0')
	{
		obj = get_obj_list(ch,argument,ch->in_room->first_content);
		if (obj == NULL)
		{
			send_to_char("You don't see that here.\n\r",ch);
			return;
		}
		if (obj->item_type != ITEM_FURNITURE)
		{
			send_to_char("It has to be furniture silly.\n\r", ch);
			return;
		}
		if (!IS_SET(obj->value[2],STAND_ON)
			&& !IS_SET(obj->value[2],STAND_IN)
			&& !IS_SET(obj->value[2],STAND_AT))
		{
			send_to_char("You can't stand on that.\n\r",ch);
			return;
		}
		if (ch->on == obj)
			aon = 1;
		else
			ch->on = obj;
	}

    switch ( ch->position )
    {
		case POS_SLEEPING:
		{
			if ( IS_AFFECTED(ch, AFF_SLEEP) )
				{ send_to_char( "You can't wake up!\n\r", ch ); return; }
			if (obj == NULL)
			{
				send_to_char( "You wake and stand up.\n\r", ch );
				act( AT_ACTION, "$g wakes and stands up.", ch, NULL, NULL, TO_ROOM );
				ch->on = NULL;
			}
			else if (IS_SET(obj->value[2],STAND_AT))
			{
				act( AT_ACTION, "You wake and stand at $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g wakes and stands at $p.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],STAND_ON))
			{
				act( AT_ACTION, "You wake and stand on $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g wakes and stands on $p.",ch,obj,NULL,TO_ROOM);
			}
			else
			{
				act( AT_ACTION, "You wake and stand in $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g wakes and stands in $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_STANDING;
			do_look(ch,"auto");
			break;
		}
		case POS_RESTING: case POS_SITTING:
		{
			if (obj == NULL)
			{
				send_to_char( "You stand up.\n\r", ch );
				act( AT_ACTION, "$g stands up.", ch, NULL, NULL, TO_ROOM );
				ch->on = NULL;
			}
			else if (IS_SET(obj->value[2],STAND_AT))
			{
				act( AT_ACTION, "You stand at $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g stands at $p.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],STAND_ON))
			{
				act( AT_ACTION, "You stand on $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g stands on $p.",ch,obj,NULL,TO_ROOM);
			}
			else
			{
				act( AT_ACTION, "You stand in $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g stands on $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_STANDING;
			break;
		}
		case POS_STANDING:
		{
			if (obj != NULL && aon != 1 )
			{
				if (IS_SET(obj->value[2],STAND_AT))
				{
					act( AT_ACTION, "You stand at $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g stands at $p.",ch,obj,NULL,TO_ROOM);
				}
				else if (IS_SET(obj->value[2],STAND_ON))
				{
					act( AT_ACTION, "You stand on $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g stands on $p.",ch,obj,NULL,TO_ROOM);
				}
				else
				{
					act( AT_ACTION, "You stand in $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g stands on $p.",ch,obj,NULL,TO_ROOM);
				}
			}
			else if (aon == 1)
			{
				act( AT_ACTION, "You are already using $p for furniture.", ch, obj, NULL, TO_CHAR);
			}
			else if (ch->on != NULL && obj == NULL)
			{
				act( AT_ACTION, "You hop off of $p and stand on the ground.", ch, ch->on, NULL, TO_CHAR);
				act( AT_ACTION, "$g hops off of $p and stands on the ground.", ch, ch->on, NULL, TO_ROOM );
				ch->on = NULL;
			}
			else
				send_to_char( "You are already standing.\n\r", ch );
			break;
		}
		case POS_FIGHTING:
			send_to_char( "You are already fighting!\n\r", ch );
			break;
	}
	return;
}

void do_sit( CHAR_DATA *ch, char *argument )
{
	OBJ_DATA *obj = NULL;
	int aon = 0;
	
	if (ch->position == POS_MOUNTED)
	{
		send_to_char("You are already sitting - on your mount.\n\r",ch);
		return;
	}

	if ( ch->char_carriedby != NULL )
	{
		send_to_char("Not available while carrying or being carried ( ... Yet - Gavin )\n\r",ch);
		return;
	}
	
	/* okay, now that we know we can sit, find an object to sit on */
    if (argument[0] != '\0')
    {
		obj = get_obj_list(ch,argument,ch->in_room->first_content);
		if (obj == NULL)
		{
			send_to_char("You don't see that here.\n\r",ch);
			return;
		}
		if (obj->item_type != ITEM_FURNITURE)
		{
			send_to_char("It has to be furniture silly.\n\r", ch);
			return;
		}
		if (!IS_SET(obj->value[2],SIT_ON)
			&&   !IS_SET(obj->value[2],SIT_IN)
			&&   !IS_SET(obj->value[2],SIT_AT))
		{
			send_to_char("You can't sit on that.\n\r",ch);
			return;
		}
		if (ch->on == obj)
			aon = 1;
		else
			ch->on = obj;
	}

    switch (ch->position)
    {
		case POS_SLEEPING:
			if (obj == NULL)
			{
				send_to_char( "You wake and sit up.\n\r", ch );
				act( AT_ACTION, "$g wakes and sits up.", ch, NULL, NULL, TO_ROOM );
			}
			else if (IS_SET(obj->value[2],SIT_AT))
			{
				act( AT_ACTION, "You wake up and sit at $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g wakes and sits at $p.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],SIT_ON))
			{
				act( AT_ACTION, "You wake and sit on $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g wakes and sits at $p.",ch,obj,NULL,TO_ROOM);
			}
			else
			{
				act( AT_ACTION, "You wake and sit in $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g wakes and sits in $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_SITTING;
			break;
		case POS_RESTING:
			if (obj == NULL)
				send_to_char("You stop resting.\n\r",ch);
			else if (IS_SET(obj->value[2],SIT_AT))
			{
				act( AT_ACTION, "You sit at $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sits at $p.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],SIT_ON))
			{
				act( AT_ACTION, "You sit on $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sits on $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_SITTING;
			break;
		case POS_SITTING:
			if (obj != NULL && aon != 1 )
			{
				if (IS_SET(obj->value[2],SIT_AT))
				{
					act( AT_ACTION, "You sit at $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g sits at $p.",ch,obj,NULL,TO_ROOM);
				}
				else if (IS_SET(obj->value[2],STAND_ON))
				{
					act( AT_ACTION, "You sit on $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g sits on $p.",ch,obj,NULL,TO_ROOM);
				}
				else
				{
					act( AT_ACTION, "You sit in $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g sits on $p.",ch,obj,NULL,TO_ROOM);
				}
			}
			else if (aon == 1)
			{
				act( AT_ACTION, "You are already using $p for furniture.", ch, obj, NULL, TO_CHAR);
			}
			else if (ch->on != NULL && obj == NULL)
			{
				act( AT_ACTION, "You hop off of $p and sit on the ground.", ch, ch->on, NULL, TO_CHAR);
				act( AT_ACTION, "$g hops off of $p and sits on the ground.", ch, ch->on, NULL, TO_ROOM );
				ch->on = NULL;
			}
			else
				send_to_char( "You are already sitting.\n\r", ch );
			break;
		case POS_STANDING:
			if (obj == NULL)
			{
				send_to_char("You sit down.\n\r",ch);
				act( AT_ACTION, "$g sits down on the ground.",ch,NULL,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],SIT_AT))
			{
				act( AT_ACTION, "You sit down at $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sits down at $p.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],SIT_ON))
			{
				act( AT_ACTION, "You sit on $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sits on $p.",ch,obj,NULL,TO_ROOM);
			}
			else
			{
				act( AT_ACTION, "You sit down in $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sits down in $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_SITTING;
			break;
		case POS_FIGHTING:
			send_to_char( "You are already fighting!\n\r", ch );
			break;
		case POS_CARRYING:
			/*******************************************
			 *  Aliana says:                           *
			 *      X sits down placing Y beside them  *
			 *      You sit ( whereever) placing Y beside you
			 *      X sits placing you beside him/her 
			 *******************************************/
			if ( ch->char_carrying != NULL )
			{
				if (obj == NULL)
				{
					act( AT_ACTION, "You sit on the ground, placing $N beside you.", ch, NULL, ch->char_carrying, TO_CHAR);
					act( AT_ACTION, "$g sits down placing $N beside $m.", ch, NULL, ch->char_carrying, TO_VICT );
					act( AT_ACTION, "$g sits placing you beside $m.", ch, NULL, ch->char_carrying, TO_NOTVICT );
					ch->char_carrying->position = POS_SITTING;
				}
				else if (IS_SET(obj->value[2],SIT_AT))
				{
					act( AT_ACTION, "You sit down at $p, placing $N beside you.", ch, obj, ch->char_carrying, TO_CHAR);
					act( AT_ACTION, "$g sits down at $p, placing $N beside $m.", ch, obj, ch->char_carrying, TO_VICT );
					act( AT_ACTION, "$g sits down at $p, placing you beside $m.", ch, obj, ch->char_carrying, TO_NOTVICT );
					ch->char_carrying->on = obj;
					ch->char_carrying->position = POS_SITTING;
				}
				else if (IS_SET(obj->value[2],SIT_ON))
				{
					act( AT_ACTION, "You sit on $p, placing $N beside you.", ch, obj, ch->char_carrying, TO_CHAR);
					act( AT_ACTION, "$g sits on $p, placing $N beside $m.", ch, obj, ch->char_carrying, TO_VICT );
					act( AT_ACTION, "$g sits on $p, placing you beside $m.", ch, obj, ch->char_carrying, TO_NOTVICT );
					ch->char_carrying->on = obj;
					ch->char_carrying->position = POS_SITTING;
				}
				else
				{
					act( AT_ACTION, "You sit down in $p, placing $N beside you.", ch, obj, ch->char_carrying, TO_CHAR);
					act( AT_ACTION, "$g sits down in $p, placing $N beside $m.", ch, obj, ch->char_carrying, TO_VICT );
					act( AT_ACTION, "$g sits down in $p, placing you beside $m.", ch, obj, ch->char_carrying, TO_NOTVICT );
					ch->char_carrying->on = obj;
					ch->char_carrying->position = POS_SITTING;
				}
			}
			else
				send_to_char( "Error - Contact Gavin\n\r",ch);
			if ( ch->char_carriedby != NULL )
			{
				clear_carry(ch->char_carriedby);
				clear_carry(ch->char_carrying);
			}
			ch->position = POS_SITTING;
			break;
/*		case POS_CARRIED:
			send_to_char( "You are already fighting!\n\r", ch );
			ch->position = POS_STANDING;
			break;*/
		default:
			send_to_char( "Error - Contact A Coder\n\r",ch);
			break;
    }
	return;
}

void do_rest( CHAR_DATA *ch, char *argument )
{
	OBJ_DATA *obj = NULL;
	int aon = 0;
	
	if (ch->position == POS_MOUNTED)
	{
		send_to_char("You are already sitting - on your mount.\n\r",ch);
		return;
	}

	if ( ch->char_carrying != NULL || ch->char_carriedby != NULL )
	{
		send_to_char("Not available while carrying or being carried ( ... Yet - Gavin )\n\r",ch);
		return;
	}

	/* okay, now that we know we can sit, find an object to sit on */
    if (argument[0] != '\0')
    {
		obj = get_obj_list(ch,argument,ch->in_room->first_content);
		if (obj == NULL)
		{
			send_to_char("You don't see that here.\n\r",ch);
			return;
		}
		if (obj->item_type != ITEM_FURNITURE)
		{
			send_to_char("It has to be furniture silly.\n\r", ch);
			return;
		}
		if (!IS_SET(obj->value[2],REST_ON)
			&&   !IS_SET(obj->value[2],REST_IN)
			&&   !IS_SET(obj->value[2],REST_AT))
		{
			send_to_char("You can't rest on that.\n\r",ch);
			return;
		}
		if (ch->on == obj)
			aon = 1;
		else
			ch->on = obj;
	}
	switch ( ch->position )
    {
		case POS_SLEEPING:
			if (obj == NULL)
			{
				send_to_char( "You wake up and start resting.\n\r", ch );
				act  ( AT_ACTION, "$g wakes up and starts resting.",ch,NULL,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],REST_AT))
			{
				act( AT_ACTION, "You wake up and rest at $p.", ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g wakes up and rests at $p.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],REST_ON))
			{
				act( AT_ACTION, "You wake up and rest on $p.", ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g wakes up and rests on $p.",ch,obj,NULL,TO_ROOM);
			}
			else
			{
				act( AT_ACTION, "You wake up and rest in $p.", ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g wakes up and rests in $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_RESTING;
			break;
		case POS_RESTING:
			if (obj != NULL && aon != 1 )
			{
				if (IS_SET(obj->value[2],REST_AT))
				{
					act( AT_ACTION, "You rest at $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g rests at $p.",ch,obj,NULL,TO_ROOM);
				}
				else if (IS_SET(obj->value[2],REST_ON))
				{
					act( AT_ACTION, "You rest on $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g rests on $p.",ch,obj,NULL,TO_ROOM);
				}
				else
				{
					act( AT_ACTION, "You rest in $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g rests on $p.",ch,obj,NULL,TO_ROOM);
				}
			}
			else if (aon == 1)
			{
				act( AT_ACTION, "You are already using $p for furniture.", ch, obj, NULL, TO_CHAR);
			}
			else if (ch->on != NULL && obj == NULL)
			{
				act( AT_ACTION, "You hop off of $p and start resting on the ground.", ch, ch->on, NULL, TO_CHAR);
				act( AT_ACTION, "$g hops off of $p and starts to rest on the ground.", ch, ch->on, NULL, TO_ROOM );
				ch->on = NULL;
			}
			else
				send_to_char( "You are already resting.\n\r", ch );
			break;
		case POS_STANDING:
			if (obj == NULL)
			{
				send_to_char( "You rest.\n\r", ch );
				act( AT_ACTION, "$g sits down and rests.", ch, NULL, NULL, TO_ROOM );
			}
			else if (IS_SET(obj->value[2],REST_AT))
			{
				act( AT_ACTION, "You sit down at $p and rest.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sits down at $p and rests.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],REST_ON))
			{
				act( AT_ACTION, "You sit on $p and rest.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sits on $p and rests.",ch,obj,NULL,TO_ROOM);
			}
			else
			{
				act( AT_ACTION, "You rest in $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g rests in $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_RESTING;
			break;
		case POS_SITTING:
			if (obj == NULL)
			{
				send_to_char("You rest.\n\r",ch);
				act( AT_ACTION, "$g rests.",ch,NULL,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],REST_AT))
			{
				act( AT_ACTION, "You rest at $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g rests at $p.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],REST_ON))
			{
				act( AT_ACTION, "You rest on $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g rests on $p.",ch,obj,NULL,TO_ROOM);
			}
			else
			{
				act( AT_ACTION, "You rest in $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g rests in $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_RESTING;
			break;
		case POS_FIGHTING:
			send_to_char( "You are already fighting!\n\r", ch );
			break;
	}
	rprog_rest_trigger( ch );
	return;
}

void do_sleep( CHAR_DATA *ch, char *argument )
{
	OBJ_DATA *obj = NULL;
	int aon = 0;

	if (ch->position == POS_MOUNTED)
	{
		send_to_char("If you wish to go to sleep, get off of your mount first.n\r",ch);
		return;
	}

	if ( ch->char_carrying != NULL || ch->char_carriedby != NULL )
	{
		send_to_char("Not available while carrying or being carried ( ... Yet - Gavin )\n\r",ch);
		return;
	}

    /* okay, now that we know we can sit, find an object to sit on */
    if (argument[0] != '\0')
    {
		obj = get_obj_list(ch,argument,ch->in_room->first_content);
		if (obj == NULL)
		{
			send_to_char("You don't see that here.\n\r",ch);
			return;
		}	
		if (obj->item_type != ITEM_FURNITURE)
		{
			send_to_char("It has to be furniture silly.\n\r", ch);
			return;
		}
		if (!IS_SET(obj->value[2],SLEEP_ON)
			&&   !IS_SET(obj->value[2],SLEEP_IN)
			&&   !IS_SET(obj->value[2],SLEEP_AT))
		{			
			send_to_char("You can't sleep on that.\n\r",ch);
			return;
		}
        
		if (ch->on == obj)
			aon = 1;
		else
			ch->on = obj;
	}
    
	switch (ch->position)
    {
		case POS_SLEEPING:
			if (obj != NULL && aon != 1 )
			{
				if (IS_SET(obj->value[2],SLEEP_AT))
				{
					act( AT_ACTION, "You sleep at $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g sleeps at $p.",ch,obj,NULL,TO_ROOM);
				}
				else if (IS_SET(obj->value[2],SLEEP_ON))
				{
					act( AT_ACTION, "You sleep on $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g sleeps on $p.",ch,obj,NULL,TO_ROOM);
				}
				else
				{
					act( AT_ACTION, "You sleep in $p.",ch,obj,NULL,TO_CHAR);
					act( AT_ACTION, "$g sleeps on $p.",ch,obj,NULL,TO_ROOM);
				}
			}
			else if (aon == 1)
			{
				act( AT_ACTION, "You are already using $p for furniture.", ch, obj, NULL, TO_CHAR);
			}
			else if (ch->on != NULL && obj == NULL)
			{
				act( AT_ACTION, "You hop off of $p and try to sleep on the ground.", ch, ch->on, NULL, TO_CHAR);
				act( AT_ACTION, "$g hops off of $p and falls quickly asleep on the ground.", ch, ch->on, NULL, TO_ROOM );
				ch->on = NULL;
			}
			else
				send_to_char( "You are already sleeping.\n\r", ch );
			break;
		case POS_RESTING:
			if ( ch->mental_state > 30 && (number_percent()+10) < ch->mental_state )
			{
				send_to_char( "You just can't seem to calm yourself down enough to sleep.\n\r", ch );
				act( AT_ACTION, "$g closes $s eyes for a few moments, but just can't seem to go to sleep.", ch, NULL, NULL, TO_ROOM );
				return;
			}
			if (obj == NULL)
			{
				send_to_char("You lean your head back more and go to sleep.\n\r",ch);
				act( AT_ACTION, "$g lies back and falls asleep on the ground.",ch,NULL,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],SLEEP_AT))
			{
				act( AT_ACTION, "You sleep at $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sleeps at $p.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],SLEEP_ON))
			{
				act( AT_ACTION, "You sleep on $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sleeps on $p.",ch,obj,NULL,TO_ROOM);
			}
			else
			{
				act( AT_ACTION, "You sleep in $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sleeps in $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_SLEEPING;
			break;
		case POS_SITTING:
			if ( ch->mental_state > 30 && (number_percent()+5) < ch->mental_state )
			{
				send_to_char( "You just can't seem to calm yourself down enough to sleep.\n\r", ch );
				act( AT_ACTION, "$g closes $s eyes for a few moments, but just can't seem to go to sleep.", ch, NULL, NULL, TO_ROOM );
				return;
			}
			if (obj == NULL)
			{
				send_to_char("You lay down and go to sleep.\n\r", ch);
				act( AT_ACTION, "$g lies back and falls asleep on the ground.",ch,NULL,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],SLEEP_AT))
			{
				act( AT_ACTION, "You sleep at $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sleeps at $p.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],SLEEP_ON))
			{
				act( AT_ACTION, "You sleep on $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sleeps on $p.",ch,obj,NULL,TO_ROOM);
			}
			else
			{
				act( AT_ACTION, "You sleep in $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sleeps in $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_SLEEPING;
			break;
		case POS_STANDING:
			if ( ch->mental_state > 30 && number_percent() < ch->mental_state )
			{
				send_to_char( "You just can't seem to calm yourself down enough to sleep.\n\r", ch );
				act( AT_ACTION, "$g closes $s eyes for a few moments, but just can't seem to go to sleep.", ch, NULL, NULL, TO_ROOM );
				return;
			}
			if (obj == NULL)
			{
				send_to_char("You drop down and fall asleep on the ground.\n\r",ch);
				act( AT_ACTION, "$g drops down and falls asleep on the ground.",ch,NULL,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],SLEEP_AT))
			{
				act( AT_ACTION, "You sleep at $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sleeps at $p.",ch,obj,NULL,TO_ROOM);
			}
			else if (IS_SET(obj->value[2],SLEEP_ON))
			{
				act( AT_ACTION, "You sleep on $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sleeps on $p.",ch,obj,NULL,TO_ROOM);
			}
			else
			{
				act( AT_ACTION, "You sleep down in $p.",ch,obj,NULL,TO_CHAR);
				act( AT_ACTION, "$g sleeps down in $p.",ch,obj,NULL,TO_ROOM);
			}
			ch->position = POS_SLEEPING;
			break;
		case POS_FIGHTING:
			send_to_char( "You are already fighting!\n\r", ch );
			break;
		case POS_CARRYING:
			/*******************************************
			 *  Aliana says:                           *
			 *      X sits down placing Y beside them  *
			 *      You sit ( whereever) placing Y beside you
			 *      X sits placing you beside him/her 
			 *******************************************/
			if ( ch->char_carrying != NULL )
			{
				if (obj == NULL)
				{
					act( AT_ACTION, "You sit on the ground, placing $N beside you.", ch, NULL, ch->char_carrying, TO_CHAR);
					act( AT_ACTION, "$g sits down placing $N beside $m.", ch, NULL, ch->char_carrying, TO_VICT );
					act( AT_ACTION, "$g sits placing you beside $m.", ch, NULL, ch->char_carrying, TO_NOTVICT );
					ch->char_carrying->position = POS_SITTING;
				}
				else if (IS_SET(obj->value[2],SIT_AT))
				{
					act( AT_ACTION, "You sit down at $p, placing $N beside you.", ch, obj, ch->char_carrying, TO_CHAR);
					act( AT_ACTION, "$g sits down at $p, placing $N beside $m.", ch, obj, ch->char_carrying, TO_VICT );
					act( AT_ACTION, "$g sits down at $p, placing you beside $m.", ch, obj, ch->char_carrying, TO_NOTVICT );
					ch->char_carrying->on = obj;
					ch->char_carrying->position = POS_SITTING;
				}
				else if (IS_SET(obj->value[2],SIT_ON))
				{
					act( AT_ACTION, "You sit on $p, placing $N beside you.", ch, obj, ch->char_carrying, TO_CHAR);
					act( AT_ACTION, "$g sits on $p, placing $N beside $m.", ch, obj, ch->char_carrying, TO_VICT );
					act( AT_ACTION, "$g sits on $p, placing you beside $m.", ch, obj, ch->char_carrying, TO_NOTVICT );
					ch->char_carrying->on = obj;
					ch->char_carrying->position = POS_SITTING;
				}
				else
				{
					act( AT_ACTION, "You sit down in $p, placing $N beside you.", ch, obj, ch->char_carrying, TO_CHAR);
					act( AT_ACTION, "$g sits down in $p, placing $N beside $m.", ch, obj, ch->char_carrying, TO_VICT );
					act( AT_ACTION, "$g sits down in $p, placing you beside $m.", ch, obj, ch->char_carrying, TO_NOTVICT );
					ch->char_carrying->on = obj;
					ch->char_carrying->position = POS_SITTING;
				}
			}
			else
				send_to_char( "Error - Contact Gavin\n\r", ch);
			if ( ch->char_carriedby != NULL )
			{
				clear_carry(ch->char_carriedby);
				clear_carry(ch->char_carrying);
			}
			ch->position = POS_SITTING;
			break;

    }

    rprog_sleep_trigger( ch );
    return;
}

void do_wake( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    CHAR_DATA *victim;

    one_argument( argument, arg );
    if ( arg[0] == '\0' )
	{ do_stand( ch, argument ); return; }

    if ( !IS_AWAKE(ch) )
	{ send_to_char( "You are asleep yourself!\n\r",       ch ); return; }

    if ( ( victim = get_char_room( ch, arg ) ) == NULL )
	{ send_to_char( "They aren't here.\n\r",              ch ); return; }

	if ( ch->char_carrying != NULL || ch->char_carriedby != NULL )
	{
		send_to_char("Not available while carrying or being carried ( ... Yet - Gavin )\n\r",ch);
		return;
	}

	if ( victim->char_carrying != NULL || victim->char_carriedby != NULL )
	{
		send_to_char("Not available while carrying or being carried ( ... Yet - Gavin )\n\r",ch);
		return;
	}


    if ( IS_AWAKE(victim) )
    { act( AT_PLAIN, "$N is already awake.", ch, NULL, victim, TO_CHAR ); return; }

    if ( IS_AFFECTED(victim, AFF_SLEEP) || victim->position < POS_SLEEPING )
    { act( AT_PLAIN, "You can't seem to wake $M!",  ch, NULL, victim, TO_CHAR );  return; }

    act( AT_ACTION, "You wake $M.", ch, NULL, victim, TO_CHAR );
    victim->position = POS_STANDING;
    act( AT_ACTION, "$g wakes you.", ch, NULL, victim, TO_VICT );
    return;
}


/*
 * "Climb" in a certain direction.				-Thoric
 */
void do_climb( CHAR_DATA *ch, char *argument )
{
    EXIT_DATA *pexit;
    bool found;

    found = FALSE;
    if ( argument[0] == '\0' )
    {
	for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next )
	    if ( IS_SET( pexit->exit_info, EX_xCLIMB ) )
	    {
		move_char( ch, pexit, 0 );
		return;
	    }
	send_to_char( "You cannot climb here.\n\r", ch );
	return;
    }

    if ( (pexit = find_door( ch, argument, TRUE )) != NULL
    &&   IS_SET( pexit->exit_info, EX_xCLIMB ))
    {
	move_char( ch, pexit, 0 );
	return;
    }
    send_to_char( "You cannot climb there.\n\r", ch );
    return;
}

/*
 * "enter" something (moves through an exit)			-Thoric
 */
void do_enter( CHAR_DATA *ch, char *argument )
{
    EXIT_DATA *pexit;
    bool found;

    found = FALSE;
    if ( argument[0] == '\0' )
    {
	for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next )
	    if ( IS_SET( pexit->exit_info, EX_xENTER ) )
	    {
		move_char( ch, pexit, 0 );
		return;
	    }
	send_to_char( "You cannot find an entrance here.\n\r", ch );
	return;
    }

    if ( (pexit = find_door( ch, argument, TRUE )) != NULL
    &&   IS_SET( pexit->exit_info, EX_xENTER ))
    {
	move_char( ch, pexit, 0 );
	return;
    }
    do_board(ch,argument);
    return;
}

/*
 * Leave through an exit.					-Thoric
 */
void do_leave( CHAR_DATA *ch, char *argument )
{
    EXIT_DATA *pexit;
    bool found;

    found = FALSE;
    if ( argument[0] == '\0' )
    {
	for ( pexit = ch->in_room->first_exit; pexit; pexit = pexit->next )
	    if ( IS_SET( pexit->exit_info, EX_xLEAVE ) )
	    {
		move_char( ch, pexit, 0 );
		return;
	    }
	do_leaveship( ch , "" );
	return;
    }

    if ( (pexit = find_door( ch, argument, TRUE )) != NULL
    &&   IS_SET( pexit->exit_info, EX_xLEAVE ))
    {
	move_char( ch, pexit, 0 );
	return;
    }
    do_leaveship( ch, "" );
    return;
}

/* Added 01/21/01 by Drraagh */
void do_run( CHAR_DATA *ch, char *argument )
{
    char arg[MAX_INPUT_LENGTH];
    ROOM_INDEX_DATA *from_room;
    EXIT_DATA *pexit;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	send_to_char( "Run where?\n\r", ch );
	return;
    }

    if ( ch->position != POS_STANDING )
    {
	send_to_char( "You are not in the correct position for that.\n\r", ch );
	return;
    }

    from_room = ch->in_room;

    while ( ( pexit = find_door( ch, arg, TRUE ) ) != NULL )
    {
      if ( ch->move < 1 )
	{
	    send_to_char( "You are too exhausted to run anymore.\n\r", ch );
	    ch->move = 0;
	    break;
	}
	ch->move -= 1;
	if ( move_char( ch, pexit, 0 ) == rSTOP )
	    break;
    }

    if ( ch->in_room == from_room )
    {
	send_to_char( "You try to run but don't get anywhere.\n\r", ch );
	act( AT_ACTION, "$n tries to run but doesn't get anywhere.", ch, NULL, NULL, TO_ROOM );
	return;
    }

    send_to_char( "You slow down after your run.\n\r", ch );
    act( AT_ACTION, "$n slows down after $s run.", ch, NULL, NULL, TO_ROOM );
}