FlCodebase3.1/
FlCodebase3.1/bounty/
FlCodebase3.1/challenge/
FlCodebase3.1/clans/
FlCodebase3.1/gods/
FlCodebase3.1/mobprogs/
FlCodebase3.1/player/
FlCodebase3.1/savemud/
/***************************************************************************
 *  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
 *  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
 *                                                                         *
 *  Merc Diku Mud improvments copyright (C) 1992, 1993 by Michael          *
 *  Chastain, Michael Quan, and Mitchell Tse.                              *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  * 
 *                                                                         *
 *      ROM 2.4 is copyright 1993-1998 Russ Taylor                         *
 *      ROM has been brought to you by the ROM consortium                  *
 *          Russ Taylor (rtaylor@hypercube.org)                            *
 *          Gabrielle Taylor (gtaylor@hypercube.org)                       *
 *          Brian Moore (zump@rom.org)                                     *
 *      By using this code, you have agreed to follow the terms of the     *
 *      ROM license, in the file Rom24/doc/rom.license                     *
 *                                                                         *
 * Code Adapted and Improved by Abandoned Realms Mud                       *
 * and Aabahran: The Forsaken Lands Mud by Virigoth                        *
 *                                                                         *
 * Continued Production of this code is available at www.flcodebase.com    *
 ***************************************************************************/

#include <sys/types.h>
#include <sys/time.h>
#include <stdio.h>
#include <string.h>
#include "merc.h"
#include "interp.h"
#include "jail.h"
#include "cabal.h"
#include "autoquest.h"

char *	const	dir_name	[]		=
{ "north", "east", "south", "west", "up", "down" };

char *	const	shrt_dir_name	[]		=
{ "N", "E", "S", "W", "U", "D" };

char *	const	dir_name2	[]		=
{ "north of you", "east of you", "south of you", "west of you", "above you", "below you" };

const	sh_int	rev_dir		[]		=
{ DIR_SOUTH, DIR_WEST, DIR_NORTH, DIR_EAST, DIR_DOWN, DIR_UP };

const	sh_int	movement_loss	[MAX_SECT]	=
//INSIDE CITY FIELD FORST HILLS MOUNT SWIM NOSWIM SWAMP AIR DESERT LAVA SNOW
{   1,    2,   3,    4,    4,    7,    5,    4,    10,   1,   8,    8,   6 };

extern void dreamprobe_cast( CHAR_DATA* victim, char* msg );

/*room_spec_update*/
/*linked only in handler.c*/
/*returns true if flag was cleared, false otherwise*/
bool room_spec_update(ROOM_INDEX_DATA* in_room)
{
  CHAR_DATA* vch;

  //This function checks the contents of the room
  //in order to decide if the room should be stripped
  //of the spec_flag

  //Eventualy the rooms will have effects attached to themselfs.
  //for now we check each spell individualy.

if (!IS_SET(in_room->room_flags2, ROOM_SPEC_UPDATE))
  return TRUE;

//Begin running through each effect, testing if they cause the flag to stay.
//if test for flag stay is true we return saving more checks.

  /////////FIRESTORM///////////
 for  (vch = in_room->people; vch != NULL; vch = vch->next_in_room) {
  if (is_affected(vch, gen_firestorm) || is_affected (vch, gen_anger))
    return FALSE;
 }

//We strip the effect.
 REMOVE_BIT(in_room->room_flags2, ROOM_SPEC_UPDATE);
 return TRUE;
}//end room_spec_update

int MOVE_CHECK( CHAR_DATA* ch, ROOM_INDEX_DATA** to_room ){
  CHAR_DATA* vch = ch;
  AFFECT_DATA* paf;
  AFFECT_DATA* paf_next;
  int result = 0;
  int fSuccess = TRUE;

  for (paf = vch->affected; paf != NULL; paf = paf_next) {
    paf_next = paf->next;
    //we only run the update once per effect.
    if (paf_next != NULL && paf->type == paf_next->type) {
      continue;
    }

    if (IS_GEN(paf->type)) {
      if ((result = run_effect_update(vch, NULL, *to_room, paf->type, NULL, 
				      NULL, TRUE, EFF_UPDATE_MOVE)) != TRUE) {
	if (result == -1) {
	  return -1;
	}
	else {
	  fSuccess = result;
	}
      }
    }
  }
  return fSuccess;
}

//------PART 2----------/
void do_out(CHAR_DATA *ch, int door)
{
    CHAR_DATA *ich;
    for ( ich = ch->in_room->people; ich != NULL; ich = ich->next_in_room )
    {

	if (ich == ch)
	    continue;
	if (IS_IMMORTAL(ich) && ich->level >= ch->level && IS_SET(ich->act,PLR_HOLYLIGHT))
	  act_new( "$n leaves $t.", ch, dir_name[door], ich, TO_VICT, POS_RESTING + 100 );
	else if (ich->race == grn_feral && IS_AWAKE(ich) && !IS_IMMORTAL(ch)
		 && (IS_AFFECTED(ch, AFF_SNEAK) || ch->class == gcn_ranger)){
	  act_new( "Someone leaves $t.", ch, dir_name[door], ich, TO_VICT, POS_RESTING);
	}
	else if (!IS_IMMORTAL(ch)
		 && is_affected(ich, gsn_sense_motion) 
		 && get_skill(ich,gsn_sense_motion) 
		 > number_percent() && monk_good(ch, WEAR_HEAD) )
	  act_new( "Someone leaves the room.", ch, NULL, ich, TO_VICT, POS_RESTING + 100 );
    }
}

void do_in(CHAR_DATA *ch)
{
    CHAR_DATA *ich;
    for ( ich = ch->in_room->people; ich != NULL; ich = ich->next_in_room )
    {
	if (ich == ch)
	    continue;
	if (IS_IMMORTAL(ich) && ich->level >= ch->level && IS_SET(ich->act,PLR_HOLYLIGHT))
	    act_new( "$n enters the room.", ch, NULL, ich, TO_VICT, POS_RESTING + 100 );
	else if (ich->race == grn_feral && IS_AWAKE(ich) && !IS_IMMORTAL(ch)
		 && (IS_AFFECTED(ch, AFF_SNEAK) || ch->class == gcn_ranger)){
	  send_to_char( "Someone enters the room.\n\r", ich);
	}
	else if (!IS_IMMORTAL(ch)
		 && is_affected(ich, gsn_sense_motion) && get_skill(ich,gsn_sense_motion) > number_percent() && monk_good(ch, WEAR_HEAD) )
	    act_new( "Someone enters the room.", ch, NULL, ich, TO_VICT, POS_RESTING + 100 );
    }
}

bool find_kick_exit(CHAR_DATA *ch, CHAR_DATA *victim)
{
    ROOM_INDEX_DATA *in_room, *to_room;
    EXIT_DATA *pexit;
    bool found = FALSE;
    int i;
    if (ch->in_room == NULL || victim->in_room == NULL)
	return FALSE;
    in_room = ch->in_room;
    to_room = ch->in_room;
    for (i = 0; i < 6; i++)
    {
	if ( ( pexit = in_room->exit[i] ) == NULL || ( to_room = pexit->to_room ) == NULL || !can_see_room(ch,pexit->to_room))
	    continue;
	if (to_room->area != in_room->area)
	{
	    found = TRUE;
	    break;
	}
    }
    if (found)
    {
	do_say(ch,"Ghosts and newbies are not allowed in here!");
	act("$N throws you out of the room!",victim,NULL,ch,TO_CHAR);
	act("$N throws $n out of the room!",victim,NULL,ch,TO_NOTVICT);
	act("You throw $N out of the room!",ch,NULL,victim,TO_CHAR);
	char_from_room(victim);
	char_to_room(victim, to_room);
	act_new( "$n is thrown in.", victim, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	do_look(victim,"auto");
    }
    return found;
}

//////////////////
//vamp_can_sneak//
/////////////////
//Cheks if vampire can sneak in the given room.
//returns true if can.

bool vamp_can_sneak(CHAR_DATA* ch, ROOM_INDEX_DATA* in_room)
{
//IF not vamp, or in mist form or bat form, cannot sneak 
  if (ch->class != class_lookup("vampire"))
    return FALSE;
  if ( (is_affected(ch, gsn_bat_form)) || (is_affected(ch, gsn_mist_form)) )
    return FALSE;

//No we know he is a vamp, and maybe in wolf form
//If is in wolf-form and  is in forest, hills, or 
//mountain then vamp can sneak.

  if ( (is_affected(ch,gsn_wolf_form))
       && (in_room->sector_type == SECT_FOREST 
	   || in_room->sector_type == SECT_HILLS 
	   || in_room->sector_type == SECT_SNOW
	   || in_room->sector_type == SECT_MOUNTAIN 
	   || in_room->sector_type == SECT_FIELD
	   || in_room->sector_type == SECT_DESERT
	   || in_room->sector_type == SECT_SWAMP))
    return TRUE;

//IF not in wolf from, or not in forest like terrain we check for city sneak.
//We already  know he is vamp, not in any of forms so must be human.
//al is left is to check for terrain.

  else if ( (in_room->sector_type == SECT_CITY || in_room->sector_type == SECT_INSIDE) && (!is_affected(ch, gsn_wolf_form)) )
  return  TRUE;

//if non of the above returned true by now, then he cannot sneak.
  return FALSE;
}

/* checks if disguise allowed someone to sneak past the mob */
bool disguise_check( CHAR_DATA* ch, int iClass ){
  AFFECT_DATA* paf;
  if (ch == NULL || iClass < 0 )
    return FALSE;
  else if ( (paf = affect_find(ch->affected, gen_guise)) != NULL
       && iClass == paf->modifier){
    send_to_char("You attempt to sneak past in your disguise.\n\r", ch);
    /* check if disguised thief suceds walkign past */
    if (number_percent() > UMAX(50, get_skill(ch, gsn_sneak) - 5)){
      send_to_char("You got caught!\n\r", ch);
      check_improve(ch, gsn_sneak, FALSE, 35);
      affect_strip(ch, gen_guise);
      return FALSE;
    }
    else{
      check_improve(ch, gsn_sneak, TRUE, 5);
      return TRUE;
    }
  }
  return FALSE;
}
	

void move_char( CHAR_DATA *ch, int door, bool fForce )
{
  AFFECT_DATA *paf, *pRipple = NULL;
  CHAR_DATA *fch, *fch_next, *wch;
  ROOM_INDEX_DATA *in_room, *to_room;
  EXIT_DATA *pexit;
  char buf[MSL];
  bool found = FALSE, condor = FALSE, fEnfeeble = FALSE;
  int i, first = door, second = door, chance = number_percent();
  int cskill = get_skill(ch,gsn_quiet_movement);
  int climb = 0;
  int lag = 1;
  if ( door < 0 || door > 5 )
    {
      bug( "Do_move: bad door %d.", door );
      return;
    }
  if (cskill > 1)
    {
      cskill += 2*(get_curr_stat(ch,STAT_LUCK) - 16);
      if (IS_WEREBEAST(ch->race))
	cskill += 10;
    }
  if(IS_AFFECTED2(ch,AFF_SEVERED))
    {
        send_to_char("But you haven't got any legs!\n\r",ch);
        return;
    }
  //fForce causes us to ignore misdirection
  if (IS_AFFECTED2(ch,AFF_MISDIRECTION) && !fForce)
    {
      for ( paf = ch->affected; paf != NULL; paf = paf->next )
        {
	  if (paf->type == gsn_misdirection && paf->location == APPLY_DEX)
	    first = paf->level;
	  if (paf->type == gsn_misdirection && paf->location == APPLY_INT)
	    second = paf->level;
	}
      if (door == first)
	door = second;
      else if (door == second)
	door = first;
    }
  else if (is_song_affected(ch,gsn_disorient))
    {
      for ( paf = ch->affected2; paf != NULL; paf = paf->next )
        {
	  if (paf->type == gsn_disorient && paf->location == APPLY_DEX)
	    first = paf->level;
	  if (paf->type == gsn_disorient && paf->location == APPLY_INT)
	    second = paf->level;
	}
      if (door == first)
	door = second;
      else if (door == second)
	door = first;
    }
/* catch death shroud move */
  i =0;
  if ( (paf = affect_find(ch->affected, gen_d_shroud)) != NULL){
    run_effect_update(ch, paf, 0, paf->type, &i , NULL, TRUE, 
		      EFF_UPDATE_PRECOMMAND);
  }
  
  in_room = ch->in_room;
  if ( ( pexit = in_room->exit[door] ) == NULL || ( to_room = pexit->to_room ) == NULL || !can_see_room(ch,pexit->to_room))
    {
      send_to_char( "Alas, you cannot go that way.\n\r", ch );
      return;
    }
  if (IS_SET(pexit->exit_info, EX_CLOSED) 
      && ((!IS_AFFECTED(ch, AFF_PASS_DOOR) && !is_ghost(ch,600)) || IS_SET(pexit->exit_info,EX_NOPASS))
      && !IS_TRUSTED(ch,ANGEL))
    {
      act( "The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR );
      return;
    }
  if ( IS_AFFECTED(ch, AFF_CHARM) 
       && ch->master != NULL 
       && in_room == ch->master->in_room 
       && !is_affected(ch,gsn_linked_mind) && !fForce)
    {
      send_to_char( "What?  And leave your beloved master?\n\r", ch );
      return;
    }
  if ( room_is_private( to_room ) )
    {
      send_to_char( "That room is private right now.\n\r", ch );
      return;
    }
  if ( !have_access(ch,to_room))
    {
      send_to_char( "Don't think so.\n\r",ch);
      return;
    }
  if ( IS_SET(to_room->room_flags,ROOM_NO_GHOST) && !IS_IMMORTAL(ch) && is_ghost(ch,600))
    {
      send_to_char("Ghosts are not allowed in there!\n\r",ch);
      return;
    }

  /* CABAL GATE */
  if (ch->incog_level == 0
      && ch->invis_level == 0
      && ch->in_room->pCabal 
      && ch->in_room->pCabal->fGate
      && ch->in_room->pCabal->anchor 
      && ch->in_room == ch->in_room->pCabal->anchor
      && to_room->pCabal){
    if (IS_NPC(ch) && IS_SET(ch->act, ACT_RAIDER)){
      act("$n scales the walls over the gate.", ch, NULL, NULL, TO_ROOM);
    }
    else{
      send_to_char( ch->in_room->pCabal->pIndexData->gate_msg, ch );
      send_to_char("\n\r", ch);
      return;
    }
  }

/* traps */
  if (trip_traps(ch, pexit->traps)){
    //fForce causes us to walk through traps while hitting them
    if (!fForce)
      return;
    //need a pair of special checks since the trap above might not block rest
    //of move after death
    if (ch == NULL || ch->in_room == NULL)
      return;
    else if (is_ghost(ch, 1))
      return;
  }

/* move update */
  if ( MOVE_CHECK(ch, &to_room) == -1)
    bug("Error at: MOVE_CHECK returned failure.\n\r", 0);  

  /* movement restrictions */
  /* Exit Triggers */
  if ( !IS_NPC(ch) && ch->in_room
       && (p_exit_trigger( ch, door, PRG_MPROG )
	   ||  p_exit_trigger( ch, door, PRG_OPROG )
	   ||  p_exit_trigger( ch, door, PRG_RPROG )) )
    return;
  if (ch == NULL || ch->in_room == NULL)
    return;
  /* JAILS (EVERYONE) (Only when moving from non-cell to cell or cell-noncell*/
  if ( (IS_SET(to_room->room_flags2, ROOM_JAILCELL)
	&& !IS_SET(in_room->room_flags2, ROOM_JAILCELL)
	&& jail_check(to_room))
       || (!IS_SET(to_room->room_flags2, ROOM_JAILCELL)
	   && jail_check(in_room)
	   && IS_SET(in_room->room_flags2, ROOM_JAILCELL)) ){
    
    /* stops only Non-Justices, and any wanteds*/
    if (!IS_NPC(ch) && ch->pCabal && IS_CABAL(ch->pCabal, CABAL_JUSTICE)
	&& !IS_IMMORTAL(ch)
	&& !IS_SET(ch->act, PLR_WANTED)){
      AFFECT_DATA* paf;
      /* check for ABUSE_CHECK (on entrance to the cell only)*/
      if ( IS_SET(to_room->room_flags2, ROOM_JAILCELL)
	   && (paf = affect_find(ch->affected, gsn_judge)) != NULL
	   && paf->modifier > ABUSE_CHECK
	   && !IS_IMMORTAL(ch)){
	act("A magical barrier crackles as it stops $n.", ch, NULL, NULL, TO_ROOM);
	act("You've spent too much time in the cells.  Wait a while.", ch, NULL, NULL, TO_CHAR);
	return;
      }
      act("A magical barrier parts about $n.", ch, NULL, NULL, TO_ROOM);
      act("A magical barrier parts about you.", ch, NULL, NULL, TO_CHAR);
    }
    else if (!IS_IMMORTAL(ch)){
      act("A magical barrier crackles as it stops $n.", ch, NULL, NULL, TO_ROOM);
      act("A magical barrier crackles as it stops you.", ch, NULL, NULL, TO_CHAR);
      return;
    }
  }
  
  /* guilds and cabals (PC ONLY)*/
  if ( !IS_NPC(ch)){
      int iClass, iGuild, iJail, move;
      CHAR_DATA *mob;
      bool fbloody = FALSE, fguild = FALSE;
      
      if (!IS_NPC(ch) && !IS_IMMORTAL(ch)){
	int class = ch->class;
	int dkClass = class_lookup("dark-knight");
	bool fJustice = (ch->pCabal && IS_CABAL(ch->pCabal, CABAL_JUSTICE) && IS_AREA(ch->in_room->area, AREA_LAWFUL));
	if (IS_SET(to_room->room_flags2, ROOM_GUILD_ENTRANCE)){
	  for ( iClass = 0; class_table[iClass].name != NULL && iClass < MAX_CLASS; iClass++ ){
	    for ( iGuild = 0; iGuild < MAX_GUILD; iGuild ++) {
	      if ( to_room->vnum == class_table[iClass].guild[iGuild]){
		fbloody = TRUE;
		if (is_exiled(ch, ch->in_room->area->vnum))
		  continue;
		if (disguise_check( ch, iClass )){
		  fguild = TRUE;
		}
		else if ((iClass == class 
			  || (IS_MASQUE(ch) && iClass == dkClass)
			  || fJustice)
			 && (!IS_SET(ch->act,PLR_OUTCAST) || fJustice))
		  fguild = TRUE;
	      }
	    }
	  }
	}//END guilds
	/* check for jail */
	for ( iJail = 0; jail_table[iJail].name != NULL && iJail < MAX_HOMETOWN; iJail++ ){
	  if (!IS_IMMORTAL(ch))
	    break;
	  if (to_room->vnum == jail_table[iJail].entrance){
	    if (ch->pCabal == NULL || !IS_CABAL(ch->pCabal, CABAL_JUSTICE)
		|| IS_WANTED(ch))
	      fguild = FALSE;
	    else
	      fguild = TRUE;
	    fbloody = TRUE;
	    break;
	  }
	}//END jails
	if (ch->class == gcn_adventurer)
	  fguild = TRUE;
	if (fbloody && !fguild){
	  for (mob = ch->in_room->people; mob != NULL; mob = mob->next_in_room)
	    if (IS_NPC(mob) && IS_SET(mob->off_flags,GUILD_GUARD))
	      {
		mprog_guild_trigger(mob,ch);
		return;
	      }
	}
	else if (fbloody && is_fight_delay(ch,90)){
	  for (mob = ch->in_room->people; mob != NULL; mob = mob->next_in_room)
	    if (IS_NPC(mob) && IS_SET(mob->off_flags,GUILD_GUARD))
	      {
		mprog_bloody_trigger(mob,ch);
		return;
	      }
	}
	else if (fbloody && ch->pCabal && IS_CABAL(ch->pCabal, CABAL_JUSTICE)){
	  for (mob = ch->in_room->people; mob != NULL; mob = mob->next_in_room)
	    if (IS_NPC(mob) && IS_SET(mob->off_flags,GUILD_GUARD))
	      {
		mprog_justice_trigger(mob,ch);
		break;
	      }
	}
      }
      
      if (!IS_NPC(ch))
	climb =  get_skill(ch,gsn_climb);
      else
	climb = 0;

      if ( in_room->sector_type == SECT_AIR || to_room->sector_type == SECT_AIR )
	{
	  if ( !(IS_AFFECTED(ch, AFF_FLYING) && !is_affected(ch,gsn_thrash)) && !IS_IMMORTAL(ch) && !is_ghost(ch,600)){
	    if ( climb > 0)
	      {
		send_to_char("You attempt to climb in that direction.\n\r", ch);
		if (number_percent() > 2 * climb / 3)
		  {
		    send_to_char("You failed to find a path.\n\r", ch);
		    WAIT_STATE2(ch,skill_table[gsn_climb].beats);
		    check_improve(ch, gsn_climb, FALSE, 1);
		    return;
		  }
		if (ch->mana < 4){
		  send_to_char("You lack the concentration required.\n\r", ch);
		  return;
		}
		WAIT_STATE2(ch,skill_table[gsn_climb].beats);
		ch->mana -= 4;
		check_improve(ch, gsn_climb, TRUE, 1);		
	      }
	    else if (is_affected(ch, gsn_sretrib)){
	      send_to_char("You attempt to climb in that direction.\n\r", ch);
	      if (ch->mana < 1){
		send_to_char("You lack the concentration required.\n\r", ch);
		return;
	      }
	      ch->mana -= 1;
	      }
	      else if (is_song_affected(ch,gsn_condor))
		{
		  condor = TRUE;
		  song_strip(ch,gsn_condor);
		  sendf(ch,"A large condor swoops in and carries you %s.\n\r",dir_name[door]);
		}
	      else
		{
		  send_to_char( "You can't fly.\n\r", ch );
		  return;
		}
	    }
	}
      if (( in_room->sector_type == SECT_WATER_NOSWIM || to_room->sector_type == SECT_WATER_NOSWIM )
	  && !(IS_AFFECTED(ch,AFF_FLYING) && !is_affected(ch,gsn_thrash)) && !is_ghost(ch,600)
	  && !IS_SET(ch->form, FORM_AMPHIBIAN) && !IS_SET(ch->form, FORM_FISH))
	{
	  OBJ_DATA *obj;
	  bool found;
	  found = FALSE;
	  if (is_song_affected(ch,gsn_condor))
	    {
	      found = TRUE;
	      condor = TRUE;
	      song_strip(ch,gsn_condor);
	      sendf(ch,"A large condor swoops in and carries you %s.\n\r",dir_name[door]);
	    }
	  else if (IS_IMMORTAL(ch))
	    found = TRUE;
	  else if (is_affected(ch, gsn_sretrib)){
	    send_to_char("You attempt to swim in that direction.\n\r", ch);
	    if (ch->mana < 1){
	      send_to_char("You lack the concentration required.\n\r", ch);
	      return;
	    }
	    ch->mana -= 1;
	  }
	  else
	    {
	      for ( obj = ch->carrying; obj != NULL; obj = obj->next_content )
		{
		  if ( obj->item_type == ITEM_BOAT ) 
		    {
		      found = TRUE;
		      break;
		    }
		}
	    }
	  if ( !found && ch->race != race_lookup("storm"))
	    {
	      send_to_char( "You need a boat to go there.\n\r", ch );
	      return;
	    }
	}
      if ( is_affected(ch, gsn_cognizance) || is_affected(ch, gsn_sretrib))
    	{
	  for ( i = 0; i <= 5; i++ )
	    if (to_room->exit[i] != NULL)
	      found = TRUE;
	  if ( !found )
	    {
	      send_to_char("You sense danger in that direction.\n\r",ch);
	      return;
	    }
        }
      if (is_affected(ch,gen_ensnare) && in_room->area != to_room->area)
	{
	  send_to_char("As you approach a host of guards come into view.  To proceed would be certain death!\n\r",ch);
	  return;
	}
      else if (is_affected(ch,gsn_tarot) && tarot_find(ch->affected) == 6 && in_room->area != to_room->area)
	{
	  send_to_char("You have been restricted to this area by your fate!\n\r",ch);
	  return;
	}
      
      move = (movement_loss[UMIN(MAX_SECT-1, in_room->sector_type)] + movement_loss[UMIN(MAX_SECT-1, to_room->sector_type)])/2;
      
      /* check for forest walk */
      if (ch->class == gcn_ranger && to_room->sector_type == SECT_FOREST){
	if ( number_percent() < get_skill(ch, gsn_forest_walk)){
	  check_improve(ch, gsn_forest_walk, TRUE, 1);
	  move = move / 2;
	}
      }

      /* if they can climb, max cost of 4, and 3 if it was 4 */
      if (move >  3 && number_percent() < climb){
	if (move == 4) 
	  move = 3;
	else
	  move = 4;
	check_improve(ch, gsn_climb, TRUE, 1);
      }
      if (is_affected(ch, gsn_sretrib)){
	if (move > 2) 
	  move = 2;
      }

      if (is_affected(ch, gsn_caltraps)){
	fEnfeeble = TRUE;
	move = 2 * move;
      }
      else if (is_affected(ch, gsn_enfeeblement )){
	fEnfeeble = TRUE;
	move *= 2;
      }
      if (IS_AFFECTED(ch, AFF_PLAGUE))
	fEnfeeble = TRUE;

      if (IS_AFFECTED(ch,AFF_SLOW))
	move *= 2;
      if (is_affected(ch, gsn_sneak))
	move *= 2;

/* fly/haste */
      if (IS_AFFECTED(ch,AFF_HASTE))
	move /= 2;
      else if (!IS_NPC(ch) && IS_AFFECTED(ch,AFF_FLYING) 
	       && !is_affected(ch,gsn_thrash) ){
	move /= 2;
      }
      /* if they ghost max move cost of 3 */
      if (move > 3 && is_ghost(ch, 600))
	move = 3;

      /* CABAL */   
      if (move > 2 && ch->in_room && ch->in_room->area->pCabal){
	/* warmaster lowers movement cost by 1 */
	if (!str_cmp(ch->in_room->area->pCabal->name, "Warmaster") 
	    && !class_table[ch->class].fMana 
	    && !class_table[ch->class].sMana)
	  move -= 1;
      }

      if (!IS_NPC(ch) && !IS_AFFECTED(ch,AFF_FLYING) 
	  && ch->pcdata->pStallion != NULL){
	if ( IS_SET(ch->pcdata->pStallion->affected_by, AFF_FLYING)
	     || (ch->pet && ch->pet->pIndexData == ch->pcdata->pStallion
		 && IS_AFFECTED(ch->pet, AFF_FLYING))
	     ){
	  move = UMAX(1, move / 2);
	}
	else
	  move = UMAX(movement_loss[SECT_INSIDE], move - 2);
      }
      if (!fEnfeeble){
	if ( move > 2 && is_affected(ch,gen_crusade))
	  move = 2;
	if ( move > 1 && is_affected(ch,gsn_heroism) )
	  move = 1;
	else if ( move > 1 && is_affected(ch,gen_avenger) )
	  move = 1;
      }
      if (condor || IS_NPC(ch))
	move = 1;

      //INSTEAD OF MOVE LAG, MIST OFRM TAKES MORE MOVS
      if (is_affected(ch,gsn_mist_form))
	move *= 2;

      //MOVEMEN LAG (WORST TO LEAST LAG PENALTY):	   
      if (IS_AFFECTED2(ch, AFF_HOLD)){
	send_to_char("You can barely move.\n\r",ch);
	lag *=6;
	move *=3;
      }
      else if (is_affected(ch, gsn_ghoul_touch)){
	send_to_char("You feel sluggish.\n\r",ch);
	lag *=3;
	move *=3;
      }
      else if (is_affected(ch, gsn_paralyze)){
	lag *=3;
	move *=3;
      }
      else if (is_affected(ch, gsn_webbing)){
	lag *= 2;
	move *= 2;
      }

      if ( ch->move < move && !IS_IMMORTAL(ch)){
	send_to_char( "You are too exhausted.\n\r", ch );
	return;
      }
      else if (!IS_IMMORTAL(ch) ){
	ch->move -= UMAX(1, move);
      }
      WAIT_STATE( ch, lag );
      
      //ADDITIONAL MOVEMENT LAGS DUE TO EFFECTS 
      if (is_affected(ch,gsn_trap_silvanus))
        {
	  send_to_char("Your trap falls apart!\n\r",ch);
	  WAIT_STATE(ch,24);
	  affect_strip(ch,gsn_trap_silvanus);
        } 
      if (is_affected(ch,gsn_deadfall))
        {
          send_to_char("Your deadfall loses its potency.\n\r",ch);
          WAIT_STATE(ch,24);
          affect_strip(ch,gsn_deadfall);
        }
      if (is_affected(ch,gsn_kinetics))
	{
	  move *= 2;
	  ch->mana += URANGE(0, move/3, ch->max_mana - ch->mana);
	}
  }
  if (!IS_NPC(ch) && is_affected(ch,gsn_pixie_dust) && number_percent() < 50)
    {
      OBJ_DATA *obj, *gobj;
      char obuf[MSL];
      send_to_char("You shed off some pixie dust.\n\r",ch);
      act("A bit of pixie dust sheds off $n.",ch,NULL,NULL,TO_ROOM);
      obj = create_object( get_obj_index( OBJ_VNUM_PIXIE_DUST ), ch->level);
      free_string(obj->description);
      sprintf(obuf,"A trail of pixie dust leading %s.", dir_name[door]);
      obj->description = str_dup( obuf );
      obj->timer = 2;
      for ( gobj = ch->in_room->contents; gobj != NULL; gobj = gobj->next_content )
        {
	  if (gobj->pIndexData->vnum == OBJ_VNUM_PIXIE_DUST)
	    {
	      obj_from_room( gobj );
	      extract_obj(gobj);
	    }
	}
      obj_to_room(obj, ch->in_room);
    }

  if ( IS_AFFECTED(ch, AFF_HIDE) 
       && to_room->sector_type != SECT_CITY
       && to_room->sector_type != SECT_INSIDE 
       && to_room->sector_type != SECT_FIELD)
    {
      affect_strip( ch, gsn_hide );
      REMOVE_BIT   ( ch->affected_by, AFF_HIDE		);
      act("You step out of the shadows.",ch,NULL,NULL,TO_CHAR);
      act("$n steps out of the shadows.",ch,NULL,NULL,TO_ROOM);
    }
  if ( IS_AFFECTED2(ch, AFF_CAMOUFLAGE) 
       && to_room->sector_type != SECT_FOREST 
       && to_room->sector_type != SECT_HILLS 
       && to_room->sector_type != SECT_SNOW 
       && to_room->sector_type != SECT_FIELD
       && to_room->sector_type != SECT_MOUNTAIN)
    {
      affect_strip( ch, gsn_camouflage );
      REMOVE_BIT   ( ch->affected2_by, AFF_CAMOUFLAGE		);
      act("You step out from your cover.",ch,NULL,NULL,TO_CHAR);
      act("$n steps out from $s cover.",ch,NULL,NULL,TO_ROOM);
    }
/* stallions do not make for sneaking */
  if ( !IS_NPC(ch) && ch->pcdata->pStallion != NULL && ch->invis_level <= LEVEL_HERO){
    bool fFly = FALSE;
    if (IS_AFFECTED(ch, AFF_HIDE)){
      affect_strip( ch, gsn_hide );
      REMOVE_BIT   ( ch->affected_by, AFF_HIDE		);
      act("You step out of the shadows.",ch,NULL,NULL,TO_CHAR);
      act("$n steps out of the shadows.",ch,NULL,NULL,TO_ROOM);
    }
    if (IS_AFFECTED2(ch,AFF_CAMOUFLAGE) ){
      if (chance > cskill ){
	affect_strip(ch,gsn_camouflage);
	REMOVE_BIT (ch->affected2_by, AFF_CAMOUFLAGE);
	act("You step out from your cover.",ch,NULL,NULL,TO_CHAR);
	act("$n steps out from $s cover.",ch,NULL,NULL,TO_ROOM);
	if (get_skill(ch,gsn_quiet_movement) != 0)
	  check_improve(ch,gsn_quiet_movement,FALSE,0);
      }
      else if (get_skill(ch,gsn_quiet_movement) > 1)
	check_improve(ch,gsn_quiet_movement,TRUE,0);
    }
    /* check if the stallion flies in */
    if (IS_SET(ch->pcdata->pStallion->affected_by, AFF_FLYING)
	|| (ch->pet && ch->pet->pIndexData == ch->pcdata->pStallion && IS_AFFECTED(ch->pet, AFF_FLYING)) )
      fFly = TRUE;
    act_new( "$n $t $T.", ch, fFly ? "flies" : "rides", dir_name[door], TO_ROOM, POS_RESTING + 100 );
  }
  else if (!(!IS_NPC(ch) && IS_SET(ch->act2,PLR_NOWHO)) && ch->invis_level <= LEVEL_HERO)
    {
      if (!IS_AFFECTED(ch, AFF_SNEAK) 
	   && IS_AFFECTED(ch, AFF_HIDE)
	  && !sneak_fade_check(ch))
    	{
	  affect_strip( ch, gsn_hide );
	  REMOVE_BIT   ( ch->affected_by, AFF_HIDE		);
	  act("You step out of the shadows.",ch,NULL,NULL,TO_CHAR);
	  act("$n steps out of the shadows.",ch,NULL,NULL,TO_ROOM);
    	}
      if (IS_AFFECTED2(ch,AFF_CAMOUFLAGE) )
	{
	  if (cskill < 2 || (chance > cskill && sneak_fade_check(ch)) )
	    {
	      affect_strip(ch,gsn_camouflage);
	      REMOVE_BIT (ch->affected2_by, AFF_CAMOUFLAGE);
	      act("You step out from your cover.",ch,NULL,NULL,TO_CHAR);
	      act("$n steps out from $s cover.",ch,NULL,NULL,TO_ROOM);
	      if (get_skill(ch,gsn_quiet_movement) != 0)
		check_improve(ch,gsn_quiet_movement,FALSE,0);
	    }
	  else if (get_skill(ch,gsn_quiet_movement) != 0)
	    check_improve(ch,gsn_quiet_movement,TRUE,0);
	}
    
      
      //This bit here checks for atuo sneak for rangers.
      if ( (to_room->sector_type != SECT_FOREST 
	    && to_room->sector_type != SECT_HILLS 
	    && to_room->sector_type != SECT_SNOW
	    && to_room->sector_type != SECT_MOUNTAIN ) 
	   || (chance > cskill 
	       && !is_affected(ch,gsn_wolf_form)) 
	   || IS_AFFECTED(ch,AFF_FAERIE_FIRE) 
	   || IS_AFFECTED(ch,AFF_FAERIE_FOG) )
	{
	  //If character is not a ranger sneking, we are going to test for sneaking vamp 
	  if(!IS_AFFECTED(ch, AFF_SNEAK) 
	     && !vamp_can_sneak(ch, to_room) 
	     && !sneak_fade_check(ch))
	    {
	      //if the vamp cant sneak in here, then we show him walking out.
	      if (condor)
		act_new( "$n is carried $T by a large condor.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if (IS_NPC(ch) && ch->pIndexData->vnum == MOB_VNUM_VAPOR)
		act_new( "$n floats $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if (IS_NPC(ch) && ch->pIndexData->vnum == MOB_VNUM_SOLID)
		act_new( "$n flows $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if (IS_AFFECTED(ch, AFF_FLYING) && !is_affected(ch,gsn_thrash))
		act_new( "$n flies $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if (is_affected(ch,gsn_mist_form))
		act_new( "$n floats $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if ( in_room->sector_type == SECT_WATER_SWIM )
		act_new( "$n swims $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if ( in_room->sector_type == SECT_WATER_NOSWIM )
		act_new( "$n floats $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if (ch->max_hit != 0 && ch->hit*100/ch->max_hit <= 5)
		act_new( "$n crawls $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if ( in_room->sector_type == SECT_MOUNTAIN || in_room->sector_type == SECT_AIR )
		act_new( "$n climbs $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if (ch->max_hit != 0 && ch->hit*100/ch->max_hit <= 20)
	        act_new( "$n limps $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if (is_affected(ch,gsn_caltraps))
		act_new( "$n limps $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else if (is_affected(ch,gsn_entangle))
		act_new( "$n trails vines $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	      else
		act_new( "$n walks $T.", ch, NULL, dir_name[door], TO_ROOM, POS_RESTING + 100 );
	    }//END IF(!vamp_can_sneak
	}//END IF( sector_>..(the ranger check)
      //do_out simply sendsout message to those that can sense sneak
      do_out(ch, door);
    }//END if NOT AFFECTED BY SNEAK
  else
    //do_out simply sendsout message to those that can sense sneak 
    do_out(ch, door);


  //change the actual position of the character
  char_from_room( ch );
/* check if any updates killed the char etc. */
  if (ch == NULL || ch->extracted)
    return;
/* ripple effect */
  if ( !IS_NPC(ch) 
       && (pRipple = affect_find(ch->affected, gsn_ripple)) != NULL
       && number_percent() < 50){
    to_room = in_room;
    --pRipple->modifier;
  }

  char_to_room( ch, to_room );
/* strip ripple if run down */
  if (pRipple && pRipple->modifier < 0){
    act(skill_table[gsn_ripple].msg_off, ch, NULL, NULL, TO_CHAR);
    act(skill_table[gsn_ripple].msg_off2, ch, NULL, NULL, TO_ROOM);
    affect_strip(ch, gsn_ripple);
  }
  
/* check if any updates killed the char etc. */
  if (ch->extracted || ch->in_room == NULL)
    return;
  if ( !IS_NPC(ch) && ch->pcdata->pStallion != NULL && ch->invis_level <= LEVEL_HERO){
    bool fFly =  FALSE;
    if (IS_SET(ch->pcdata->pStallion->affected_by, AFF_FLYING)
	|| (ch->pet && ch->pet->pIndexData == ch->pcdata->pStallion && IS_AFFECTED(ch->pet, AFF_FLYING)) )
      fFly = TRUE;
    act_new( "$n $t in.", ch, fFly ? "flies" : "rides", NULL, TO_ROOM, POS_RESTING + 100 );
  }
  else
    { 
      if ( !IS_AFFECTED(ch, AFF_SNEAK) 
	   && !(!IS_NPC(ch) 
		&& IS_SET(ch->act2,PLR_NOWHO)) 
	   && ch->invis_level <= LEVEL_HERO 
	   && ((to_room->sector_type != SECT_FOREST 
		&& to_room->sector_type != SECT_HILLS 
		&& to_room->sector_type != SECT_SNOW 
		&& to_room->sector_type != SECT_MOUNTAIN )  
	       || chance > cskill 
	       || (!IS_SET(race_table[ch->race].aff,AFF_SNEAK)
		   && (IS_AFFECTED(ch,AFF_FAERIE_FIRE) 
		       || IS_AFFECTED(ch,AFF_FAERIE_FOG)) ) ))
	{
	  //Since he is not ranger, or cannot sneak in forest, we check for vampire sneak
	  if(!vamp_can_sneak(ch, to_room) && !sneak_fade_check(ch))
	    {
	      if (condor)
		act_new( "$n is carried in by a large condor.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if (IS_NPC(ch) && ch->pIndexData->vnum == MOB_VNUM_VAPOR)
		act_new( "$n floats in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if (IS_NPC(ch) && ch->pIndexData->vnum == MOB_VNUM_SOLID)
		act_new( "$n flows in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if (IS_AFFECTED(ch, AFF_FLYING) && !is_affected(ch,gsn_thrash))
		act_new( "$n flies in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if (is_affected(ch,gsn_mist_form))
		act_new( "$n floats in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if ( to_room->sector_type == SECT_WATER_SWIM )
		act_new( "$n swims in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if ( to_room->sector_type == SECT_WATER_NOSWIM )
		act_new( "$n floats in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if (ch->max_hit != 0 && ch->hit*100/ch->max_hit <= 5)
		act_new( "$n crawls in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if ( to_room->sector_type == SECT_MOUNTAIN || to_room->sector_type == SECT_AIR )
		act_new( "$n climbs in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if (ch->max_hit != 0 && ch->hit*100/ch->max_hit <= 20)
		act_new( "$n limps in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if (is_affected(ch,gsn_caltraps))
		act_new( "$n limps in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else if (is_affected(ch,gsn_entangle))
		act_new( "$n limps in, trailing vines.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	      else
		act_new( "$n walks in.", ch, NULL, NULL, TO_ROOM, POS_RESTING + 100 );
	    }//END If(!vamp_Can_sneak
	  do_in(ch);
	}//END Ranger check
      else
	//do_in makes sure characrters who can, see sneakers.
	do_in(ch);
    }
  /* check for anger after entering */
  if (is_affected(ch, gen_anger)){
    run_effect_update(ch, NULL, to_room, gen_anger, NULL, NULL, TRUE, EFF_UPDATE_INIT);
    if (ch == NULL || ch->in_room == NULL)
      return;
  }
  do_look( ch, "auto" );

  /* tracks */
  if (!IS_NPC(ch) 
      && to_room->sector_type != SECT_WATER_SWIM
      && to_room->sector_type != SECT_WATER_NOSWIM
      && to_room->sector_type != SECT_AIR){
    to_room->tracks[anatomy_lookup(pc_race_table[ch->race].anatomy)] = mud_data.current_time;
  }

  if (condor)
    act("A large condor soars away.",ch,NULL,NULL,TO_ALL);
  if (in_room == to_room)
    return;
  if (!IS_NPC(ch) && vamp_check(ch) && !is_ghost(ch,600)
      && (ch->tattoo != deity_lookup("cycle") || mud_data.time_info.hour == 12))
    {
      send_to_char("You skin burns from exposure to the sunlight.\n\r",ch);
      ch->move -= ch->level/10;
      if (!is_affected(ch,gsn_drained))
	{
	  AFFECT_DATA af;
	  send_to_char("You feel weak...\n\r",ch);
	  af.where            = TO_AFFECTS;
	  af.type             = gsn_drained;
	  af.level            = ch->level;
	  af.duration         = -1;
	  af.location         = 0;
	  af.modifier         = 0;
	  af.bitvector        = 0;
	  affect_to_char(ch,&af);   
	}
      damage(ch,ch,ch->level/10,1052,DAM_LIGHT,TRUE);
    }
  for ( fch = in_room->people; fch != NULL; fch = fch_next )
    {
      fch_next = fch->next_in_room;
      if (fch->in_room == to_room)
	continue;
      if ( fch->master == ch && IS_AFFECTED(fch,AFF_CHARM) && fch->position < POS_STANDING)
	do_stand(fch,"");
      if (IS_SET(fch->special,SPECIAL_SENTINEL) || IS_SET(fch->special,SPECIAL_COWARD))
	continue;
      if (is_affected(fch,gsn_linked_mind))
	continue;
      if ( fch->master == ch 
	   && fch != ch 
	   && fch->position == POS_STANDING 
	   && can_see_room(fch,to_room))
	{
	  sendf(fch, "You follow %s.\n\r", PERS(ch,fch));
	  move_char( fch, door, TRUE );
	}
      else if ( is_song_affected(fch,gsn_lust) && !IS_AFFECTED(fch,AFF_CHARM)
		&& ((fch->sex == 1 && ch->sex == 2) || (fch->sex == 1 && ch->sex == 2))
		&& number_percent() < 10 && can_see_room(fch,to_room))
	{
	  if (fch->position < POS_STANDING)
	    do_stand(fch,"");
	  sendf(fch, "You scurry after %s lustfully.\n\r", PERS(ch,fch));
	  move_char( fch, door, TRUE );
	  act("$N stares at you with a lustful grin.",ch,NULL,fch,TO_CHAR);
	  act("You stare at $n lustfully.",ch,NULL,fch,TO_VICT);
	  act("$N stares at $n with a lustful grin.",ch,NULL,fch,TO_NOTVICT);
	}
    }
  
  mprog_entry_trigger( ch );
  if (ch == NULL || ch->in_room == NULL || ch->in_room != to_room )
    return;
  mprog_greet_trigger( ch );
  if (ch == NULL || ch->in_room == NULL || ch->in_room != to_room )
    return;

  if ( (!IS_NPC( ch ) || ch->trust == 6969) && ch->in_room){
    p_greet_trigger( ch, PRG_MPROG );
    if (ch == NULL || ch->extracted || ch->in_room == NULL || ch->in_room != to_room )
      return;
    p_greet_trigger( ch, PRG_OPROG );
    if (ch == NULL || ch->extracted || ch->in_room == NULL || ch->in_room != to_room )
      return;
    p_greet_trigger( ch, PRG_RPROG );
    if (ch == NULL || ch->extracted || ch->in_room == NULL || ch->in_room != to_room )
      return;
  }
  if (ch == NULL || ch->extracted || ch->in_room == NULL || ch->in_room != to_room )
    return;

  if ( IS_NPC( ch ) && ch->in_room && HAS_TRIGGER_MOB( ch, TRIG_ENTRY )){
    p_percent_trigger(ch, NULL, NULL, ch, NULL, NULL, TRIG_ENTRY);
  }
  if (ch == NULL || ch->in_room == NULL || ch->in_room != to_room )
    return;

  /* quest check */
  QuestRoomCheck( ch, ch->in_room );

  /* CABAL GUARD YELLS */
  if (!IS_IMMORTAL(ch) && !IS_NPC(ch) 
      && ch->in_room->pCabal 
      && ch->in_room->pCabal->anchor
      && ch->in_room->pCabal->anchor == ch->in_room
      && ch->in_room->pCabal->guard
      && IS_CABAL(ch->in_room->pCabal, CABAL_GUARDMOB)){
    for ( fch = ch->in_room->people; fch != NULL; fch = fch_next ){
      fch_next = fch->next_in_room;
      if (IS_NPC(fch) && IS_AWAKE(fch) 
	  && !IS_AFFECTED(fch,AFF_CHARM) 
	  && !IS_AFFECTED2(fch,AFF_HOLD)
	  && IS_SET(fch->off_flags,CABAL_GUARD) 
	  && fch->pCabal
	  && fch->pCabal->guard
	  && fch->pCabal->guard == fch->pIndexData
	  && ch->pCabal
	  && !is_captured_by(ch->pCabal, fch->pCabal)	  
	  && is_friendly( fch->pCabal, ch->pCabal ) == CABAL_ENEMY){
	sprintf(buf, "%s: Alert! %s%s%s`$%s sighted at our gates!``",
		PERS2( fch), 
		PERS(ch,fch),
		ch->pCabal ? " of [" : "",
		ch->pCabal ? ch->pCabal->who_name : "",
		ch->pCabal ? "]" : "");

	cabal_echo( fch->pCabal, buf );
	multi_hit( fch, ch, TYPE_UNDEFINED );
	break;
      }
    }
  }
  if (!IS_NPC(ch)){
    for (wch = to_room->people;wch != NULL;wch = wch->next_in_room){
      CHAR_DATA *victim;
      victim     = ch;
      if (ch == wch)
	continue;
      if ( !IS_NPC(wch) 
	   && wch->fighting == NULL 
	   && IS_AWAKE(wch) 
	   && !IS_AFFECTED(wch,AFF_CALM)
	   && victim->position > POS_SITTING
	   && !is_area_safe_quiet(wch,victim) 
	   && is_affected(wch,gsn_deadfall) )
	
	{
	  AFFECT_DATA naf;
	  if (number_percent() < get_skill(wch,gsn_deadfall)){
	    if (!IS_AFFECTED(victim,AFF_FLYING) 
		|| is_affected(victim,gsn_thrash)
		|| number_percent() < 20){
	      sprintf(buf,"Help! I'm caught in %s's deadfall!",PERS(wch,victim));
	      j_yell(victim,buf);          
	      act("You `1BRUTALIZE`` $N in your deadfall!",wch,NULL,victim,TO_CHAR);
	      act("$n `1BRUTALIZES`` $N in $S deadfall!",wch,NULL,victim,TO_NOTVICT);
	      act("You are `1BRUTALIZED`` by $n's deadfall!",wch,NULL,victim,TO_VICT);
	      if (!IS_AFFECTED(victim,AFF_FLYING) 
		  || is_affected(victim,gsn_thrash)
		  ){
		act("You can't move an inch!",wch,NULL,victim,TO_VICT);
		damage(ch,ch,40,gsn_deadfall,DAM_BASH,TRUE);
		victim->position = POS_SLEEPING;
		naf.where     = TO_AFFECTS;
		naf.type      = gsn_deadfall;
		naf.level     = wch->level;
		naf.duration  = number_range(0, 3);
		naf.location  = APPLY_NONE;
		naf.modifier  = 0;
		naf.bitvector = AFF_SLEEP;
		affect_to_char( victim, &naf );
		if ( IS_AWAKE(victim) )
		  {
		    send_to_char( "You are unconscious!\n\r", victim );
		  }
	      }
	      else{
		act("You manage to avoid $N's deadfall but it stuns you.", victim, NULL, wch, TO_CHAR);
		act("$n avoids your deadfall but it stuns $m.", victim, NULL, wch, TO_ROOM);
		victim->position = POS_RESTING;
		set_delay(wch,victim);
		WAIT_STATE2(victim,24);
	      }
	    }
	    else
	      {
		act("Your deadfall releases!",wch,NULL,NULL,TO_CHAR);
		act("$n's deadfall releases!",wch,NULL,NULL,TO_ROOM);
		WAIT_STATE(wch,24);
	      }
	  }
	}
      
      if ( !IS_NPC(wch) && is_affected(wch,gsn_trap_silvanus) && wch->fighting == NULL && IS_AWAKE(wch) &&!IS_AFFECTED(wch,AFF_CALM)
	   && !is_area_safe_quiet(wch,victim) && !(IS_AFFECTED(victim,AFF_FLYING) && !IS_AFFECTED(victim,gsn_thrash))
	   && victim->position > POS_SITTING)
	{
	  AFFECT_DATA naf;
	  if (number_percent() < get_skill(wch,gsn_trap_silvanus))
	    {
	      sprintf(buf,"Help! I've fallen into %s's trap!",PERS(wch,victim));
	      j_yell(victim,buf);
	      if (number_percent() < get_skill(victim, gsn_balance)/2 && is_empowered_quiet(victim,1) && victim->mana > 0)
		{
		  act("$N steps on your trap but $E keeps $S balance!",wch,NULL,victim,TO_CHAR);
		  act("$N steps on $n's trap but keeps $S balance!",wch,NULL,victim,TO_NOTVICT);
		  act("$n ensnares you in $s trap but you manage to stay balanced!",wch,NULL,victim,TO_VICT);
		  check_improve(victim,gsn_balance,TRUE,5);
		  victim->mana -= URANGE(0,25,victim->mana);
		}        
	      else
		{
		  act("Your trap sends $N to the ground!",wch,NULL,victim,TO_CHAR);
		  act("$n's trap sends $N to the ground!",wch,NULL,victim,TO_NOTVICT);
		  act("$n's trap sends you to the ground!",wch,NULL,victim,TO_VICT);
		  victim->position = POS_RESTING;
		  set_delay(wch,victim);
		  WAIT_STATE2(victim,24);
		}
	    }
	  else
	    {
	      act("Your trap comes apart in your face!",wch,NULL,NULL,TO_CHAR);
	      act("$n's trap comes apart in $s face!",wch,NULL,NULL,TO_ROOM);
	      wch->position = POS_RESTING;
	      WAIT_STATE(wch,24);
	    }               
	  affect_strip(wch,gsn_trap_silvanus);
	  naf.where            = TO_AFFECTS;
	  naf.type             = gsn_wire_delay;
	  naf.level            = wch->level;
	  naf.duration         = 15 - (wch->level/10);
	  naf.location         = 0;
	  naf.modifier         = 0;
	  naf.bitvector        = 0;
	  affect_to_char(wch,&naf);
	  break;
	} 
    }
  }
  if (ch->in_room && IS_SET(ch->in_room->room_flags2, ROOM_PSI_FEAR))
    effect_field_of_fear(ch);

/* after all that, assuming we are alive we check if we should draw weapons */
  if (IS_GAME(ch, GAME_ASHEATH) 
      && IS_SET(in_room->area->area_flags, AREA_LAWFUL) 
      && !IS_SET(to_room->area->area_flags, AREA_LAWFUL)){
    do_combatdraw(ch, get_eq_char(ch, WEAR_WIELD), get_eq_char(ch, WEAR_SECONDARY));
  }

/* now check for opposite, sheathing */
  else if (IS_GAME(ch, GAME_ASHEATH) 
	   && IS_SET(to_room->area->area_flags, AREA_LAWFUL) 
	   && !IS_SET(in_room->area->area_flags, AREA_LAWFUL)
	   && get_eq_char(ch, WEAR_SHEATH_L) == NULL
	   && get_eq_char(ch, WEAR_SHEATH_R) == NULL){
    do_sheath(ch, "");
  }
}

void do_north( CHAR_DATA *ch, char *argument )
{
move_char( ch, DIR_NORTH, FALSE );
}

void do_east( CHAR_DATA *ch, char *argument )
{
  move_char( ch, DIR_EAST, FALSE );
}

void do_south( CHAR_DATA *ch, char *argument )
{
  move_char( ch, DIR_SOUTH, FALSE );
}

void do_west( CHAR_DATA *ch, char *argument )
{
  move_char( ch, DIR_WEST, FALSE );
}

void do_up( CHAR_DATA *ch, char *argument )
{
  move_char( ch, DIR_UP, FALSE );
}

void do_down( CHAR_DATA *ch, char *argument )
{
    move_char( ch, DIR_DOWN, FALSE );
}

int find_door( CHAR_DATA *ch, char *arg )
{
    EXIT_DATA *pexit;
    int door;
    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
    {
	for ( door = 0; door <= 5; door++ )
	{
	    if ( ( pexit = ch->in_room->exit[door] ) != NULL && IS_SET(pexit->exit_info, EX_ISDOOR)
            && pexit->keyword != NULL && is_name( arg, pexit->keyword ) )
		return door;
	}
	sendf(ch, "I see no %s here.\n\r", arg);
	return -1;
    }
    if ( ( pexit = ch->in_room->exit[door] ) == NULL )
    {
	sendf(ch, "I see no door %s here.\n\r", arg);
	return -1;
    }
    if ( !IS_SET(pexit->exit_info, EX_ISDOOR) )
    {
	sendf(ch, "I see no door %s here.\n\r", arg);
	return -1;
    }
    return door;
}


int find_door_quiet( CHAR_DATA *ch, char *arg )
{
    EXIT_DATA *pexit;
    int door;
    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
    {
	for ( door = 0; door <= 5; door++ )
	{
	    if ( ( pexit = ch->in_room->exit[door] ) != NULL && IS_SET(pexit->exit_info, EX_ISDOOR)
            && pexit->keyword != NULL && is_name( arg, pexit->keyword ) )
		return door;
	}
	return -1;
    }
    if ( ( pexit = ch->in_room->exit[door] ) == NULL )
    {
	return -1;
    }
    if ( !IS_SET(pexit->exit_info, EX_ISDOOR) )
    {
	return -1;
    }
    return door;
}

void do_open( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buf[MSL];
    OBJ_DATA *obj;
    int door;
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Open what?\n\r", ch );
	return;
    }
    if ( ( obj = get_obj_here( ch, NULL,  arg ) ) != NULL 
	 && ( door = find_door_quiet( ch, arg ) ) < 0 )
    {
	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 already open.\n\r",      ch ); return; }
	if ( !IS_SET(obj->value[1], CONT_CLOSEABLE) )
	    { send_to_char( "You can't do that.\n\r",      ch ); return; }
	if ( IS_SET(obj->value[1], CONT_LOCKED) )
	    { send_to_char( "It's locked.\n\r",            ch ); return; }
	REMOVE_BIT(obj->value[1], CONT_CLOSED);
	act("You open $p.",ch,obj,NULL,TO_CHAR);
        act("$n opens $p.", ch, obj, NULL, TO_ROOM );
	/* TRAP check */
	trip_traps(ch, obj->traps);
	return;
    }
    if ( ( door = find_door( ch, arg ) ) >= 0 )
    {
	ROOM_INDEX_DATA *to_room;
	EXIT_DATA *pexit = ch->in_room->exit[door], *pexit_rev;
	CHAR_DATA *ich = NULL;
	bool ecto = FALSE;
	if (ch->class == class_lookup("psionicist")){
	  for (ich = ch->in_room->people; ich; ich = ich->next_in_room){
	    if (IS_NPC(ich) 
		&& ich->pIndexData->vnum == MOB_VNUM_VAPOR 
		&& ich->leader == ch){
	      ecto = TRUE;
	      break;
	    }
	  }
	}
	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; }
	REMOVE_BIT(pexit->exit_info, EX_CLOSED);
	sprintf(buf,"$n opens the $d %s.",dir_name2[door]);
	WAIT_STATE(ch,6);
	if (ecto)
	    act( buf, ich, NULL, pexit->keyword, TO_ROOM );
	else
	{
	    act( buf, ch, NULL, pexit->keyword, TO_ROOM );
	    sprintf(buf,"You open the $d %s.",dir_name2[door]);
	    act( buf, ch, NULL, pexit->keyword, TO_CHAR );
	}
	if ( ( to_room   = pexit->to_room ) != NULL  && ( pexit_rev = to_room->exit[rev_dir[door]] ) != NULL
        && pexit_rev->to_room == ch->in_room )
	{

	    CHAR_DATA *rch;
	    REMOVE_BIT( pexit_rev->exit_info, EX_CLOSED );
	    sprintf(buf,"The $d %s opens.",dir_name2[rev_dir[door]]);
	    for ( rch = to_room->people; rch != NULL; rch = rch->next_in_room )
		act( buf, rch, NULL, pexit_rev->keyword, TO_CHAR );
	}
	/* TRAP check */
	trip_traps(ch, pexit->traps);
    }
}

void do_close( CHAR_DATA *ch, char *argument )
{
    char arg[MIL], buf[MSL];
    OBJ_DATA *obj;
    int door;
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Close what?\n\r", ch );
	return;
    }
    if ( ( obj = get_obj_here( ch, NULL,  arg ) ) != NULL 
	 && ( door = find_door_quiet( ch, arg ) ) < 0 )
    {
	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 already closed.\n\r",    ch ); return; }
	if ( !IS_SET(obj->value[1], CONT_CLOSEABLE) )
	    { send_to_char( "You can't do that.\n\r",      ch ); return; }
	SET_BIT(obj->value[1], CONT_CLOSED);
	act("You close $p.",ch,obj,NULL,TO_CHAR);
        act("$n closes $p.", ch, obj, NULL, TO_ROOM );

	/* TRAP check */
	trip_traps(ch, obj->traps);
	return;
    }
    if ( ( door = find_door( ch, arg ) ) >= 0 )
    {
	ROOM_INDEX_DATA *to_room;
	EXIT_DATA *pexit = ch->in_room->exit[door], *pexit_rev;
        CHAR_DATA *ich = NULL;
        bool ecto = FALSE;
        if (ch->class == class_lookup("psionicist"))
            for (ich = ch->in_room->people; ich != NULL; ich = ich->next_in_room)
                if (IS_NPC(ich) && ich->pIndexData->vnum == MOB_VNUM_VAPOR && ich->leader == ch)
                {
                    ecto = TRUE;
                    break;
                }
	if ( IS_SET(pexit->exit_info, EX_CLOSED) )
	    { send_to_char( "It's already closed.\n\r",    ch ); return; }
	else if (IS_SET(pexit->exit_info, EX_NOCLOSE)){
	  send_to_char("It seems stuck!\n\r", ch);
	  return;
	}
	SET_BIT(pexit->exit_info, EX_CLOSED);
	sprintf(buf,"$n closes the $d %s.",dir_name2[door]);
	WAIT_STATE(ch,12);
        if (ecto)
            act( buf, ich, NULL, pexit->keyword, TO_ROOM );
	else
	{
	    act( buf, ch, NULL, pexit->keyword, TO_ROOM );
	    sprintf(buf,"You close the $d %s.",dir_name2[door]);
	    act( buf, ch, NULL, pexit->keyword, TO_CHAR );
	}
	if ( ( to_room = pexit->to_room ) != NULL && ( pexit_rev = to_room->exit[rev_dir[door]] ) != 0
	&& pexit_rev->to_room == ch->in_room )
	{
	    CHAR_DATA *rch;
	    SET_BIT( pexit_rev->exit_info, EX_CLOSED );
	    sprintf(buf,"The $d %s closes.",dir_name2[rev_dir[door]]);
	    for ( rch = to_room->people; rch != NULL; rch = rch->next_in_room )
		act( buf, rch, NULL, pexit_rev->keyword, TO_CHAR );
	}
	/* TRAP check */
	trip_traps(ch, pexit->traps);
    }
}

OBJ_DATA* has_key( CHAR_DATA *ch, int key )
{
    OBJ_DATA *obj;
    for ( obj = ch->carrying; obj != NULL; obj = obj->next_content )
	if ( obj->pIndexData->vnum == key )
	    return obj;
    return NULL;
}

void do_lock( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    OBJ_DATA *obj, *key;
    int door;
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Lock what?\n\r", ch );
	return;
    }
    if ( ( obj = get_obj_here( ch, NULL,  arg ) ) != NULL 
	 && ( door = find_door_quiet( ch, arg ) ) < 0 )
    {
	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);
	act("You lock $p.",ch,obj,NULL,TO_CHAR);
        act("$n locks $p.", ch, obj, NULL, TO_ROOM );
	/* TRAP check */
	if (key)
	  trip_traps(ch, key->traps);
	return;
    }
    if ( ( door = find_door( ch, arg ) ) >= 0 )
    {
	ROOM_INDEX_DATA *to_room;
	EXIT_DATA *pexit = ch->in_room->exit[door], *pexit_rev;
        CHAR_DATA *ich = NULL;
        bool ecto = FALSE;
        if (ch->class == class_lookup("psionicist"))
            for (ich = ch->in_room->people; ich != NULL; ich = ich->next_in_room)
                if (IS_NPC(ich) && ich->pIndexData->vnum == MOB_VNUM_VAPOR && ich->leader == ch)
                {
                    ecto = TRUE;
                    break;
                }
	if ( !IS_SET(pexit->exit_info, EX_CLOSED) )
	    { send_to_char( "It's not closed.\n\r",        ch ); return; }
	if ( pexit->key <= 0 || IS_SET(pexit->exit_info, EX_NOLOCK))
	  { send_to_char( "It can't be locked.\n\r",     ch ); return; }
	if ( ( key = has_key( ch, pexit->key)) == NULL && !ecto)
	  { 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; }
	SET_BIT(pexit->exit_info, EX_LOCKED);
        if (ecto)
            act( "$n locks the $d.", ich, NULL, pexit->keyword, TO_ROOM );
	else
	    act( "$n locks the $d.", ch, NULL, pexit->keyword, TO_ROOM );
	send_to_char( "*Click*\n\r", ch );
	/* TRAP check */
	if (key)
	  trip_traps(ch, key->traps);
	if ( ( to_room = pexit->to_room ) != NULL && ( pexit_rev = to_room->exit[rev_dir[door]] ) != 0
        && pexit_rev->to_room == ch->in_room )
	    SET_BIT( pexit_rev->exit_info, EX_LOCKED );
    }
}

void do_unlock( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    OBJ_DATA *obj, *key;
    int door;
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Unlock what?\n\r", ch );
	return;
    }
    if ( ( obj = get_obj_here( ch, NULL,  arg ) ) != NULL 
	 && ( door = find_door_quiet( ch, arg ) ) < 0 )
    {
	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);
	act("You unlock $p.",ch,obj,NULL,TO_CHAR);
        act("$n unlocks $p.", ch, obj, NULL, TO_ROOM );
	/* TRAP check */
	if (key)
	  trip_traps(ch, key->traps);
	return;
    }
    if ( ( door = find_door( ch, arg ) ) >= 0 )
    {
	ROOM_INDEX_DATA *to_room;
	EXIT_DATA *pexit = ch->in_room->exit[door], *pexit_rev;
        CHAR_DATA *ich = NULL;
        bool ecto = FALSE;
        if (ch->class == class_lookup("psionicist"))
            for (ich = ch->in_room->people; ich != NULL; ich = ich->next_in_room)
                if (IS_NPC(ich) && ich->pIndexData->vnum == MOB_VNUM_VAPOR && ich->leader == ch)
                {
                    ecto = TRUE;
                    break;
                }
	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){
	  if (!ecto 
	      || IS_SET(pexit->exit_info, EX_PICKPROOF)){
	    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; }
	REMOVE_BIT(pexit->exit_info, EX_LOCKED);
        if (ecto)
            act( "$n unlocks the $d.", ich, NULL, pexit->keyword, TO_ROOM );
	else
	    act( "$n unlocks the $d.", ch, NULL, pexit->keyword, TO_ROOM );
	send_to_char( "*Click*\n\r", ch );
	/* TRAP check */
	if (key)
	  trip_traps(ch, key->traps);
	if ( ( to_room   = pexit->to_room ) != NULL && ( pexit_rev = to_room->exit[rev_dir[door]] ) != NULL
        && pexit_rev->to_room == ch->in_room )
	    REMOVE_BIT( pexit_rev->exit_info, EX_LOCKED );
    }
}

void do_pick( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    CHAR_DATA *gch;
    OBJ_DATA *obj;
    int door,chance = 0;
    one_argument( argument, arg );
    if ( arg[0] == '\0' )
    {
	send_to_char( "Pick what?\n\r", ch );
	return;
    }
    for ( gch = ch->in_room->people; gch; gch = gch->next_in_room )
	if ( IS_NPC(gch) && IS_AWAKE(gch) && ch->level + 5 < gch->level )
	{
            sendf(ch, "%s is standing too close to the lock.\n\r", PERS(gch,ch));
	    return;
	}
    WAIT_STATE( ch, skill_table[gsn_pick_lock].beats );
    chance = get_skill(ch,gsn_pick_lock);
    if (chance > 0)
	chance += 2*(get_curr_stat(ch,STAT_LUCK) - 16) ;
    if ( ( obj = get_obj_here( ch, NULL,  arg ) ) != NULL 
	 && ( door = find_door_quiet( ch, arg ) ) < 0 )
    {
	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 ( !IS_SET(obj->value[1], CONT_LOCKED) )
	    { send_to_char( "It's already unlocked.\n\r",  ch ); return; }
	if ( IS_SET(obj->value[1], CONT_PICKPROOF) )
	    { send_to_char( "You failed.\n\r",             ch ); return; }
    	if ( !IS_NPC(ch) && chance < number_percent())
    	{
	    send_to_char( "You failed.\n\r", ch);
	    check_improve(ch,gsn_pick_lock,FALSE,2);
	    return;
    	}
	REMOVE_BIT(obj->value[1], CONT_LOCKED);
        act("You pick the lock on $p.",ch,obj,NULL,TO_CHAR);
        act("$n picks the lock on $p.",ch,obj,NULL,TO_ROOM);
	check_improve(ch,gsn_pick_lock,TRUE,2);
	return;
    }
    if ( ( door = find_door( ch, arg ) ) >= 0 )
    {
	ROOM_INDEX_DATA *to_room;
	EXIT_DATA *pexit = ch->in_room->exit[door], *pexit_rev;
	if ( !IS_SET(pexit->exit_info, EX_CLOSED) && !IS_IMMORTAL(ch))
	    { send_to_char( "It's not closed.\n\r",        ch ); return; }
	if ( pexit->key < 0 && !IS_IMMORTAL(ch))
	    { send_to_char( "It can't be picked.\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_PICKPROOF) && !IS_IMMORTAL(ch))
	    { send_to_char( "You failed.\n\r",             ch ); return; }
    	if ( !IS_SET(pexit->exit_info, EX_EASY) )
    	    chance = 3*chance/2;
    	if ( !IS_SET(pexit->exit_info, EX_HARD) )
    	    chance = 2*chance/3;
    	if ( !IS_SET(pexit->exit_info, EX_INFURIATING) )
    	    chance /= 2;    
    	if ( !IS_NPC(ch) && chance < number_percent())
    	{
	    send_to_char( "You failed.\n\r", ch);
	    check_improve(ch,gsn_pick_lock,FALSE,2);
	    return;
    	}
	REMOVE_BIT(pexit->exit_info, EX_LOCKED);
	send_to_char( "*Click*\n\r", ch );
	act( "$n picks the $d.", ch, NULL, pexit->keyword, TO_ROOM );
	check_improve(ch,gsn_pick_lock,TRUE,2);
	if ( ( to_room = pexit->to_room ) != NULL && ( pexit_rev = to_room->exit[rev_dir[door]] ) != NULL
        && pexit_rev->to_room == ch->in_room )
	    REMOVE_BIT( pexit_rev->exit_info, EX_LOCKED );
    }
}

void do_stand( CHAR_DATA *ch, char *argument )
{
    AFFECT_DATA af;
    OBJ_DATA *obj = NULL;
    char buf[MIL];

    /* check for acting on objects */
    if (argument[0] != '\0'){
      if (!str_cmp("on", argument))
	argument = one_argument(argument, buf);
      if ((obj = get_obj_list( ch, argument, ch->in_room->contents )) == NULL){
	send_to_char("You do not see such object here.\n\r", ch);
	return;
      }
      sprintf(buf," on %s", obj->short_descr);
      if ( obj && HAS_TRIGGER_OBJ( obj, TRIG_SIT ) )
	p_percent_trigger( NULL, obj, NULL, ch, NULL, NULL, TRIG_SIT );
      if ( obj && HAS_TRIGGER_ROOM( ch->in_room, TRIG_SIT ) )
	p_percent_trigger( NULL, NULL, ch->in_room, ch, NULL, NULL, TRIG_SIT );
    }
    else
      sprintf(buf, " up");

    if (IS_AFFECTED2(ch, AFF_CATALEPSY))
    {
        send_to_char( "You're in a state of self-induced catalepsy.  You can't do that!\n\r", ch );
        send_to_char( "Type revive to revive yourself if you want.\n\r", ch );
        return;
    } 
    switch ( ch->position )
    {
    case POS_MEDITATE:
        act_new( "You stop meditating and stand$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
	if (!IS_AFFECTED(ch, AFF_HIDE))
	  act( "$n stops meditating and stands$t.", ch, buf, NULL, TO_ROOM );
	ch->position = POS_STANDING;
	dreamprobe_cast(ch, NULL );
	break;
    case POS_SLEEPING:
	if ( IS_AFFECTED(ch, AFF_SLEEP))
        {
            send_to_char( "You can't wake up!\n\r", ch );
            return;
        }
	if ( is_affected(ch, gsn_camp))
	{
	    send_to_char( "You feel drained from deprivation of sleep.\n\r", ch);
	    if (is_affected(ch, gsn_drained))
    	        affect_strip(ch,gsn_drained);
	    af.where		= TO_AFFECTS;
	    af.type             = gsn_drained;
            af.level            = ch->level;
            af.duration         = 10;
            af.location         = APPLY_NONE;
            af.modifier         = 0;
            af.bitvector        = 0;
            affect_to_char(ch,&af);	    
	    affect_strip(ch,gsn_camp);
	}
        act_new( "You wake and stand$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
	if (!IS_AFFECTED(ch, AFF_HIDE))
	  act( "$n wakes and stands$t.", ch, buf, NULL, TO_ROOM );
	ch->position = POS_STANDING;
	dreamprobe_cast(ch, NULL );
	break;
    case POS_RESTING: case POS_SITTING:
        act_new( "You stand$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
	if (!IS_AFFECTED(ch, AFF_HIDE))
	  act( "$n stands$t.", ch, buf, NULL, TO_ROOM );
	ch->position = POS_STANDING;
	break;
    case POS_STANDING:
	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;
    }
}

void do_rest( CHAR_DATA *ch, char *argument )
{
    AFFECT_DATA af;
    OBJ_DATA* obj = NULL;
    char buf[MIL];

    /* check for acting on objects */
    if (argument[0] != '\0'){
      if (!str_cmp("on", argument))
	argument = one_argument(argument, buf);
      if ((obj = get_obj_list( ch, argument, ch->in_room->contents )) == NULL){
	send_to_char("You do not see such object here.\n\r", ch);
	return;
      }
      sprintf(buf," on %s", obj->short_descr);
      if ( obj && HAS_TRIGGER_OBJ( obj, TRIG_SIT ) )
	p_percent_trigger( NULL, obj, NULL, ch, NULL, NULL, TRIG_SIT );
      if ( obj && HAS_TRIGGER_ROOM( ch->in_room, TRIG_SIT ) )
	p_percent_trigger( NULL, NULL, ch->in_room, ch, NULL, NULL, TRIG_SIT );
    }
    else
      buf[0] = '\0';

    if (IS_AFFECTED2(ch, AFF_CATALEPSY))
    {
        send_to_char( "You're already resting...as a corpse!\n\r", ch );
        send_to_char( "Type revive to revive yourself if you want.\n\r", ch );
        return;
    } 
    else if (is_affected(ch,gen_suffocate))
    {
	send_to_char("You cannot rest while suffocating!\n\r",ch);
	return;
    }

    check_dispel(-99, ch, gsn_stance );

    switch ( ch->position )
    {
    case POS_MEDITATE:
        act_new( "You stop meditating and rest$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
        act( "$n stops meditating and rests$t.", ch, buf, NULL, TO_ROOM );
	ch->position = POS_RESTING;
	dreamprobe_cast(ch, NULL );
	break;
    case POS_SLEEPING:
	if (IS_AFFECTED(ch,AFF_SLEEP))
	{
	    send_to_char("You can't wake up!\n\r",ch);
	    return;
	}
	if ( is_affected(ch, gsn_camp))
        {
            send_to_char( "You feel drained from deprivation of sleep.\n\r", ch);
            if (is_affected(ch, gsn_drained))    
                affect_strip(ch,gsn_drained);
            af.type             = gsn_drained;
            af.level            = ch->level;
            af.duration         = 10;
            af.location         = APPLY_NONE;
            af.modifier         = 0;
            af.bitvector        = 0;
            affect_to_char(ch,&af);
            affect_strip(ch,gsn_camp);
        }

	act_new("You wake up and start resting$t.", ch, buf, NULL, TO_CHAR, POS_DEAD);
        act("$n wakes up and starts resting$t.",ch,buf,NULL,TO_ROOM);
	ch->position = POS_RESTING;
	dreamprobe_cast(ch, NULL );
	break;
    case POS_RESTING:
	send_to_char( "You are already resting.\n\r", ch );
        break;
    case POS_STANDING:
        act_new( "You rest$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
        act( "$n sits down and rests$t.", ch, buf, NULL, TO_ROOM );
	ch->position = POS_RESTING;
	break;
    case POS_SITTING:
        act_new( "You rest$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
        act("$n rests$t.",ch, buf,NULL,TO_ROOM);
	ch->position = POS_RESTING;
	break;
    }
 
}

void do_sit (CHAR_DATA *ch, char *argument )
{
    AFFECT_DATA af;
    OBJ_DATA *obj = NULL;
    char buf[MIL];

    /* check for acting on objects */
    if (argument[0] != '\0'){
      if (!str_cmp("on", argument))
	argument = one_argument(argument, buf);
      if ((obj = get_obj_list( ch, argument, ch->in_room->contents )) == NULL){
	send_to_char("You do not see such object here.\n\r", ch);
	return;
      }
      sprintf(buf," on %s", obj->short_descr);
      if ( obj && HAS_TRIGGER_OBJ( obj, TRIG_SIT ) )
	p_percent_trigger( NULL, obj, NULL, ch, NULL, NULL, TRIG_SIT );
      if ( obj && HAS_TRIGGER_ROOM( ch->in_room, TRIG_SIT ) )
	p_percent_trigger( NULL, NULL, ch->in_room, ch, NULL, NULL, TRIG_SIT );
    }
    else
      buf[0] = '\0';

    if (IS_AFFECTED2(ch, AFF_CATALEPSY))
    {
        send_to_char( "You're in a state of self-induced catalepsy.  You can't do that!\n\r", ch );
        send_to_char( "Type revive to revive yourself if you want.\n\r", ch );
        return;
    } 
    if (!IS_NPC(ch) && ch->pcdata->pStallion != NULL)
    {
      sendf( ch, "You can't get into a comfortable position on the back of %s.\n\r",ch->pcdata->pStallion->short_descr);
      return;
    }

    check_dispel(-99, ch, gsn_stance );

    switch (ch->position)
    {
    case POS_MEDITATE:
        act_new( "You stop meditating and relax$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
        act( "$n stops meditating and relaxes$t.", ch, buf, NULL, TO_ROOM );
	ch->position = POS_SITTING;
	dreamprobe_cast(ch, NULL );
	break;
    case POS_SLEEPING:
        if (IS_AFFECTED(ch,AFF_SLEEP))
        {
            send_to_char("You can't wake up!\n\r",ch);
            return;
        }
	if ( is_affected(ch, gsn_camp))
        {
            send_to_char( "You feel drained from deprivation of sleep.\n\r", ch);
            if (is_affected(ch, gsn_drained))    
                affect_strip(ch,gsn_drained);
            af.type             = gsn_drained;
            af.level            = ch->level;
            af.duration         = 10;
            af.location         = APPLY_NONE;
            af.modifier         = 0;
            af.bitvector        = 0;
            affect_to_char(ch,&af);
            affect_strip(ch,gsn_camp);
        }
        act_new( "You wake and sit up$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
        act( "$n wakes and sits up$t.", ch, buf, NULL, TO_ROOM );
        ch->position = POS_SITTING;
	dreamprobe_cast(ch, NULL );
        break;
    case POS_RESTING:
        act_new( "You stop resting and sit$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
        act( "$n wakes and sits up$t.", ch, buf, NULL, TO_ROOM );
        ch->position = POS_SITTING;
        break;
    case POS_SITTING:
        send_to_char("You are already sitting down.\n\r",ch);
        break;
    case POS_STANDING:
        act_new("You sit down$t.",ch, buf,NULL,TO_CHAR, POS_DEAD);
        act("$n sits down$t.",ch, buf,NULL,TO_ROOM);
        ch->position = POS_SITTING;
        break;
    }
}

void do_meditate( CHAR_DATA *ch, char *argument )
{
    if (IS_AFFECTED2(ch, AFF_CATALEPSY))
    {
        send_to_char( "You're in a state of self-induced catalepsy.  You can't do that!\n\r", ch );
        send_to_char( "Type revive to revive yourself if you want.\n\r", ch );
        return;
    } 
/*    if (ch->class != class_lookup("monk"))
    {
	send_to_char("You assume a very comfortable position and begin to meditate.\n", ch);
	act("$n rests and begins to meditate... $e chants softly to $mself.", ch, NULL, NULL, TO_ROOM);
	return;
    }
*/
    /* reset memorization */
    if (!IS_NPC(ch)){
      //reset memticks
      reset_memticks( ch->pcdata );    
    }

    check_dispel(-99, ch, gsn_stance );

    switch ( ch->position )
    {
    case POS_MEDITATE:
	send_to_char( "You already are meditating.\n\r", ch );
	break;
    case POS_SLEEPING:
	send_to_char( "You have to wake up first.\n\r", ch );
	break;
    case POS_RESTING:
        act_new( "You sit up and begin to meditate.", ch, NULL, NULL, TO_CHAR, POS_DEAD );
	if (!IS_AFFECTED(ch, AFF_HIDE))
	  act( "$n sits up and begins to meditate.", ch, NULL, NULL, TO_ROOM );
        ch->position = POS_MEDITATE;
	dreamprobe_cast(ch, NULL );
	break;
    case POS_SITTING:
        act_new( "You begin to meditate.", ch, NULL, NULL, TO_CHAR, POS_DEAD );
	if (!IS_AFFECTED(ch, AFF_HIDE))
	  act( "$n begins to meditate.", ch, NULL, NULL, TO_ROOM );
        ch->position = POS_MEDITATE;
	dreamprobe_cast(ch, NULL);
	break;
    case POS_STANDING: 
        act_new( "You sit down and begin to meditate.", ch, NULL, NULL, TO_CHAR, POS_DEAD );
	if (!IS_AFFECTED(ch, AFF_HIDE))
	  act( "$n sits down and begins to meditate.", ch, NULL, NULL, TO_ROOM );
        ch->position = POS_MEDITATE;
	dreamprobe_cast(ch, NULL );
	break;
    case POS_FIGHTING:
	send_to_char( "You must settle down first!\n\r", ch );
	break;
    }
}

void do_sleep( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA* obj = NULL;
    char buf[MIL];
    bool force = FALSE;

    if (IS_AFFECTED(ch,AFF_SLEEP))
	force = TRUE;	

    /* check for acting on objects */
    if (!force && argument[0] != '\0'){
      if (!str_cmp("on", argument))
	argument = one_argument(argument, buf);
      if ((obj = get_obj_list( ch, argument, ch->in_room->contents )) == NULL){
	send_to_char("You do not see such object here.\n\r", ch);
	return;
      }
      sprintf(buf," on %s", obj->short_descr);
      if ( obj && HAS_TRIGGER_OBJ( obj, TRIG_SIT ) )
	p_percent_trigger( NULL, obj, NULL, ch, NULL, NULL, TRIG_SIT );
      if ( obj && HAS_TRIGGER_ROOM( ch->in_room, TRIG_SIT ) )
	p_percent_trigger( NULL, NULL, ch->in_room, ch, NULL, NULL, TRIG_SIT );
    }
    else
      buf[0] = '\0';

    if (IS_AFFECTED2(ch, AFF_CATALEPSY))
    {
        send_to_char( "You're as close to sleeping as you can get!\n\r", ch );
        send_to_char( "Type revive to revive yourself if you want.\n\r", ch );
        return;
    } 
    if (is_affected(ch,gsn_insomnia) && !force)
    {
	send_to_char("You cannot manage to sleep due to the insomnia.\n\r",ch);
	return;
    }
    else if (is_affected(ch,gen_suffocate) && !force)
    {
	send_to_char("You cannot sleep while suffocating!\n\r",ch);
	return;
    }
    if (!force && ch->class == class_lookup("vampire") 
	&& (mud_data.time_info.hour < 6 || mud_data.time_info.hour > 18))
    {
        send_to_char("Vampires do not sleep at night!\n\r",ch);
        return;
    }
    if (is_affected(ch,gsn_empower) && !force)
    {
	send_to_char("You can't concentrate enough while sleeping.\n\r",ch);
	return;
    }
    check_dispel(-99, ch, gsn_stance );

    if (IS_AFFECTED2(ch, AFF_SHADOWFORM))
    {
	affect_strip ( ch, gsn_shadowform			);
	REMOVE_BIT	 ( ch->affected2_by, AFF_SHADOWFORM	);
	act_new("Your body regains its substance, and you materialize into existence.",ch,NULL,NULL,TO_CHAR,POS_DEAD);
	act("$n's body regains its substance, and $e materializes into existence.",ch,NULL,NULL,TO_ROOM);
	WAIT_STATE( ch, 24);
    }
    if (IS_AFFECTED2(ch, AFF_TREEFORM))
    {
        affect_strip ( ch, gsn_treeform                       );
        REMOVE_BIT       ( ch->affected2_by, AFF_TREEFORM     );
        act_new("Your body returns to its normal form.",ch,NULL,NULL,TO_CHAR,POS_DEAD);
        act("$n's body returns to its normal form.",ch,NULL,NULL,TO_ROOM);
        WAIT_STATE( ch, 24);
    }
    switch ( ch->position )
    {
    case POS_MEDITATE:
        act_new( "You stop meditating and go to sleep$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
        act( "$n stops meditating and goes to sleep.$t", ch, buf, NULL, TO_ROOM );
	ch->position = POS_SLEEPING;
	break;
    case POS_SLEEPING:
	send_to_char( "You are already sleeping.\n\r", ch );
	break;
    case POS_RESTING:
    case POS_SITTING:
    case POS_STANDING: 
        act_new( "You go to sleep$t.", ch, buf, NULL, TO_CHAR, POS_DEAD );
        act( "$n goes to sleep$t.", ch, buf, NULL, TO_ROOM );
        ch->position = POS_SLEEPING;
	dreamprobe_cast(ch, NULL );
	break;
    case POS_FIGHTING:
	send_to_char( "You are already fighting!\n\r", ch );
	break;
    }
}

void do_wake( CHAR_DATA *ch, char *argument )
{
    char arg[MIL];
    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, NULL, arg ) ) == NULL )
    {
        send_to_char( "They aren't here.\n\r",ch );
        return;
    }
    if ( IS_AWAKE(victim) )
    {
        sendf(ch, "%s is already awake.\n\r", PERS(victim,ch));
        return;
    }
    if ( IS_AFFECTED(victim, AFF_SLEEP))
    {
        sendf(ch, "You can't wake %s!\n\r", PERS(victim,ch));
        return;
    }
    sendf(victim, "%s wakes you.\n\r", PERS(ch,victim));
    do_stand(victim,"");
}

void do_sneak( CHAR_DATA *ch, char *argument )
{
    AFFECT_DATA af;
    int chance = get_skill(ch, gsn_sneak);

    if (chance < 2){
      send_to_char("Huh?\n\r", ch);
      return;
    }
    else if (is_affected(ch, gsn_sneak)){
      send_to_char("You trample around loudly again.\n\r",ch);
      affect_strip( ch, gsn_sneak );
      return;
    }
    else if (!IS_NPC(ch) && ch->pcdata->pStallion != NULL){
      sendf( ch, "You can't sneak on the back of %s.\n\r",ch->pcdata->pStallion->short_descr);
      return;
    }
    else if ( IS_AFFECTED(ch, AFF_FAERIE_FOG) 
	      || IS_AFFECTED(ch, AFF_FAERIE_FIRE)){
      send_to_char( "You can't sneak while glowing.\n\r", ch);
      return;
    }

    send_to_char( "You attempt to move silently.\n\r", ch );
    WAIT_STATE(ch, 2);
    affect_strip( ch, gsn_sneak );

    if (IS_AFFECTED(ch,AFF_SNEAK))
      return;
    chance = UMAX(1, chance + (get_curr_stat(ch,STAT_LUCK) - 12) / 2);

    if ( number_percent() < chance){
      check_improve(ch,gsn_sneak,TRUE,1);
      af.where     = TO_AFFECTS;
      af.type      = gsn_sneak;
      af.level     = ch->level; 
      af.duration  = ch->level;
      af.location  = APPLY_NONE;
      af.modifier  = 0;
      af.bitvector = AFF_SNEAK;
      affect_to_char( ch, &af );
    }
    else
      check_improve(ch,gsn_sneak,FALSE,1);
}
    
void do_hide( CHAR_DATA *ch, char *argument ){

  int skill = get_skill(ch, gsn_hide);
  int roll = number_percent();

  if ( IS_AFFECTED(ch, AFF_HIDE) ){
    REMOVE_BIT(ch->affected_by, AFF_HIDE);
    act("You step out of the shadows.",ch,NULL,NULL,TO_CHAR);
    act("$n steps out of the shadows.",ch,NULL,NULL,TO_ROOM);
    return;
  }
  if (skill < 2){
    send_to_char("Huh?\n\r",ch);
    return;
  }
  if (!IS_NPC(ch) && ch->pcdata->pStallion != NULL)
    {
      sendf( ch, "You can't hide on the back of %s.\n\r",ch->pcdata->pStallion->short_descr);
      return;
    }
  if ( IS_AFFECTED(ch, AFF_FAERIE_FOG) || IS_AFFECTED(ch, AFF_FAERIE_FIRE))
    {
      send_to_char( "You can't hide while glowing.\n\r", ch);
      return;
    }
  if ( IS_AFFECTED(ch, AFF_CHARM) )
    {
      send_to_char( "You can't hide while charmed.\n\r",ch);
      return;
    }
  if (IS_SET(ch->in_room->room_flags2, ROOM_JAILCELL)){
    send_to_char("There's nothing around to hide in.\n\r",ch);
    return;
  }
  if (ch->in_room->sector_type != SECT_INSIDE 
      && ch->in_room->sector_type != SECT_CITY 
      && ch->in_room->sector_type != SECT_FIELD)
    {
      if (ch->in_room->sector_type == SECT_AIR 
	  || ch->in_room->sector_type == SECT_DESERT)
	{
	  send_to_char("There's nothing around to hide in.\n\r",ch);
	  return;
	}
      else
	{
	  send_to_char("You're not comfortable enough in this territory to know where to hide.\n\r",ch);
	  return;
	}
    }
  send_to_char( "You attempt to hide.\n\r", ch );
  WAIT_STATE(ch,skill_table[gsn_hide].beats);


  if (skill <= 100)
    roll -= (get_curr_stat(ch,STAT_LUCK) - 14) / 2;

  if ( roll < skill ){
    SET_BIT(ch->affected_by, AFF_HIDE);
    check_improve(ch,gsn_hide,TRUE,1);
  }
  else
    check_improve(ch,gsn_hide,FALSE,1);
}

void do_camouflage( CHAR_DATA *ch, char *argument )
{
  int skill = IS_NPC(ch) ? 999 : get_skill(ch,gsn_camouflage);
  int chance = number_percent();

  const int gsn_concealment = skill_lookup("concealment");
  int conceal = get_skill(ch, gsn_concealment);
  bool fAll = FALSE;

  if ( IS_AFFECTED2(ch, AFF_CAMOUFLAGE) ){
    REMOVE_BIT(ch->affected2_by, AFF_CAMOUFLAGE);
    act("You step out from your cover.",ch,NULL,NULL,TO_CHAR);
    act("$n steps out from $s cover.",ch,NULL,NULL,TO_ROOM);
    return;
  }

  if (skill < 2){
    send_to_char("Huh?\n\r", ch);
    return;
  }

  if (!IS_NPC(ch) && ch->pcdata->pStallion != NULL){
    sendf( ch, "You can't camouflage properly while on %s.\n\r",ch->pcdata->pStallion->short_descr);
    return;
  }
  if ( IS_AFFECTED(ch, AFF_FAERIE_FOG) || IS_AFFECTED(ch, AFF_FAERIE_FIRE)){
    send_to_char( "You can't camouflage yourself while glowing.\n\r", ch);
    return;
  }
  if (!IS_NPC(ch)
      && ch->in_room->sector_type != SECT_FOREST 
      && ch->in_room->sector_type != SECT_HILLS
      && ch->in_room->sector_type != SECT_SNOW
      && ch->in_room->sector_type != SECT_MOUNTAIN 
      && ch->in_room->sector_type != SECT_FIELD){
    if (ch->in_room->sector_type == SECT_AIR || ch->in_room->sector_type == SECT_DESERT){
      send_to_char("There's nothing around to camouflage yourself with.\n\r",ch);
      return;
    }
    else{
      send_to_char("You don't see any suitable cover to camouflage.\n\r",ch);
      return;
    }
  }

  if (IS_WEREBEAST(ch->race))
    chance -= 10;
  if (skill <= 100){
    chance -= (get_curr_stat(ch,STAT_LUCK) - 14) / 2;
  }

  send_to_char( "You attempt to camouflage yourself.\n\r", ch );
  WAIT_STATE(ch,skill_table[gsn_camouflage].beats);
  if ( chance < skill){
    SET_BIT(ch->affected2_by, AFF_CAMOUFLAGE);
    check_improve(ch,gsn_camouflage,TRUE,0);
  }
  else
    check_improve(ch,gsn_camouflage,FALSE,0);

  if (number_percent() < conceal){
    check_improve(ch, gsn_concealment, TRUE, 1);
    fAll = TRUE;
  }
  else
    check_improve(ch, gsn_concealment, FALSE, 1);

  /* Verdigar Tat camoes pets */
  if ((ch->tattoo && ch->tattoo == deity_lookup("nature")) || fAll){
    CHAR_DATA* vch;

    for (vch = ch->in_room->people; vch != NULL; vch = vch->next_in_room){
      if (IS_NPC(vch) && IS_AFFECTED(vch, AFF_CHARM) 
	  && vch->master && vch->master == ch)
	SET_BIT(vch->affected2_by, AFF_CAMOUFLAGE);
    }
  }
}

void do_visible( CHAR_DATA *ch, char *argument )
{
  AFFECT_DATA* paf;

  /* photon wall delay */
  if ( (paf = affect_find(ch->affected, gen_photon_wall)) != NULL){
    paf->modifier = 3;
  }
  if (IS_AFFECTED(ch, AFF_INVISIBLE))
    {
      affect_strip ( ch, gsn_invis			);
      affect_strip ( ch, gsn_mass_invis		);
      REMOVE_BIT   ( ch->affected_by, AFF_INVISIBLE	);
      act("You fade into existence.",ch,NULL,NULL,TO_CHAR);
      act("$n fades into existence.",ch,NULL,NULL,TO_ROOM);
    }
  if (IS_AFFECTED2(ch, AFF_TREEFORM))
    {
	affect_strip ( ch, gsn_treeform );
        REMOVE_BIT   ( ch->affected2_by, AFF_TREEFORM );
	act("You emerge from your treeformed state.",ch,NULL,NULL,TO_CHAR);
	act("$n emerges from $s treeformed state.",ch,NULL,NULL,TO_ROOM);
	WAIT_STATE( ch, 24);
    }
    if (IS_AFFECTED2(ch, AFF_CAMOUFLAGE))
    {
	affect_strip( ch, gsn_camouflage );
	REMOVE_BIT   ( ch->affected2_by, AFF_CAMOUFLAGE		);
	act("You step out from your cover.",ch,NULL,NULL,TO_CHAR);
	act("$n steps out from $s cover.",ch,NULL,NULL,TO_ROOM);
    }
    if (IS_AFFECTED(ch, AFF_HIDE))
    {
	affect_strip( ch, gsn_hide );
	REMOVE_BIT   ( ch->affected_by, AFF_HIDE		);
	act("You step out of the shadows.",ch,NULL,NULL,TO_CHAR);
	act("$n steps out of the shadows.",ch,NULL,NULL,TO_ROOM);
    }
    if (IS_AFFECTED(ch, AFF_SNEAK) 
	&& ch->race != race_lookup("faerie")
	&& ch->race != race_lookup("elf")
	&& ch->race != race_lookup("drow"))
    {
	affect_strip ( ch, gsn_sneak			);
	REMOVE_BIT   ( ch->affected_by, AFF_SNEAK		);
	send_to_char("You trample around loudly again.\n\r",ch);
    }
    if (IS_AFFECTED2(ch, AFF_SHADOWFORM))
    {
	affect_strip ( ch, gsn_shadowform			);
	REMOVE_BIT	 ( ch->affected2_by, AFF_SHADOWFORM	);
	act("Your body regains its substance, and you materialize into existence.",ch,NULL,NULL,TO_CHAR);
	act("$n's body regains its substance, and $e materializes into existence.",ch,NULL,NULL,TO_ROOM);
	WAIT_STATE( ch, 24);
    }
    if (is_affected(ch, gen_d_shroud))
      affect_strip(ch, gen_d_shroud);
    
}

void do_revert( CHAR_DATA *ch, char *argument )
{
    if (is_affected(ch,gsn_bat_form) || is_affected(ch,gsn_wolf_form) || is_affected(ch,gsn_mist_form))
    {
	affect_strip(ch,gsn_bat_form);
	affect_strip(ch,gsn_wolf_form);
	affect_strip(ch,gsn_mist_form);
	free_string( ch->short_descr );
        ch->short_descr = str_empty;
        ch->dam_type = 17;
	send_to_char("You revert back to your natural form.\n\r",ch);
	act("$n reverts back to $s natural form.",ch,NULL,NULL,TO_ROOM);
	WAIT_STATE( ch, 12);
	return;
    }
    else if (is_affected(ch,gsn_doppelganger)){
      affect_strip( ch, gsn_doppelganger );
      act("You revert to your original form.",ch,NULL,NULL,TO_CHAR);
      act("$n reverts to $s original form.",ch,NULL,NULL,TO_ROOM);
      WAIT_STATE( ch, 12);
      return;
    }
    else if (is_affected(ch, gsn_weretiger) || is_affected(ch, gsn_werewolf) 
	     || is_affected(ch, gsn_werebear) || is_affected(ch, gsn_werefalcon)){
      affect_strip(ch,gsn_weretiger);
      affect_strip(ch,gsn_werewolf);
      affect_strip(ch,gsn_werebear);
      affect_strip(ch,gsn_werefalcon);
      affect_strip(ch,gsn_werepower);

      free_string( ch->short_descr );
      ch->short_descr = str_empty;
      ch->dam_type = 17;

      send_to_char("You revert back to your natural form.\n\r",ch);
      act("$n reverts back to $s natural form.",ch,NULL,NULL,TO_ROOM);
      WAIT_STATE( ch, 12);
      return;
    }
    send_to_char("You are already in your native form.\n\r",ch);
    return;
}

void do_recall( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    ROOM_INDEX_DATA *location;
    if (IS_NPC(ch))
    {
	send_to_char("Only players can recall.\n\r",ch);
	return;
    }
    act( "$n tries to recall to $s hometown.", ch, 0, 0, TO_ROOM );
    location = get_room_index(get_temple(ch));
    if (location == NULL)
    {
	send_to_char( "You are completely lost.\n\r", ch );
	return;
    }
    if ( ch->in_room == location )
	return;
    if (ch->level > 10 && !IS_IMMORTAL(ch))
    {
        send_to_char("Only level 10 and under get free recalls.\n\r", ch);
        return;
    }
    if (is_fight_delay(ch,60))
    {
	send_to_char("You are too pumped to pray.\n\r",ch);
	return;
    }
    if ( IS_SET(ch->in_room->room_flags, ROOM_NO_INOUT) || IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
	 || IS_AFFECTED(ch, AFF_CURSE) || IS_SET(ch->act, PLR_DOOF) || is_affected(ch, gsn_damnation) )
      
      {
	send_to_char( "The Gods have forsaken you.\n\r", ch );
	return;
      }
    else if (is_affected(ch,gen_ensnare)){
      send_to_char("You sense a powerful magical field preventing your departure.\n\r", ch);
      return;
    }
    if ( ( victim = ch->fighting ) != NULL )
    {
	int lose, skill = get_skill(ch,gsn_recall);
	if ( number_percent() < 80 * skill / 100 )
	{
	    check_improve(ch,gsn_recall,FALSE,0);
	    WAIT_STATE( ch, 4 );
	    sendf( ch, "You failed!.\n\r");
	    return;
	}
	lose = (ch->desc != NULL) ? 25 : 50;
	gain_exp( ch, 0 - lose );
	check_improve(ch,gsn_recall,TRUE,4);
	sendf( ch, "You recall from combat!  You lose %d exps.\n\r", lose );
        if ( IS_NPC(ch->fighting) && !IS_SET(ch->fighting->off_flags,CABAL_GUARD))
        {
            if (!IS_NPC(ch))
                ch->fighting->hunting = ch;   
            else if (ch->master != NULL)
                ch->fighting->hunting = ch->master;
            else
                ch->fighting->hunting = ch;
            ch->fighting->hunttime = 0;
        }
	stop_fighting( ch, TRUE );
    }
    ch->move /= 2;
    act( "$n disappears.", ch, NULL, NULL, TO_ROOM );
    char_from_room( ch );
    char_to_room( ch, location );
    act( "$n appears in the room.", ch, NULL, NULL, TO_ROOM );
    do_look( ch, "auto" );
    send_to_char("\n\rIMPORTANT: Only level 10 and under get free recalls.\n\r", ch);
    if (ch->pet != NULL)
    {
	char_from_room( ch->pet );
	char_to_room ( ch->pet, location );
    }
}

void do_train( CHAR_DATA *ch, char *argument )
{
    char buf[MSL];
    CHAR_DATA *mob;
    sh_int stat = - 1;
    char *pOutput = NULL;

    if ( IS_NPC(ch) )
	return;
    for ( mob = ch->in_room->people; mob; mob = mob->next_in_room )
    {
        if ( ch->class == class_lookup("monk") && IS_NPC(mob) && IS_SET(mob->act, ACT_IS_HEALER))
            if (mob->pIndexData->vnum == get_temple(ch) || mob->pIndexData->vnum == (get_temple(ch) + 1))
		break;
	if ( IS_NPC(mob) && IS_SET(mob->act, ACT_TRAIN) )
	    break;
    }
    if ( mob == NULL )
    {
	send_to_char( "You can't do that here.\n\r", ch );
	return;
    }
    if (is_exiled(ch, mob->in_room->area->vnum )){
      char buf[MIL];
      sprintf( buf, "No one in %s will deal with you %s!", mob->in_room->area->name, PERS2(ch));
      do_say( mob, buf );
      return;
    }
    if ( argument[0] == '\0' )
    {
	sendf( ch, "You have %d training sessions.\n\r", ch->train );
	argument = "foo";
    }
    if (ch->train < 1)
    {
	send_to_char("You have no training sessions left.\n\r",ch);
	return;
    }
    if ( !str_cmp( argument, "str" ) )
    {	stat        = STAT_STR; 	pOutput     = "strength";    }
    else if ( !str_cmp( argument, "int" ) )
    {	stat	    = STAT_INT; 	pOutput     = "intelligence";    }
    else if ( !str_cmp( argument, "wis" ) )
    {	stat	    = STAT_WIS; 	pOutput     = "wisdom";    }
    else if ( !str_cmp( argument, "dex" ) )
    {	stat  	    = STAT_DEX; 	pOutput     = "dexterity";    }
    else if ( !str_cmp( argument, "con" ) )
    {	stat	    = STAT_CON; 	pOutput     = "constitution";    }
    else if ( !str_cmp(argument, "hp" ) );
    else if ( !str_cmp(argument, "mana" ) );
    else if ( !str_cmp(argument, "move" ) );
    else
    {
	strcpy( buf, "You can train:" );
	if ( ch->perm_stat[STAT_STR] < get_max_train(ch,STAT_STR))     strcat( buf, " str" );
	if ( ch->perm_stat[STAT_INT] < get_max_train(ch,STAT_INT))     strcat( buf, " int" );
	if ( ch->perm_stat[STAT_WIS] < get_max_train(ch,STAT_WIS))     strcat( buf, " wis" );
	if ( ch->perm_stat[STAT_DEX] < get_max_train(ch,STAT_DEX))     strcat( buf, " dex" );
	if ( ch->perm_stat[STAT_CON] < get_max_train(ch,STAT_CON))     strcat( buf, " con" );
        strcat( buf, " hp mana move");
	if ( buf[strlen(buf)-1] != ':' )
	{
	    strcat( buf, ".\n\r" );
	    send_to_char( buf, ch );
	}
	else
            send_to_char( "You have nothing left to train", ch);
	return;
    }
    if (!str_cmp("hp",argument)){
      if (ch->class == gcn_adventurer){
	send_to_char("Adventurers cannot train health.\n\r", ch);
	return;
      }      
      --ch->train;
      ch->pcdata->perm_hit += 10;
      ch->max_hit += 10;
      ch->hit +=10;
      act( "Your durability increases!",ch,NULL,NULL,TO_CHAR);
      act( "$n's durability increases!",ch,NULL,NULL,TO_ROOM);
      return;
    }
    if (!str_cmp("mana",argument)){
      if (ch->class == gcn_adventurer){
	send_to_char("Adventurers cannot train their minds.\n\r", ch);
	return;
      }      
      --ch->train;
      ch->pcdata->perm_mana += 20;
      ch->max_mana += 20;
      ch->mana += 20;
      act( "Your power increases!",ch,NULL,NULL,TO_CHAR);
      act( "$n's power increases!",ch,NULL,NULL,TO_ROOM);
      return;
    }
    if (!str_cmp("move",argument)){
      if (ch->class == gcn_adventurer){
	send_to_char("Adventurers cannot train their stamina.\n\r", ch);
	return;
      }      
      --ch->train;
      ch->pcdata->perm_move += 30;
      ch->max_move += 30;
      ch->move += 30;
      act( "Your endurance increases!",ch,NULL,NULL,TO_CHAR);
      act( "$n's endurance increases!",ch,NULL,NULL,TO_ROOM);
      return;
    }
    if ( ch->perm_stat[stat]  >= get_max_train(ch,stat) )
    {
      act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
      return;
    }
    --ch->train;
    ch->perm_stat[stat]++;
    act( "Your $T increases!", ch, NULL, pOutput, TO_CHAR );
    act( "$n's $T increases!", ch, NULL, pOutput, TO_ROOM );
}

void scan_room (CHAR_DATA *ch, ROOM_INDEX_DATA *room, int distance, int dir)
{
    CHAR_DATA *victim = room->people;
    OBJ_DATA* obj;
    int number_found = 0;
    bool fLight = FALSE;

    if (IS_SET(room->room_flags,ROOM_NO_SCAN))
      return;
/* add light if required */
    if ( ( obj = get_eq_char( ch, WEAR_LIGHT ) ) != NULL 
	 && obj->item_type == ITEM_LIGHT
	 && obj->value[2] != 0){
      fLight = TRUE;
      room->light++;
    }
    
    while (victim != NULL){
      if ((can_see(ch,victim) 
	   || (IS_AFFECTED2(ch,AFF_SENSE_EVIL) 
	       && IS_EVIL(victim)
	       && !is_affected(victim, gen_d_shroud)
	       && (victim->invis_level < 1 || victim->incog_level < 1))) && !IS_IMMORTAL(victim))
        {
	  if (number_found == 0)
	    sendf (ch, "*** Range %d (%s) ***\n\r", distance, dir_name[dir]);
	  number_found++;
	  show_char_to_char_0(victim,ch);
        }
      victim = victim->next_in_room;
    }
    if (fLight)
      room->light --;
}

void do_scan (CHAR_DATA *ch, char *argument)
{
    EXIT_DATA * pexit;
    ROOM_INDEX_DATA * room;
    extern char * const dir_name[];
    char arg[MIL];
    int dir, distance;
    if (IS_AFFECTED2(ch,AFF_TERRAIN))
    {
      if (is_affected(ch, gsn_forest_mist)){
	if (ch->in_room->sector_type != SECT_AIR 
	    && ch->in_room->sector_type != SECT_DESERT 
	    && ch->in_room->sector_type != SECT_CITY
	    && ch->in_room->sector_type != SECT_INSIDE){
	  send_to_char("A thick mist prevents any observation.\n\r",ch);
	  return;
	}
      }
      else
	send_to_char("Thick walls of darkness stop your sight short.\n\r",ch);
      return;
    }
    if (IS_SET(ch->in_room->room_flags,ROOM_NO_SCAN))
    {
	send_to_char("A blanket of darkness prevents you from scanning out of this room.\n\r",ch);
	return;
    }

    argument = one_argument(argument, arg);
    if      (!str_cmp(arg, "n") || !str_cmp(arg, "north")) dir = 0;
    else if (!str_cmp(arg, "e") || !str_cmp(arg, "east"))  dir = 1;
    else if (!str_cmp(arg, "s") || !str_cmp(arg, "south")) dir = 2;
    else if (!str_cmp(arg, "w") || !str_cmp(arg, "west"))  dir = 3;
    else if (!str_cmp(arg, "u") || !str_cmp(arg, "up" ))   dir = 4;
    else if (!str_cmp(arg, "d") || !str_cmp(arg, "down"))  dir = 5;
    else if (!str_cmp(arg, "a") || !str_cmp(arg, "all"))   dir = 99;
    else if (IS_NULLSTR(arg)				)  dir = 99;
    else
    {
	send_to_char("Which way do you wish to scan?\n\r",ch);
	return;
    }
    if (dir == 99)
    {
	int allscan;
	int range = (ch->level + 10) / 10;

	if (IS_PERK(ch, PERK_EAGLEEYE))
	  range += 2;

    	act("You scan all around.", ch, NULL,NULL, TO_CHAR);
    	act("$n scans all around.", ch, NULL,NULL, TO_ROOM);
	for (allscan = 0; allscan <= 5; allscan++)
	{
    	    room = ch->in_room;
    	    act("You scan $T.", ch, NULL, dir_name[allscan], TO_CHAR);
	    for (distance = 1 ; distance <= range; distance++)
	    {
	        pexit = room->exit[allscan];
	        if ((pexit == NULL) || (pexit->to_room == NULL) || (IS_SET(pexit->exit_info, EX_CLOSED)))
		    break;
		if (IS_SET(pexit->to_room->room_flags,ROOM_NO_SCAN))
		{
		    send_to_char("You vision cannot penetrate the blanket of darkness surrounding this room.\n\r",ch);
		    send_to_char("*** Too Dark ***\n\r",ch);
	            break;
		}
	        scan_room(ch,pexit->to_room,distance,allscan);
        	room = pexit->to_room;
	    }
	}
    }
    else
    {	
      int range = (ch->level + 10) / 10;
      if (IS_PERK(ch, PERK_EAGLEEYE))
	range += 2;

    	room = ch->in_room;
    	act("You scan $T.", ch, NULL, dir_name[dir], TO_CHAR);
    	act("$n scans $T.", ch, NULL, dir_name[dir], TO_ROOM);
    for (distance = 1 ; distance <= range; distance++)
    {
        pexit = room->exit[dir];
        if ((pexit == NULL) || (pexit->to_room == NULL) || (IS_SET(pexit->exit_info, EX_CLOSED)))
	    break;
	if (IS_SET(pexit->to_room->room_flags,ROOM_NO_SCAN))
	{
	    send_to_char("You vision cannot penetrate the blanket of darkness surrounding this room.\n\r",ch);
	    send_to_char("*** Too Dark ***\n\r",ch);
            break;
	}
        scan_room(ch,pexit->to_room,distance,dir);
        room = pexit->to_room;
    }
    }
}

void do_scout (CHAR_DATA *ch, char *argument)
{
    EXIT_DATA * pexit;
    ROOM_INDEX_DATA * room;
    extern char * const dir_name[];
    char arg[MIL];
    int dir, distance, chance, extra = 0;
    if ( (chance = get_skill(ch,gsn_scout)) == 0)
    {
	send_to_char("You don't know how to scout.\n\r",ch);
	return;
    }
    if (IS_AFFECTED2(ch,AFF_TERRAIN))
    {
        send_to_char("Thick walls of darkness stop your sight short.\n\r",ch);
        return;
    }
    if (IS_SET(ch->in_room->room_flags,ROOM_NO_SCAN))
    {
	send_to_char("A blanket of darkness prevents you from scanning out of this room.\n\r",ch);
	return;
    }
    if (ch->in_room->vnum == 70)
    {
	send_to_char("You see millions of stars.\n\r",ch);
	return;
    }
    argument = one_argument(argument, arg);
    if      (!str_cmp(arg, "n") || !str_cmp(arg, "north")) dir = 0;
    else if (!str_cmp(arg, "e") || !str_cmp(arg, "east"))  dir = 1;
    else if (!str_cmp(arg, "s") || !str_cmp(arg, "south")) dir = 2;
    else if (!str_cmp(arg, "w") || !str_cmp(arg, "west"))  dir = 3;
    else if (!str_cmp(arg, "u") || !str_cmp(arg, "up" ))   dir = 4;
    else if (!str_cmp(arg, "d") || !str_cmp(arg, "down"))  dir = 5;
    else
    {
	send_to_char("Which direction do you wish to scout?\n\r",ch);
	return;
    }
    act("You attempt to scout $T.", ch, NULL, dir_name[dir], TO_CHAR);
    act("$n attempts to scout $T.", ch, NULL, dir_name[dir], TO_ROOM);
    WAIT_STATE( ch, skill_table[gsn_scout].beats );
    chance += 2*(get_curr_stat(ch,STAT_LUCK) - 16);
    if (IS_WEREBEAST(ch->race))
	chance += 10;
    if ( number_percent() < chance)
    {

	if (IS_PERK(ch, PERK_EAGLEEYE))
	  extra = number_range(3,5);	 
	else
	  extra = number_range(1,5);
   	check_improve(ch,gsn_scout,TRUE,0);
    }
    else
    {
	send_to_char("You squint your eyes but can't manage to see any further.\n\r",ch);
	check_improve(ch,gsn_scout,FALSE,0);
    }
    room = ch->in_room;
    for (distance = 1 ; distance <= ((ch->level + 10) /10)+extra; distance++)
    {
        pexit = room->exit[dir];
        if ((pexit == NULL) || (pexit->to_room == NULL) || (IS_SET(pexit->exit_info, EX_CLOSED)))
            break;
	if (IS_SET(pexit->to_room->room_flags,ROOM_NO_SCAN))
	{
	    send_to_char("You vision cannot penetrate the blanket of darkness surrounding this room.\n\r",ch);
	    send_to_char("*** Too Dark ***\n\r",ch);
            break;
	}
        scan_room(ch,pexit->to_room,distance,dir);
        room = pexit->to_room;
    }
}

void do_kinetics( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *tattoo = NULL;
    AFFECT_DATA af;
    if (IS_NPC(ch))
	return;
    if (is_affected(ch,gsn_kinetics))
    {
	affect_strip(ch,gsn_kinetics);
	send_to_char("Kinetic transfer OFF.\n\r",ch);
	return;
    }
    tattoo= get_eq_char(ch, WEAR_TATTOO);
    if (tattoo == NULL || tattoo->pIndexData->vnum != 93)
    {
	send_to_char("Huh?\n\r",ch);
	return;
    }
    af.where     = TO_AFFECTS;
    af.type      = gsn_kinetics;
    af.level     = ch->level;
    af.duration  = -1;   
    af.modifier  = 0;
    af.location  = 0;
    af.bitvector = 0;
    affect_to_char( ch, &af );
    send_to_char("Kinetic transfer ON.\n\r",ch);
}


//03-25 14:00 Viri: Added 2 if statements in move_char(..) for city sneak
//in vamp class.

//03-25 12:00 Viri: Created bool vamp_can_sneak(CHAR_DATA*, ROOM_INDEX_DATA*)
//the function tests if vampire can sneak in th room 
//Tests for autosneak in both wolf and human form.


//03-25 12:00 Viri: Implemented vamp_can_sneak in move_char(..)
//04-18 22:00 Viri: Added LEAVE_CHECK and ENTER_CHECK