area/
build/testing/
log/
player/
player/backup/
/***************************************************************************
 *  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 Merc Diku Mud, you must comply with   *
 *  both the original Diku license in 'license.doc' as well the Merc       *
 *  license in 'license.txt'.  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.                                                  *
 ***************************************************************************/
#include <glib.h>

#if defined(macintosh)
#include <types.h>
#else
#include <sys/types.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <ctype.h>
#include <merc.h>
#include <tables.h>
#include <interp.h>



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

const	sh_int	rev_dir		[]		=
{
	2, 3, 0, 1, 5, 4
};

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

/**
 * External Functions
 */

void teleport_char	args((	CHAR_DATA *victim ));
void set_attack_flag args(( CHAR_DATA *ch, CHAR_DATA *victim));
/*
 * Local functions.
 */
int	find_door	args( ( CHAR_DATA *ch, char *arg ) );
bool	has_key		args( ( CHAR_DATA *ch, int key ) );
extern int	count_imms	args( ( CHAR_DATA *ch ) );
bool	check_track	args( ( CHAR_DATA *ch, int direction ) );
void	add_tracks	args( ( CHAR_DATA *ch, int direction ) );
void	show_page	args( ( CHAR_DATA *ch, OBJ_DATA *book, int pnum, bool pagefalse ) );
void	show_runes	args( ( CHAR_DATA *ch, OBJ_DATA *page, bool endline ) );
bool	are_runes	args( ( OBJ_DATA *page ) );

/*! \fn count_users(OBJ_DATA *obj)
    \brief Counts all the people that are on a object(Sitting/Laying)
    \param obj The furniture object we need to count people.
*/

int count_users(OBJ_DATA *obj)
{
    CHAR_DATA *fch;	/*!< character that is on the furniture object */
    int count = 0;  /*!< Initalise the count */

    /*!
     * If the object is not in a room we can't do
     * any thing
     */
    if (obj->in_room == NULL)
		return 0;
	
	/*!
	 * Loop the people in the room. Check for the furniture object
	 * then if it's the object we are looking for.. increment the
	 * counter
	 */
    for (fch = obj->in_room->people; fch != NULL; fch = fch->next_in_room)
    {
		if (fch->on == obj)
		    count++;
    }
    
    return count;
}

void check_pet_reaction(CHAR_DATA *pet)
{
    CHAR_DATA *victim,*victim_next;

    //Imm pets are above fighting...
    //if (IS_IMMORTAL(pet->pet_master))
    //    return;

    for (victim = pet->in_room->people; victim != NULL; victim = victim_next)
    {
        victim_next = victim->next_in_room;
        if (IS_NPC(victim) && IS_PET(victim) && can_see(pet,victim))
        {
            switch (pet->pet_stats[PET_TYPE])
            {
                case PET_TYPE_DOG:
                    if (victim->pet_stats[PET_TYPE] == PET_TYPE_CAT)
                    {
                        do_say(pet,"Whoof! A CAT!!!! GET HIM!!!");
                        if (!is_tempsafe(pet))
                            damage(pet,victim,10,TYPE_CLAW);
                        else
                            do_say(pet,"Step outside this room cat...");

                        return;
                    }
                    break;
                case PET_TYPE_CAT:
                    if (victim->pet_stats[PET_TYPE] == PET_TYPE_DOG)
                    {
                        do_say(pet,"Meow! Oh no a DOG!! RUN!!!");
                        if (!is_tempsafe(pet))
                            do_flee(pet,"");
                        return;
                    }
                    break;

            }
        }
    }
}

/*!
 * This is the SOLE function for moving the char_data pointer around.
 * Using normal movement commands(north,south,east,west,up,down)
 */

void move_char( CHAR_DATA *ch, int door )
{
	CHAR_DATA *fch,*victim;
	CHAR_DATA *fch_next;
	CHAR_DATA *mount;					/*!< if the person is riding something that something has to move too! */
	ROOM_INDEX_DATA *in_room;
	ROOM_INDEX_DATA *to_room;
	EXIT_DATA *pexit;
	DESCRIPTOR_DATA *d;					/*!< Looking at the descriptor pointer */
	char buf  [MAX_STRING_LENGTH];		/*!< Generic String buffer */
	char poly [MAX_STRING_LENGTH];
	GString *mxpout;	/*!< used to hold mxp strings */
	char mount2 [MAX_INPUT_LENGTH];
	char leave [20];
	int revdoor;
	OBJ_DATA *to_obj;
	GSList *desc_list;

	if ( door < 0 || door > 5 )
	{
		bug( "Do_move: bad door %d.", door );
		return;
	}
	if (!IS_NPC(ch))
	{
		/* Uh oh, another drunk Frenchman on the loose! :) */
		if (ch->pcdata->condition[COND_DRUNK] > 10)
		{
			if (ch->pcdata->condition[COND_DRUNK] > number_percent())
			{
				act("You feel a little drunk... not to mention kind of lost...",
						ch,NULL,NULL,TO_CHAR);
				act("$n looks a little drunk... not to mention kind of lost...",
						ch,NULL,NULL,TO_ROOM);
				door = number_range(0,5);
			}
			else
			{
				act("You feel a little... drunk...",ch,NULL,NULL,TO_CHAR);
				act("$n looks a little... drunk...",ch,NULL,NULL,TO_ROOM);
			}
		}
	}

	/*
	 * Exit trigger, if activated, bail out. Only PCs are triggered.
	 */
	if ( !IS_NPC(ch) && mp_exit_trigger( ch, door ) )
		return;

	if ( rprog_exit_trigger(ch, door))
		return;

	for ( to_obj = ch->in_room->contents; to_obj;	to_obj = to_obj->next_content )
	{
		if ( oprog_exit_trigger(to_obj, door))
			return;
	}


	in_room = ch->in_room;
	if ( ( pexit   = in_room->exit[door] ) == NULL
			||   ( to_room = pexit->to_room      ) == NULL )
	{
		if ((IS_NPC(ch) && number_percent() < 10)
				|| (!IS_NPC(ch) && number_percent() < (10 +
						ch->pcdata->condition[COND_DRUNK])))
		{
			/*
			   if (!IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK] > 10)
			   {
			   act("You drunkenly slam face-first into the 'exit' on your way $T.",ch,NULL,mxpconv(dir_name[door],ch),TO_CHAR);
			   act("$n drunkenly slams face-first into the 'exit' on $s way $X.",ch,NULL,mxpconv(dir_name[door],ch),TO_ROOM);
			   damage(ch,ch,3,0);
			   }
			   else
			   {
			   act("Did you not see that wall? BOOM! Now all you see are stars!",ch,NULL,dir_name[door],TO_CHAR);
			   act("$n slams face-first into the 'exit' on $s way $X. WHAM!",
			   ch,NULL,dir_name[door],TO_ROOM);
			   damage(ch,ch,3,0);
			   }
			   */
		}
		else
		{
			if (!IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK] > 10)
			{
				act("You stumble about aimlessly and fall down drunk.",
						ch,NULL,dir_name[door],TO_CHAR);
				act("$n stumbles about aimlessly and falls down drunk.",
						ch,NULL,dir_name[door],TO_ROOM);
				ch->position = POS_RESTING;
			}
			else
			{
				act("You almost go $X, but suddenly realize that there's no exit there.",ch,NULL,dir_name[door],TO_CHAR);
				act("$n takes a half step to the $X, but stops short and looks confused.",ch,NULL,dir_name[door],TO_ROOM);
			}
		}

		/* send_to_char( "Alas, you cannot go that way.\n\r", ch ); */
		return;
	}

	if ( IS_SET(pexit->exit_info, EX_WALL_WATER) )
	{
		send_to_char("You are unable to pass the wall of water.\n\r",ch);
		return;
	}

	if ( IS_SET(pexit->exit_info, EX_WALL_GRANITE) )
	{
		send_to_char("You are unable to pass the wall of granite.\n\r",ch);
		return;
	}

	if ( IS_SET(pexit->exit_info, EX_WALL_FLAME) )
	{
		int ch_hp = ch->hit;
		send_to_char("You step through the wall of searing flames!\n\r",ch);
		act("$n gingerly steps through the wall of searing flames!",ch,NULL,NULL,TO_ROOM);
		/*
		   if ( ( sn = skill_lookup("fire breath") ) >= 0 )
		   {
		   spelltype = skill_table[sn].target;
		   (*skill_table[sn].spell_fun) ( sn, 25, ch, ch );
		   }
		   if (ch == NULL || ch->position == POS_DEAD) return;
		   */
		if (ch->hit < ch_hp)
		{
			act("$n's flesh smolders as $e passes through the wall of searing flames!",ch,NULL,NULL,TO_ROOM);
			send_to_char("Your flesh smolders as you pass through the wall of searing flames!\n\r",ch);
			if (number_percent() <= 5) SET_BIT(ch->affected_by, AFF_FLAMING);
		}
	}



	if ( IS_SET(to_room->room_flags, ROOM_SAFE) 
			&& weather_info[ch->in_room->sector_type].sunlight != SUN_DARK
			&& ch->pk_timer > 0 )
	{
		send_to_char("You need to settle down to enter a safe room.\n\r",ch);
		return;
	}

	if ( IS_SET(pexit->exit_info, EX_CLOSED)
			&&  (!IS_AFFECTED(ch, AFF_PASS_DOOR) || IS_SET(pexit->exit_info,EX_PASSPROOF)))
	{
		if (!IS_NPC(ch) && !IS_SET(pexit->exit_info, EX_PASSPROOF) && IS_CLASS(ch, CLASS_WEREWOLF) &&
				ch->pcdata->powers[WPOWER_BOAR] > 0)
		{
			act( "You smash open the $d.", ch, NULL, pexit->keyword, TO_CHAR );
			act( "$n smashes open the $d.", ch, NULL, pexit->keyword, TO_ROOM );
			REMOVE_BIT(pexit->exit_info, EX_CLOSED);
		}
		else
		{
			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 )
	{
		send_to_char( "What?  And leave your beloved master?\n\r", ch );
		return;
	}

	if (IS_NPC(ch) && (mount=ch->mount) != NULL && IS_SET(ch->mounted,IS_MOUNT))
	{
		send_to_char( "You better wait for instructions from your rider.\n\r", ch );
		return;
	}

	if ( room_is_private( to_room ))
	{
		if ( IS_NPC( ch ) || ch->trust < MAX_LEVEL)
		{
			send_to_char( "That room is private right now.\n\r", ch );
			return;
		}
		else 
			send_to_char( "That room is private (Access granted).\n\r", ch);
	}

	if ( (IS_LEG_L(ch,BROKEN_LEG) || IS_LEG_L(ch,LOST_LEG)) &&
			(IS_LEG_R(ch,BROKEN_LEG) || IS_LEG_R(ch,LOST_LEG)) &&
			(IS_ARM_L(ch,BROKEN_ARM) || IS_ARM_L(ch,LOST_ARM) ||
			 get_eq_char(ch, WEAR_HOLD) != NULL) &&
			(IS_ARM_R(ch,BROKEN_ARM) || IS_ARM_R(ch,LOST_ARM) ||
			 get_eq_char(ch, WEAR_WIELD) != NULL))
	{
		send_to_char( "You need at least one free arm to drag yourself with.\n\r", ch );
		return;
	}
	else if ( IS_BODY(ch,BROKEN_SPINE) &&
			(IS_ARM_L(ch,BROKEN_ARM) || IS_ARM_L(ch,LOST_ARM) ||
			 get_eq_char(ch, WEAR_HOLD) != NULL) &&
			(IS_ARM_R(ch,BROKEN_ARM) || IS_ARM_R(ch,LOST_ARM) ||
			 get_eq_char(ch, WEAR_WIELD) != NULL))
	{
		send_to_char( "You cannot move with a broken spine.\n\r", ch );
		return;
	}

	if ( !IS_NPC(ch) )
	{
		int move;
		if ( in_room->sector_type == SECT_AIR
				||   to_room->sector_type == SECT_AIR )
		{
			if ( !IS_AFFECTED(ch, AFF_FLYING) &&
					(!IS_NPC(ch) && !IS_VAMPAFF(ch, VAM_FLYING))
					&&   !((mount=ch->mount) != NULL && IS_SET(ch->mounted,IS_RIDING) &&
						IS_AFFECTED(mount, AFF_FLYING) ) )
			{
				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 )
		{
			OBJ_DATA *obj;
			bool found;

			/*
			 * Look for a boat.
			 */
			found = FALSE;
			if ( !IS_NPC(ch) && IS_CLASS(ch, CLASS_VAMPIRE))
			{
				if ( IS_VAMPAFF(ch, VAM_FLYING) )
					found = TRUE;
				else if (IS_SWWF(ch) && get_tribe(ch, TRIBE_STARGAZERS) > 0)
					found = TRUE;
				else if (IS_SWWF(ch) && get_tribe(ch, TRIBE_UKTENA) > 1)
					found = TRUE;
				else if ( IS_POLYAFF(ch, POLY_SERPENT) )
					found = TRUE;
				else if ((mount=ch->mount) != NULL && IS_SET(ch->mounted, IS_RIDING) 
						&& IS_AFFECTED(mount, AFF_FLYING))
					found = TRUE;
				else
				{
					send_to_char( "You are unable to cross running water.\n\r", ch );
					return;
				}
			}
			if ( IS_AFFECTED(ch, AFF_FLYING) )
				found = TRUE;

			if ( !found )
			{
				for ( obj = ch->carrying; obj != NULL; obj = obj->next_content )
				{
					if ( obj->item_type == ITEM_BOAT )
					{
						found = TRUE;
						break;
					}
				}
				if ( !found )
				{
					send_to_char( "You need a boat to go there.\n\r", ch );
					return;
				}
			}
		}
		else if ( !IS_AFFECTED(ch, AFF_FLYING) && IS_POLYAFF(ch, POLY_FISH) )
		{
			bool from_ok = FALSE;
			bool to_ok = FALSE;
			if ( in_room->sector_type == SECT_WATER_NOSWIM ) from_ok = TRUE;
			if ( in_room->sector_type == SECT_WATER_SWIM   ) from_ok = TRUE;
			if ( to_room->sector_type == SECT_WATER_NOSWIM ) to_ok   = TRUE;
			if ( to_room->sector_type == SECT_WATER_SWIM   ) to_ok   = TRUE;
			if ( !from_ok || !to_ok )
			{
				send_to_char("You cannot cross land.\n\r",ch);
				return;
			}
		}

		move = movement_loss[UMIN(SECT_MAX-1, in_room->sector_type)]
			+ movement_loss[UMIN(SECT_MAX-1, to_room->sector_type)]
			;

		if (IS_HERO(ch)) move = 0;

		if(ch->move <= 0)
		{
			send_to_char("You are too Exhausted.\n\r",ch);
			return;
		}

		if (IS_SET(ch->mounted, IS_RIDING) && (ch->move < move || ch->move < 1))
		{
			send_to_char( "You are too exhausted.\n\r", ch );
			return;
		}

		WAIT_STATE( ch, 1 );
		if (!IS_SET(ch->mounted, IS_RIDING)) ch->move -= move;
	}

	/* Check for mount message - KaVir */
	if ( (mount = ch->mount) != NULL && ch->mounted == IS_RIDING )
	{
		if (IS_NPC(mount))
			sprintf(mount2," on %s.",mount->short_descr->str);
		else
			sprintf(mount2," on %s.",mount->name->str);
	}
	else
		sprintf(mount2,".");

	if ( IS_HEAD(ch,LOST_HEAD) || IS_EXTRA(ch,EXTRA_OSWITCH) )
		sprintf(leave,"rolls");
	else if ( ch->in_room->sector_type == SECT_WATER_SWIM )
		sprintf(leave,"swims");
	else if ( IS_SET(ch->polyaff,POLY_SERPENT) )
		sprintf(leave,"slithers");
	else if ( IS_SET(ch->polyaff,POLY_WOLF) )
		sprintf(leave,"stalks");
	else if ( IS_SET(ch->polyaff,POLY_FROG) )
		sprintf(leave,"hops");
	else if ( IS_SET(ch->polyaff,POLY_FISH) )
		sprintf(leave,"swims");
	else if ( IS_BODY(ch,BROKEN_SPINE) )
		sprintf(leave,"drags $mself");
	else if ( IS_LEG_L(ch,LOST_LEG) && IS_LEG_R(ch,LOST_LEG) )
		sprintf(leave,"drags $mself");
	else if ( (IS_LEG_L(ch,BROKEN_LEG) || IS_LEG_L(ch,LOST_LEG) || IS_LEG_L(ch,LOST_FOOT)) &&
			(IS_LEG_R(ch,BROKEN_LEG) || IS_LEG_R(ch,LOST_LEG) || IS_LEG_R(ch,LOST_FOOT)) )
		sprintf(leave,"crawls");
	else if ( ch->hit < (ch->max_hit/4) )
		sprintf(leave,"crawls");
	else if ( (IS_LEG_R(ch,LOST_LEG) || IS_LEG_R(ch,LOST_FOOT)) &&
			(!IS_LEG_L(ch,BROKEN_LEG) && !IS_LEG_L(ch,LOST_LEG) && 
			 !IS_LEG_L(ch,LOST_FOOT)) )
		sprintf(leave,"hops");
	else if ( (IS_LEG_L(ch,LOST_LEG) || IS_LEG_L(ch,LOST_FOOT)) &&
			(!IS_LEG_R(ch,BROKEN_LEG) && !IS_LEG_R(ch,LOST_LEG) &&
			 !IS_LEG_R(ch,LOST_FOOT)) )
		sprintf(leave,"hops");
	else if ( (IS_LEG_L(ch,BROKEN_LEG) || IS_LEG_L(ch,LOST_FOOT)) &&
			(!IS_LEG_R(ch,BROKEN_LEG) && !IS_LEG_R(ch,LOST_LEG) &&
			 !IS_LEG_R(ch,LOST_FOOT)) )
		sprintf(leave,"limps");
	else if ( (IS_LEG_R(ch,BROKEN_LEG) || IS_LEG_R(ch,LOST_FOOT)) &&
			(!IS_LEG_L(ch,BROKEN_LEG) && !IS_LEG_L(ch,LOST_LEG) &&
			 !IS_LEG_L(ch,LOST_FOOT)) )
		sprintf(leave,"limps");
	else if ( ch->hit < (ch->max_hit/3) )
		sprintf(leave,"limps");
	else if ( ch->hit < (ch->max_hit/2) )
		sprintf(leave,"staggers");
	else if ( !IS_NPC(ch) )
	{
		if (ch->pcdata->condition[COND_DRUNK] > 10)
			sprintf(leave,"staggers");
		else
			sprintf(leave,"walks");
	}
	else
		sprintf(leave,"walks");

	if (!IS_NPC(ch) && ch->stance[0] != -1) do_stance(ch,"");

	for ( desc_list = descriptor_list; desc_list != NULL; desc_list = g_slist_next(desc_list) )
	{
		d = (DESCRIPTOR_DATA*)desc_list->data;

		if ( ( victim = d->character ) == NULL )
			continue;

		if ( ch->in_room == NULL || victim->in_room == NULL ) continue;

		if ( ch == victim || ch->in_room != victim->in_room) continue;

		if ( d->connected != CON_PLAYING )
			continue;

		if (!can_see(victim,ch) && !IS_ADDED(victim, ADDED_DISCERN))
			continue;

		if (IS_AFFECTED(ch, AFF_SNEAK) && (!IS_IMMORTAL(victim) && !IS_ADDED(victim,ADDED_DISCERN)))
			continue;

		if ( !IS_NPC(ch) && IS_AFFECTED(ch,AFF_POLYMORPH))
		{
			mxpout = g_string_new("");
			if (((mount = ch->mount) != NULL && ch->mounted == IS_RIDING &&
						IS_AFFECTED(mount,AFF_FLYING)) || IS_AFFECTED(ch,AFF_FLYING) ||
					(!IS_NPC(ch) && IS_VAMPAFF(ch,VAM_FLYING)) ){
				sprintf(poly,"{W%s flies %s%s{x",ch->morph->str,dir_name[door],mount2);
				mxpconv(mxpout,poly,victim);
			}
			else if ( (mount = ch->mount) != NULL && ch->mounted == IS_RIDING ){
				sprintf(poly,"{W%s rides %s%s{x",ch->morph->str,dir_name[door],mount2);
				mxpconv(mxpout,poly,victim);
			}
			else{
				sprintf(poly,"{W%s %s %s%s{x",ch->morph->str,leave,dir_name[door],mount2);
				mxpconv(mxpout,poly,victim);
			}
			act( mxpout->str, victim, NULL, victim, TO_CHAR );
			g_string_free(mxpout,TRUE);
		}
		else 
		{
			mxpout = g_string_new("");
			if (((mount = ch->mount) != NULL && ch->mounted == IS_RIDING &&
						IS_AFFECTED(mount,AFF_FLYING)) || IS_AFFECTED(ch,AFF_FLYING) ||
					(!IS_NPC(ch) && IS_VAMPAFF(ch,VAM_FLYING)) ){
				sprintf(poly,"{W$n flies %s%s{x",dir_name[door],mount2);
				mxpconv(mxpout,poly,victim);
			}
			else if ( (mount = ch->mount) != NULL && ch->mounted == IS_RIDING ){
				sprintf(poly,"{W$n rides %s%s{x",dir_name[door],mount2);
				mxpconv(mxpout,poly,victim);
			}
			else{
				sprintf(poly,"{W$n %s %s%s{x",leave,dir_name[door],mount2);
				mxpconv(mxpout,poly,victim);
			}
			act( mxpout->str, ch, NULL, victim, TO_VICT );
			g_string_free(mxpout,TRUE);
		}
	}
	char_from_room( ch );
	char_to_room( ch, to_room );
	if      ( door == 0 ) {revdoor = 2;sprintf(buf,"the south");}
	else if ( door == 1 ) {revdoor = 3;sprintf(buf,"the west");}
	else if ( door == 2 ) {revdoor = 0;sprintf(buf,"the north");}
	else if ( door == 3 ) {revdoor = 1;sprintf(buf,"the east");}
	else if ( door == 4 ) {revdoor = 5;sprintf(buf,"below");}
	else                  {revdoor = 4;sprintf(buf,"above");}

	for ( desc_list = descriptor_list; desc_list != NULL; desc_list = g_slist_next(desc_list) )
	{
		d = (DESCRIPTOR_DATA*)desc_list->data;

		if ( ( victim = d->character ) == NULL )
			continue;

		if ( ch->in_room == NULL || victim->in_room == NULL ) continue;

		if ( ch == victim || ch->in_room != victim->in_room) continue;

		if ( d->connected != CON_PLAYING )
			continue;

		if (!can_see(victim,ch) && !IS_ADDED(victim, ADDED_DISCERN))
			continue;

		if (IS_AFFECTED(ch, AFF_SNEAK) && (!IS_IMMORTAL(victim) && !IS_ADDED(victim,ADDED_DISCERN)))
			continue;

		if ( !IS_NPC(ch) && IS_AFFECTED(ch,AFF_POLYMORPH))
		{
			if (((mount = ch->mount) != NULL && ch->mounted == IS_RIDING &&
						IS_AFFECTED(mount,AFF_FLYING)) || IS_AFFECTED(ch,AFF_FLYING) ||
					(!IS_NPC(ch) && IS_VAMPAFF(ch,VAM_FLYING)) )
				sprintf(poly,"{W%s flies in from %s%s{x",ch->morph->str,buf,mount2);
			else if ( (mount = ch->mount) != NULL && ch->mounted == IS_RIDING )
				sprintf(poly,"{W%s rides in from %s%s{x",ch->morph->str,buf,mount2);
			else
				sprintf(poly,"{W%s %s in from %s%s{x",ch->morph->str,leave,buf,mount2);
			act( poly, ch, NULL, victim, TO_VICT );
		}
		else 
		{
			if (((mount = ch->mount) != NULL && ch->mounted == IS_RIDING &&
						IS_AFFECTED(mount,AFF_FLYING)) || IS_AFFECTED(ch,AFF_FLYING) ||
					(!IS_NPC(ch) && IS_VAMPAFF(ch,VAM_FLYING)) )
				sprintf( poly, "{W$n flies in from %s%s{x",buf,mount2);
			else if ( (mount = ch->mount) != NULL && ch->mounted == IS_RIDING )
				sprintf(poly,"{W$n rides in from %s%s{x",buf,mount2);
			else
				sprintf( poly, "{W$n %s in from %s%s{x",leave,buf,mount2);
			act( poly, ch, NULL, victim, TO_VICT );
		}
	}

	do_look( ch, "auto" );

	if (IS_ADDED(ch, ADDED_VOICESOFCASTLE))
	{
		send_to_char("The Voices Stop.\n\r",ch);
		REMOVE_BIT(ch->added, ADDED_VOICESOFCASTLE);
	}

	for ( fch = in_room->people; fch != NULL; fch = fch_next )
	{
		fch_next = fch->next_in_room;
		if ( (mount = fch->mount) != NULL && mount == ch && IS_SET(fch->mounted,IS_MOUNT))
		{
			act( "{W$N digs $S heels into you.{x", fch, NULL, ch, TO_CHAR );
			char_from_room(fch);
			char_to_room(fch,ch->in_room);
		}

		if ( fch->master == ch && fch->position == POS_STANDING 
				&& fch->in_room != ch->in_room)
		{
			act( "You follow $N.", fch, NULL, ch, TO_CHAR );
			move_char( fch, door );
		}
	}

	/* 
	 * If someone is following the char, these triggers get activated
	 * for the followers before the char, but it's safer this way...
	 */
	if ( IS_NPC( ch ) && HAS_TRIGGER( ch, TRIG_ENTRY ) )
		mp_percent_trigger( ch, NULL, NULL, NULL, TRIG_ENTRY );
	if ( !IS_NPC( ch ) )
		mp_greet_trigger( ch );

	if ( HAS_PROG(ch->in_room, TRIG_ENTRY) )
		rprog_percent_trigger(ch->in_room, ch, NULL, NULL, TRIG_ENTRY);

	for ( to_obj = ch->in_room->contents; to_obj;	to_obj = to_obj->next_content )
	{
		if ( HAS_PROG(to_obj->pIndexData, TRIG_ENTRY) )
			oprog_percent_trigger(to_obj, ch, NULL, NULL, TRIG_ENTRY);
	}

	/* look for pets entering/leaving the room*/
	if (IS_NPC(ch) && IS_PET(ch))
		check_pet_reaction(ch);

	room_text(ch,">ENTER<");
	/* clear the roompose */
	if (!IS_NPC(ch))
	{
		ch->pcdata->roompose = g_string_assign(ch->pcdata->roompose,"");
	}
	return;
}

/*!
 * char_data wanted to move north
 */

void do_north( CHAR_DATA *ch, char *argument )
{
	ROOM_INDEX_DATA *in_room;
	
	if (IS_AFFECTED(ch, AFF_WEBBED))
	{
		send_to_char("You are unable to move with all this sticky webbing on.\n\r",ch);
		return;
	}
	in_room = ch->in_room;
	move_char( ch, DIR_NORTH );
	if (!IS_NPC(ch) && ch->in_room != in_room)
	{
		ROOM_INDEX_DATA *old_room;
		old_room = ch->in_room;
		char_from_room(ch);
		char_to_room(ch, in_room);
		add_tracks( ch, DIR_NORTH );
		char_from_room(ch);
		char_to_room(ch, old_room);
	}
/*
    if (!IS_NPC(ch) && ch->in_room != in_room) add_tracks( ch, DIR_SOUTH );
*/
	return;
}



void do_east( CHAR_DATA *ch, char *argument )
{
	ROOM_INDEX_DATA *in_room;
	
	if (IS_AFFECTED(ch, AFF_WEBBED))
	{
		send_to_char("You are unable to move with all this sticky webbing on.\n\r",ch);
		return;
	}
	in_room = ch->in_room;
	move_char( ch, DIR_EAST );
	if (!IS_NPC(ch) && ch->in_room != in_room)
	{
		ROOM_INDEX_DATA *old_room;
		old_room = ch->in_room;
		char_from_room(ch);
		char_to_room(ch, in_room);
		add_tracks( ch, DIR_EAST );
		char_from_room(ch);
		char_to_room(ch, old_room);
	}
/*
    if (!IS_NPC(ch) && ch->in_room != in_room) add_tracks( ch, DIR_WEST );
*/
	return;
}



void do_south( CHAR_DATA *ch, char *argument )
{
	ROOM_INDEX_DATA *in_room;
	
	if (IS_AFFECTED(ch, AFF_WEBBED))
	{
		send_to_char("You are unable to move with all this sticky webbing on.\n\r",ch);
		return;
	}
	in_room = ch->in_room;
	move_char( ch, DIR_SOUTH );
	if (!IS_NPC(ch) && ch->in_room != in_room)
	{
		ROOM_INDEX_DATA *old_room;
		old_room = ch->in_room;
		char_from_room(ch);
		char_to_room(ch, in_room);
		add_tracks( ch, DIR_SOUTH );
		char_from_room(ch);
		char_to_room(ch, old_room);
	}
/*
    if (!IS_NPC(ch) && ch->in_room != in_room) add_tracks( ch, DIR_NORTH );
*/
	return;
}



void do_west( CHAR_DATA *ch, char *argument )
{
	ROOM_INDEX_DATA *in_room;
	
	if (IS_AFFECTED(ch, AFF_WEBBED))
	{
		send_to_char("You are unable to move with all this sticky webbing on.\n\r",ch);
		return;
	}
	in_room = ch->in_room;
	move_char( ch, DIR_WEST );
	if (!IS_NPC(ch) && ch->in_room != in_room)
	{
		ROOM_INDEX_DATA *old_room;
		old_room = ch->in_room;
		char_from_room(ch);
		char_to_room(ch, in_room);
		add_tracks( ch, DIR_WEST );
		char_from_room(ch);
		char_to_room(ch, old_room);
	}
/*
    if (!IS_NPC(ch) && ch->in_room != in_room) add_tracks( ch, DIR_EAST );
*/
	return;
}



void do_up( CHAR_DATA *ch, char *argument )
{
	ROOM_INDEX_DATA *in_room;
	
	if (IS_AFFECTED(ch, AFF_WEBBED))
	{
		send_to_char("You are unable to move with all this sticky webbing on.\n\r",ch);
		return;
	}
	in_room = ch->in_room;
	move_char( ch, DIR_UP );
	if (!IS_NPC(ch) && ch->in_room != in_room)
	{
		ROOM_INDEX_DATA *old_room;
		old_room = ch->in_room;
		char_from_room(ch);
		char_to_room(ch, in_room);
		add_tracks( ch, DIR_UP );
		char_from_room(ch);
		char_to_room(ch, old_room);
	}
/*
    if (!IS_NPC(ch) && ch->in_room != in_room) add_tracks( ch, DIR_DOWN );
*/
	return;
}



void do_down( CHAR_DATA *ch, char *argument )
{
	ROOM_INDEX_DATA *in_room;
	
	if (IS_AFFECTED(ch, AFF_WEBBED))
	{
		send_to_char("You are unable to move with all this sticky webbing on.\n\r",ch);
		return;
	}
	in_room = ch->in_room;
	move_char( ch, DIR_DOWN );
	if (!IS_NPC(ch) && ch->in_room != in_room)
	{
		ROOM_INDEX_DATA *old_room;
		old_room = ch->in_room;
		char_from_room(ch);
		char_to_room(ch, in_room);
		add_tracks( ch, DIR_DOWN );
		char_from_room(ch);
		char_to_room(ch, old_room);
	}
/*
    if (!IS_NPC(ch) && ch->in_room != in_room) add_tracks( ch, DIR_UP );
*/
	return;
}



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)
				&&   strcmp(pexit->keyword,"")
				&&   is_name( arg, pexit->keyword ) )
				return door;
		}
		act( "I see no $T here.", ch, NULL, arg, TO_CHAR );
		return -1;
	}
	
	if ( ( pexit = ch->in_room->exit[door] ) == NULL )
	{
		act( "I see no door $T here.", ch, NULL, arg, TO_CHAR );
		return -1;
	}
	
	if ( !IS_SET(pexit->exit_info, EX_ISDOOR) )
	{
		send_to_char( "You can't do that.\n\r", ch );
		return -1;
	}
	
	return door;
}

/* Designed for the portal spell, but can also have other uses...KaVir
 * V0 = Where the portal will take you.
 * V1 = Number of uses (0 is infinate).
 * V2 = if 2, cannot be entered.
 * V3 = The room the portal is currently in.
 */
void do_enter( CHAR_DATA *ch, char *argument )
{
	ROOM_INDEX_DATA *pRoomIndex;
	ROOM_INDEX_DATA *location;
	char arg[MAX_INPUT_LENGTH];
	char poly [MAX_INPUT_LENGTH];
	OBJ_DATA *obj;
	OBJ_DATA *portal;
	OBJ_DATA *portal_next;
	CHAR_DATA *mount;
	bool found;
	
	argument = one_argument( argument, arg );
	
	if ( arg[0] == '\0' )
	{
		send_to_char( "Enter what?\n\r", ch );
		return;
	}
	
	obj = get_obj_list( ch, arg, ch->in_room->contents );
	if ( obj == NULL )
	{
		act( "I see no $T here.", ch, NULL, arg, TO_CHAR );
		return;
	}
	if ( obj->item_type != ITEM_PORTAL )
	{
		act( "You cannot enter that.", ch, NULL, arg, TO_CHAR );
		return;
	}
	
	if ( ch->delay_timer > 1) 
	{
		send_to_char("Not with a delay timer...\n\r",ch);
		return;
	}
	
	if ( obj->value[2] == 2 || obj->value[2] == 3 )
	{
		act( "It seems to be closed.", ch, NULL, arg, TO_CHAR );
		return;
	}
	
	if (obj->plane != ch->plane)
	{
		act( "It seems to be on a diffrent plane then you are right now.", ch, NULL, arg, TO_CHAR );
		return;
	}

	pRoomIndex = get_room_index(obj->value[0]);
	location = ch->in_room;
	
	if ( pRoomIndex == NULL )
	{
		act( "You are unable to enter.", ch, NULL, arg, TO_CHAR );
		return;
	}
	
	act( "You step into $p.",  ch, obj, NULL, TO_CHAR );
	if ( !IS_NPC(ch) && IS_AFFECTED(ch,AFF_POLYMORPH) )
		sprintf(poly,"%s steps into $p.",ch->morph->str);
	else
		sprintf(poly,"$n steps into $p.");
	act( poly,  ch, obj, NULL, TO_ROOM );
	char_from_room(ch);
	char_to_room(ch,pRoomIndex);
	str_cpy(poly,"Someone steps out of $p.");
	act( poly,  ch, obj, NULL, TO_ROOM );
	char_from_room(ch);
	char_to_room(ch,location);
	
    if (obj->value[1] != 0)
	{
		obj->value[1] = obj->value[1] - 1;
		if (obj->value[1] < 1)
		{
			act( "$p vanishes.",  ch, obj, NULL, TO_CHAR );
			act( "$p vanishes.",  ch, obj, NULL, TO_ROOM );
			extract_obj(obj);
		}
	}
	char_from_room(ch);
	char_to_room(ch,pRoomIndex);
	found = FALSE;
	for ( portal = ch->in_room->contents; portal != NULL; portal = portal_next )
	{
		portal_next = portal->next_content;
		if ( ( obj->value[0] == portal->value[3]  )
			&& (obj->value[3] == portal->value[0]) )
		{
			found = TRUE;
			if (portal->value[1] != 0)
			{
				portal->value[1] = portal->value[1] - 1;
				if (portal->value[1] < 1)
				{
					act( "$p vanishes.",  ch, portal, NULL, TO_CHAR );
					act( "$p vanishes.",  ch, portal, NULL, TO_ROOM );
					extract_obj(portal);
				}
			}
		}
	}
	do_look(ch,"auto");
	if ( ( mount = ch->mount ) == NULL ) return;
	char_from_room( mount );
	char_to_room( mount, ch->in_room );
 	/* 
 	 * If someone is following the char, these triggers get activated
 	 * for the followers before the char, but it's safer this way...
 	 */
	if ( IS_NPC( ch ) && HAS_TRIGGER( ch, TRIG_ENTRY ) )
		mp_percent_trigger( ch, NULL, NULL, NULL, TRIG_ENTRY );
	if ( !IS_NPC( ch ) )
		mp_greet_trigger( ch );
	return;
}


void do_open( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	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, arg ) ) != NULL )
	{
	/* 'open object' */
		if ( obj->item_type != ITEM_CONTAINER && obj->item_type != ITEM_BOOK)
		{ 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) && obj->item_type != ITEM_BOOK)
		{ 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);
		send_to_char( "Ok.\n\r", ch );
		act( "$n opens $p.", ch, obj, NULL, TO_ROOM );
		return;
	}
	
	if ( ( door = find_door( ch, arg ) ) >= 0 )
	{
	/* 'open door' */
		ROOM_INDEX_DATA *to_room;
		EXIT_DATA *pexit;
		EXIT_DATA *pexit_rev;
		
		pexit = ch->in_room->exit[door];
		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);
		playwave_toroom(ch,7);
		act( "$n opens the $d.", ch, NULL, pexit->keyword, TO_ROOM );
		send_to_char( "Ok.\n\r", ch );
		
	/* open the other side */
		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 );
			for ( rch = to_room->people; rch != NULL; rch = rch->next_in_room )
				act( "The $d opens.", rch, NULL, pexit_rev->keyword, TO_CHAR );
		}
	}
	
	return;
}



void do_close( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	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, arg ) ) != NULL )
	{
	/* 'close object' */
		if ( obj->item_type != ITEM_CONTAINER && obj->item_type != ITEM_BOOK)
		{ 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) && obj->item_type != ITEM_BOOK )
		{ send_to_char( "You can't do that.\n\r",      ch ); return; }
		
		SET_BIT(obj->value[1], CONT_CLOSED);
		//if (obj->item_type == ITEM_BOOK) obj->value[2] = 0;
		send_to_char( "Ok.\n\r", ch );
		act( "$n closes $p.", ch, obj, NULL, TO_ROOM );
		return;
	}
	
	if ( ( door = find_door( ch, arg ) ) >= 0 )
	{
	/* 'close door' */
		ROOM_INDEX_DATA *to_room;
		EXIT_DATA *pexit;
		EXIT_DATA *pexit_rev;
		
		pexit	= ch->in_room->exit[door];
		if ( IS_SET(pexit->exit_info, EX_CLOSED) )
		{ send_to_char( "It's already closed.\n\r",    ch ); return; }
		
		SET_BIT(pexit->exit_info, EX_CLOSED);
		act( "$n closes the $d.", ch, NULL, pexit->keyword, TO_ROOM );
		send_to_char( "Ok.\n\r", ch );
		
	/* close the other side */
		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 );
			for ( rch = to_room->people; rch != NULL; rch = rch->next_in_room )
				act( "The $d closes.", rch, NULL, pexit_rev->keyword, TO_CHAR );
		}
	}
	
	return;
}



void do_turn( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	OBJ_DATA *obj;
	int value = 0;
	
	argument = one_argument( argument, arg1 );
	argument = one_argument( argument, arg2 );
	
	if ( arg1[0] == '\0' || arg2[0] == '\0' )
	{
		send_to_char( "Syntax: Turn <book> <forward/back>.\n\r", ch );
		return;
	}
	
	if (is_number(arg2)) value = atoi(arg2);
	
	if ( ( obj = get_obj_here( ch, arg1 ) ) == NULL )
	{
		send_to_char("You don't have that book.\n\r",ch);
		return;
	}
	
	if ( obj->item_type != ITEM_BOOK)
	{ send_to_char( "That's not a book.\n\r", ch ); return; }
	if ( IS_SET(obj->value[1], CONT_CLOSED) )
	{ send_to_char( "First you should open it.\n\r",    ch ); return; }
	
	if (!str_cmp(arg2,"f") || !str_cmp(arg2,"forward"))
	{
		if (obj->value[2] >= obj->value[3])
		{
			send_to_char("But you are already at the end of the book.\n\r",ch);
			return;
		}
		obj->value[2] += 1;
		act( "You flip forward a page in $p.", ch, obj, NULL, TO_CHAR );
		act( "$n flips forward a page in $p.", ch, obj, NULL, TO_ROOM );
	}
	else if (!str_cmp(arg2,"b") || !str_cmp(arg2,"backward"))
	{
		if (obj->value[2] <= 0)
		{
			send_to_char("But you are already at the beginning of the book.\n\r",ch);
			return;
		}
		obj->value[2] -= 1;
		act( "You flip backward a page in $p.", ch, obj, NULL, TO_CHAR );
		act( "$n flips backward a page in $p.", ch, obj, NULL, TO_ROOM );
	}
	else if (is_number(arg2) && value >= 0 && value <= obj->value[3])
	{
		if (value == obj->value[2])
		{
			act("$p is already open at that page.",ch,obj,NULL,TO_CHAR);
			return;
		}
		else if (value < obj->value[2])
		{
			act( "You flip backwards through $p.", ch, obj, NULL, TO_CHAR );
			act( "$n flips backwards through $p.", ch, obj, NULL, TO_ROOM );
		}
		else
		{
			act( "You flip forwards through $p.", ch, obj, NULL, TO_CHAR );
			act( "$n flips forwards through $p.", ch, obj, NULL, TO_ROOM );
		}
		obj->value[2] = value;
	}
	else
		send_to_char("Do you wish to turn forward or backward a page?\n\r",ch);
	return;
}

void do_read( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char buf[MAX_STRING_LENGTH];
	OBJ_DATA *obj;
	
	argument = one_argument( argument, arg );
	argument = one_argument( argument, arg2 );
	
	if ( arg[0] == '\0' )
	{
		send_to_char( "What do you wish to read?\n\r", ch );
		return;
	}
	
	if ( ( obj = get_obj_here( ch, arg ) ) == NULL )
	{
		send_to_char("You don't have that book.\n\r",ch);
		return;
	}
	
	if ( obj->item_type == ITEM_PAGE)
	{
		if (!str_cmp(obj->victpoweruse->str,"(null)"))
			sprintf(buf,"Untitled page.\n\r");
		else
			sprintf(buf,"%s.\n\r",obj->victpoweruse->str);
		buf[0] = UPPER(buf[0]);
		send_to_char(buf,ch);
		send_to_char("--------------------------------------------------------------------------------\n\r",ch);
		send_to_char(obj->page_content->str,ch);
		send_to_char("\n\r--------------------------------------------------------------------------------\n\r",ch);
	   return;
	}
	
	if ( obj->item_type != ITEM_BOOK)
	{ send_to_char( "That's not a book.\n\r", ch ); return; }
	if ( IS_SET(obj->value[1], CONT_CLOSED) )
	{
		if (!str_cmp(obj->victpoweruse->str,"(null)"))
			sprintf(buf,"The book is untitled.\n\r");
		else
			sprintf(buf,"The book is titled '%s'.\n\r",obj->victpoweruse->str);
		buf[0] = UPPER(buf[0]);
		send_to_char(buf,ch);
		return;
	}
	
	if (obj->value[2] > 1)
	{
		if (arg2[0] == '\0')
		{
			int page;
		
			send_to_char("Index page.\n\r",ch);
			if (obj->value[3] <= 0)
			{
				send_to_char("<No pages>\n\r",ch);
				return;
			}
			for ( page = 1; page <= obj->value[3]; page ++ )
			{
				sprintf(buf,"Page %d:",page);
				send_to_char(buf,ch);
				show_page(ch,obj,page,TRUE);
			}
		}
		else
		{
			sprintf(buf,"Page %d:",atoi(arg2));
			send_to_char(buf,ch);
			show_page(ch,obj,atoi(arg2),FALSE);
		}
	}
	else
	{
		sprintf(buf,"Page %d:",obj->value[2]);
		send_to_char(buf,ch);
		show_page(ch,obj,obj->value[2],FALSE);
	}
	return;
}
void do_write( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char arg3[MAX_INPUT_LENGTH];
	char buf[MAX_STRING_LENGTH];
	OBJ_DATA *obj;
	
	smash_tilde( argument );
	argument = one_argument( argument, arg1 );
	argument = one_argument( argument, arg2 );
	str_cpy( arg3, argument );
	
	if (IS_NPC(ch)) return;
	if ( arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0' )
	{
		send_to_char("Syntax: Write <page> <title/line> <text>.\n\r",ch);
		return;
	}
	
	if ( ( ( ( obj = get_eq_char(ch, WEAR_HOLD) ) != NULL) && 
		( obj->item_type != ITEM_TOOL || !IS_SET(obj->value[0],TOOL_PEN) ) )
		|| obj == NULL)
	{
		if ( ( ( ( obj = get_eq_char(ch, WEAR_WIELD) ) != NULL) && 
			( obj->item_type != ITEM_TOOL || !IS_SET(obj->value[0],TOOL_PEN) ) )
			|| obj == NULL)
		{
			send_to_char("You are not holding a pen.\n\r",ch);
			return;
		}
	}
	
	if ( ( obj = get_obj_carry( ch, arg1) ) == NULL )
	{
		send_to_char("You are not carrying that item.\n\r",ch);
		return;
	}
	if ( obj->item_type != ITEM_PAGE && obj->item_type != ITEM_BOOK )
	{
		send_to_char("You cannot write on that.\n\r",ch);
		return;
	}
	if (!str_cmp( arg2,"title"))
	{
		obj->victpoweruse = g_string_assign(obj->victpoweruse, arg3 );
		send_to_char("Ok.\n\r",ch);
		act("$n writes something on $p.",ch,obj,NULL,TO_ROOM);
		return;
	}
	else if (str_cmp( arg2,"line"))
	{
		send_to_char("You can write a TITLE or a LINE.\n\r",ch);
		return;
	}
	else if ( obj->item_type == ITEM_BOOK )
	{
		send_to_char("You can only write a title on the book.\n\r",ch);
		return;
	}
	
	act("$n writes something on $p.",ch,obj,NULL,TO_ROOM);
	smash_tilde( arg3 );
	
	
	if ( arg3[0] == '+' )
	{
		if ( obj->page_content != NULL )
		{
			buf[0] = '\0';
			
			if ( ch->description != NULL )
				strcat( buf, obj->page_content->str );
			
			argument++;
			while ( isspace(*argument) )
				argument++;
			
			if ( strlen(buf) + strlen(arg3) >= MAX_STRING_LENGTH - 2 )
			{
				send_to_char( "Page too long, Please start a new page.\n\r", ch );
				return;
			}
			
			strcat( buf, argument );
			strcat( buf,"\n\r");
			
			obj->page_content = g_string_assign(obj->page_content,buf);
			
			send_to_char("OK\n\r",ch);
			return;
		}
	}
	
	if ( !str_cmp(arg3,"clear"))
	{
		obj->page_content = g_string_assign(obj->page_content,"");
		send_to_char("Page cleared.\n\r",ch);
		return;
	}

	if ( strlen(arg3) >= MAX_LINE_LENGTH - 2 )
	{
		send_to_char( "Line too long.\n\r", ch );
		return;
	}
			
	strcat( arg3, "\n\r" );
	obj->page_content = g_string_assign(obj->page_content,arg3);
	send_to_char("Ok.\n\r",ch);
	return;
}

void show_page( CHAR_DATA *ch, OBJ_DATA *book, int pnum, bool pagefalse )
{
	OBJ_DATA *page;
	OBJ_DATA *page_next;
	char buf[MAX_STRING_LENGTH];
	bool found = FALSE;
	
	for ( page = book->contains; page != NULL; page = page_next )
	{
		page_next = page->next_content;
		if (page->value[0] == pnum)
		{
			found = TRUE;
			if (!str_cmp(page->victpoweruse->str,"(null)"))
				sprintf(buf,"Untitled page.\n\r");
			else
				sprintf(buf,"%s.\n\r",page->victpoweruse->str);
			buf[0] = UPPER(buf[0]);
			send_to_char(buf,ch);
			if (!pagefalse)
			{
				send_to_char("--------------------------------------------------------------------------------\n\r",ch);
				send_to_char(page->page_content->str,ch);
				send_to_char("\n\r--------------------------------------------------------------------------------\n\r",ch);
			}
		}
	}
	if (!found)
		send_to_char("This page has been torn out.\n\r",ch);
	return;
}

bool 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 TRUE;
	}
	
	return FALSE;
}



void do_lock( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	OBJ_DATA *obj;
	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, arg ) ) != NULL )
	{
	/* 'lock object' */
		if ( obj->item_type != ITEM_CONTAINER )
		{ send_to_char( "That's not a container.\n\r", ch ); return; }
		if ( !IS_SET(obj->value[1], CONT_CLOSED) )
		{ send_to_char( "It's not closed.\n\r",        ch ); return; }
		if ( obj->value[2] < 0 )
		{ send_to_char( "It can't be locked.\n\r",     ch ); return; }
		if ( !has_key( ch, obj->value[2] ) )
		{ send_to_char( "You lack the key.\n\r",       ch ); return; }
		if ( IS_SET(obj->value[1], CONT_LOCKED) )
		{ send_to_char( "It's already locked.\n\r",    ch ); return; }
		
		SET_BIT(obj->value[1], CONT_LOCKED);
		send_to_char( "*Click*\n\r", ch );
		act( "$n locks $p.", ch, obj, NULL, TO_ROOM );
		return;
	}
	
	if ( ( door = find_door( ch, arg ) ) >= 0 )
	{
	/* 'lock door' */
		ROOM_INDEX_DATA *to_room;
		EXIT_DATA *pexit;
		EXIT_DATA *pexit_rev;
		
		pexit	= ch->in_room->exit[door];
		if ( !IS_SET(pexit->exit_info, EX_CLOSED) )
		{ send_to_char( "It's not closed.\n\r",        ch ); return; }
		if ( pexit->key < 0 )
		{ send_to_char( "It can't be locked.\n\r",     ch ); return; }
		if ( !has_key( ch, pexit->key) )
		{ 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);
		send_to_char( "*Click*\n\r", ch );
		act( "$n locks the $d.", ch, NULL, pexit->keyword, TO_ROOM );
		
	/* lock the other side */
		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 );
		}
	}
	
	return;
}



void do_unlock( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	OBJ_DATA *obj;
	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, arg ) ) != NULL )
	{
	/* 'unlock object' */
		if ( obj->item_type != ITEM_CONTAINER )
		{ send_to_char( "That's not a container.\n\r", ch ); return; }
		if ( !IS_SET(obj->value[1], CONT_CLOSED) )
		{ send_to_char( "It's not closed.\n\r",        ch ); return; }
		if ( obj->value[2] < 0 )
		{ send_to_char( "It can't be unlocked.\n\r",   ch ); return; }
		if ( !has_key( ch, obj->value[2] ) )
		{ send_to_char( "You lack the key.\n\r",       ch ); return; }
		if ( !IS_SET(obj->value[1], CONT_LOCKED) )
		{ send_to_char( "It's already unlocked.\n\r",  ch ); return; }
		
		REMOVE_BIT(obj->value[1], CONT_LOCKED);
		send_to_char( "*Click*\n\r", ch );
		act( "$n unlocks $p.", ch, obj, NULL, TO_ROOM );
		return;
	}
	
	if ( ( door = find_door( ch, arg ) ) >= 0 )
	{
	/* 'unlock door' */
		ROOM_INDEX_DATA *to_room;
		EXIT_DATA *pexit;
		EXIT_DATA *pexit_rev;
		
		pexit = ch->in_room->exit[door];
		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 ( !has_key( ch, pexit->key) )
		{ 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);
		send_to_char( "*Click*\n\r", ch );
		act( "$n unlocks the $d.", ch, NULL, pexit->keyword, TO_ROOM );
		
	/* unlock the other side */
		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 );
		}
	}
	
	return;
}



void do_pick( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *gch;
	OBJ_DATA *obj;
	int door;
	
	one_argument( argument, arg );
	
	if ( arg[0] == '\0' )
	{
		send_to_char( "Pick what?\n\r", ch );
		return;
	}
	
	WAIT_STATE( ch, skill_table[gsn_pick_lock].beats );
	
    /* look for guards */
	for ( gch = ch->in_room->people; gch; gch = gch->next_in_room )
	{
		if ( IS_NPC(gch) && IS_AWAKE(gch) && ch->level + 5 < gch->level )
		{
		    if (IS_EXTRA(ch, EXTRA_AWE))
	    	{
				act( "$N steps aside to let you reach the lock.",ch, NULL, gch, TO_CHAR );
				act( "$N steps aside to let $n reach the lock.",ch, NULL, gch, TO_NOTVICT );
				act( "You step aside to let $n reach the lock.  Isn't $e awesome?",ch, NULL, gch, TO_VICT );
	    	}
	    	else
	    	{
				act( "$N is standing too close to the lock.",ch, NULL, gch, TO_CHAR );
				return;
	    	}
		}
	}
	
	if ( !IS_NPC(ch) && number_percent( ) > ch->pcdata->learned[gsn_pick_lock] )
	{
		send_to_char( "You failed.\n\r", ch);
		return;
	}
	
	if ( ( obj = get_obj_here( ch, arg ) ) != NULL )
	{
	/* 'pick object' */
		if ( obj->item_type != ITEM_CONTAINER )
		{ send_to_char( "That's not a container.\n\r", ch ); return; }
		if ( !IS_SET(obj->value[1], CONT_CLOSED) )
		{ send_to_char( "It's not closed.\n\r",        ch ); return; }
		if ( obj->value[2] < 0 )
		{ send_to_char( "It can't be unlocked.\n\r",   ch ); return; }
		if ( !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; }
		
		REMOVE_BIT(obj->value[1], CONT_LOCKED);
		send_to_char( "*Click*\n\r", ch );
		act( "$n picks $p.", ch, obj, NULL, TO_ROOM );
		return;
	}
	
	if ( ( door = find_door( ch, arg ) ) >= 0 )
	{
	/* 'pick door' */
		ROOM_INDEX_DATA *to_room;
		EXIT_DATA *pexit;
		EXIT_DATA *pexit_rev;
		
		pexit = ch->in_room->exit[door];
		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 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) )
		{ send_to_char( "You failed.\n\r",             ch ); 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 );
		
	/* pick the other side */
		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 );
		}
	}
	
	return;
}

void do_stand( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *obj = NULL;

    if (argument[0] != '\0')
    {
	if (ch->position == POS_FIGHTING)
	{
	    send_to_char("Maybe you should finish fighting first?\n\r",ch);
	    return;
	}
	obj = get_obj_list(ch,argument,ch->in_room->contents);
	if (obj == NULL)
	{
	    send_to_char("You don't see that here.\n\r",ch);
	    return;
	}
	if (obj->item_type != ITEM_FURNITURE
	||  (!IS_SET(obj->value[2],STAND_AT)
	&&   !IS_SET(obj->value[2],STAND_ON)
	&&   !IS_SET(obj->value[2],STAND_IN)))
	{
	    send_to_char("You can't seem to find a place to stand.\n\r",ch);
	    return;
	}
	if (ch->on != obj && count_users(obj) >= obj->value[0])
	{
	    act("There's no room to stand on $p.",
		ch,obj,NULL,TO_CHAR);
	    return;
	}
 	ch->on = obj;
    }
    
    switch ( ch->position )
    {
    case POS_SLEEPING:
	if ( IS_AFFECTED(ch, AFF_SLEEP) )
	    { send_to_char( "You can't wake up!\n\r", ch ); return; }
	
	if (obj == NULL)
	{
	    send_to_char( "You wake and stand up.\n\r", ch );
	    act( "$n wakes and stands up.", ch, NULL, NULL, TO_ROOM );
	    ch->on = NULL;
	}
	else if (IS_SET(obj->value[2],STAND_AT))
	{
	   act("You wake and stand at $p.",ch,obj,NULL,TO_CHAR);
	   act("$n wakes and stands at $p.",ch,obj,NULL,TO_ROOM);
	}
	else if (IS_SET(obj->value[2],STAND_ON))
	{
	    act("You wake and stand on $p.",ch,obj,NULL,TO_CHAR);
	    act("$n wakes and stands on $p.",ch,obj,NULL,TO_ROOM);
	}
	else 
	{
	    act("You wake and stand in $p.",ch,obj,NULL,TO_CHAR);
	    act("$n wakes and stands in $p.",ch,obj,NULL,TO_ROOM);
	}
	ch->position = POS_STANDING;
	do_look(ch,"auto");
	break;

    case POS_RESTING: case POS_SITTING:
	if (obj == NULL)
	{
	    send_to_char( "You stand up.\n\r", ch );
	    act( "$n stands up.", ch, NULL, NULL, TO_ROOM );
	    ch->on = NULL;
	}
	else if (IS_SET(obj->value[2],STAND_AT))
	{
	    act("You stand at $p.",ch,obj,NULL,TO_CHAR);
	    act("$n stands at $p.",ch,obj,NULL,TO_ROOM);
	}
	else if (IS_SET(obj->value[2],STAND_ON))
	{
	    act("You stand on $p.",ch,obj,NULL,TO_CHAR);
	    act("$n stands on $p.",ch,obj,NULL,TO_ROOM);
	}
	else
	{
	    act("You stand in $p.",ch,obj,NULL,TO_CHAR);
	    act("$n stands on $p.",ch,obj,NULL,TO_ROOM);
	}
	ch->position = POS_STANDING;
	break;

    case POS_MEDITATING:
	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;
    }

    return;
}
void do_rest( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *obj = NULL;

    if (ch->position == POS_FIGHTING)
    {
	send_to_char("You are already fighting!\n\r",ch);
	return;
    }

    /* okay, now that we know we can rest, find an object to rest on */
    if (argument[0] != '\0')
    {
	obj = get_obj_list(ch,argument,ch->in_room->contents);
	if (obj == NULL)
	{
	    send_to_char("You don't see that here.\n\r",ch);
	    return;
	}
    }
    else obj = ch->on;

    if (obj != NULL)
    {
        if (obj->item_type != ITEM_FURNITURE
    	||  (!IS_SET(obj->value[2],REST_ON)
    	&&   !IS_SET(obj->value[2],REST_IN)
    	&&   !IS_SET(obj->value[2],REST_AT)))
    	{
	    send_to_char("You can't rest on that.\n\r",ch);
	    return;
    	}

        if (obj != NULL && ch->on != obj && count_users(obj) >= obj->value[0])
        {
	    act("There's no more room on $p.",ch,obj,NULL,TO_CHAR);
	    return;
    	}
	
	ch->on = obj;
    }

    switch ( ch->position )
    {
    case POS_SLEEPING:
	if (IS_AFFECTED(ch,AFF_SLEEP))
	{
	    send_to_char("You can't wake up!\n\r",ch);
	    return;
	}

	if (obj == NULL)
	{
	    send_to_char( "You wake up and start resting.\n\r", ch );
	    act ("$n wakes up and starts resting.",ch,NULL,NULL,TO_ROOM);
	}
	else if (IS_SET(obj->value[2],REST_AT))
	{
	    act("You wake up and rest at $p.",
		    ch,obj,NULL,TO_CHAR);
	    act("$n wakes up and rests at $p.",ch,obj,NULL,TO_ROOM);
	}
        else if (IS_SET(obj->value[2],REST_ON))
        {
            act("You wake up and rest on $p.",
                    ch,obj,NULL,TO_CHAR);
            act("$n wakes up and rests on $p.",ch,obj,NULL,TO_ROOM);
        }
        else
        {
            act("You wake up and rest in $p.",
                    ch,obj,NULL,TO_CHAR);
            act("$n wakes up and rests in $p.",ch,obj,NULL,TO_ROOM);
        }
	ch->position = POS_RESTING;
	break;

    case POS_RESTING:
	send_to_char( "You are already resting.\n\r", ch );
	break;

    case POS_STANDING:
	if (obj == NULL)
	{
	    send_to_char( "You rest.\n\r", ch );
	    act( "$n sits down and rests.", ch, NULL, NULL, TO_ROOM );
	}
        else if (IS_SET(obj->value[2],REST_AT))
        {
	    act("You sit down at $p and rest.",ch,obj,NULL,TO_CHAR);
	    act("$n sits down at $p and rests.",ch,obj,NULL,TO_ROOM);
        }
        else if (IS_SET(obj->value[2],REST_ON))
        {
	    act("You sit on $p and rest.",ch,obj,NULL,TO_CHAR);
	    act("$n sits on $p and rests.",ch,obj,NULL,TO_ROOM);
        }
        else
        {
	    act("You rest in $p.",ch,obj,NULL,TO_CHAR);
	    act("$n rests in $p.",ch,obj,NULL,TO_ROOM);
        }
	ch->position = POS_RESTING;
	break;

    case POS_SITTING:
	if (obj == NULL)
	{
	    send_to_char("You rest.\n\r",ch);
	    act("$n rests.",ch,NULL,NULL,TO_ROOM);
	}
        else if (IS_SET(obj->value[2],REST_AT))
        {
	    act("You rest at $p.",ch,obj,NULL,TO_CHAR);
	    act("$n rests at $p.",ch,obj,NULL,TO_ROOM);
        }
        else if (IS_SET(obj->value[2],REST_ON))
        {
	    act("You rest on $p.",ch,obj,NULL,TO_CHAR);
	    act("$n rests on $p.",ch,obj,NULL,TO_ROOM);
        }
        else
        {
	    act("You rest in $p.",ch,obj,NULL,TO_CHAR);
	    act("$n rests in $p.",ch,obj,NULL,TO_ROOM);
	}
	ch->position = POS_RESTING;
	break;
    }


    return;
}

void do_sit (CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *obj = NULL;

    if (ch->position == POS_FIGHTING)
    {
	send_to_char("Maybe you should finish this fight first?\n\r",ch);
	return;
    }

    /* okay, now that we know we can sit, find an object to sit on */
    if (argument[0] != '\0')
    {
	obj = get_obj_list(ch,argument,ch->in_room->contents);
	if (obj == NULL)
	{
	    send_to_char("You don't see that here.\n\r",ch);
	    return;
	}
    }
    else obj = ch->on;

    if (obj != NULL)                                                              
    {
	if (obj->item_type != ITEM_FURNITURE
	||  (!IS_SET(obj->value[2],SIT_ON)
	&&   !IS_SET(obj->value[2],SIT_IN)
	&&   !IS_SET(obj->value[2],SIT_AT)))
	{
	    send_to_char("You can't sit on that.\n\r",ch);
	    return;
	}

	if (obj != NULL && ch->on != obj && count_users(obj) >= obj->value[0])
	{
	    act("There's no more room on $p.",ch,obj,NULL,TO_CHAR);
	    return;
	}

	ch->on = obj;
    }
    switch (ch->position)
    {
	case POS_SLEEPING:
	    if (IS_AFFECTED(ch,AFF_SLEEP))
	    {
		send_to_char("You can't wake up!\n\r",ch);
		return;
	    }

            if (obj == NULL)
            {
            	send_to_char( "You wake and sit up.\n\r", ch );
            	act( "$n wakes and sits up.", ch, NULL, NULL, TO_ROOM );
            }
            else if (IS_SET(obj->value[2],SIT_AT))
            {
            	act("You wake and sit at $p.",ch,obj,NULL,TO_CHAR);
            	act("$n wakes and sits at $p.",ch,obj,NULL,TO_ROOM);
            }
            else if (IS_SET(obj->value[2],SIT_ON))
            {
            	act("You wake and sit on $p.",ch,obj,NULL,TO_CHAR);
            	act("$n wakes and sits at $p.",ch,obj,NULL,TO_ROOM);
            }
            else
            {
            	act("You wake and sit in $p.",ch,obj,NULL,TO_CHAR);
            	act("$n wakes and sits in $p.",ch,obj,NULL,TO_ROOM);
            }

	    ch->position = POS_SITTING;
	    break;
	case POS_RESTING:
	    if (obj == NULL)
		send_to_char("You stop resting.\n\r",ch);
	    else if (IS_SET(obj->value[2],SIT_AT))
	    {
		act("You sit at $p.",ch,obj,NULL,TO_CHAR);
		act("$n sits at $p.",ch,obj,NULL,TO_ROOM);
	    }

	    else if (IS_SET(obj->value[2],SIT_ON))
	    {
		act("You sit on $p.",ch,obj,NULL,TO_CHAR);
		act("$n sits on $p.",ch,obj,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:
	    if (obj == NULL)
    	    {
		send_to_char("You sit down.\n\r",ch);
    	        act("$n sits down on the ground.",ch,NULL,NULL,TO_ROOM);
	    }
	    else if (IS_SET(obj->value[2],SIT_AT))
	    {
		act("You sit down at $p.",ch,obj,NULL,TO_CHAR);
		act("$n sits down at $p.",ch,obj,NULL,TO_ROOM);
	    }
	    else if (IS_SET(obj->value[2],SIT_ON))
	    {
		act("You sit on $p.",ch,obj,NULL,TO_CHAR);
		act("$n sits on $p.",ch,obj,NULL,TO_ROOM);
	    }
	    else
	    {
		act("You sit down in $p.",ch,obj,NULL,TO_CHAR);
		act("$n sits down in $p.",ch,obj,NULL,TO_ROOM);
	    }
    	    ch->position = POS_SITTING;
    	    break;
    }
    return;
}

void do_meditate( CHAR_DATA *ch, char *argument )
{
	if (IS_NPC(ch) || !IS_CLASS(ch, CLASS_MAGE))
	{
		send_to_char("You are unable to attain the correct state of mind.\n\r",ch);
		return;
	}
	
	switch ( ch->position )
	{
		case POS_SLEEPING:
			send_to_char( "You are already sleeping.\n\r", ch );
			break;
			
		case POS_RESTING:
			send_to_char( "You are already resting.\n\r", ch );
			break;
			
		case POS_MEDITATING:
			send_to_char( "You are already meditating.\n\r", ch );
			break;
			
		case POS_SITTING:
			send_to_char( "You cross your legs and start meditating.\n\r", ch );
			act( "$n crosses $s legs and starts meditating.", ch, NULL, NULL, TO_ROOM );
			ch->position = POS_MEDITATING;
			break;
			
		case POS_STANDING:
			send_to_char( "You sit down, cross your legs and start meditating.\n\r", ch );
			act( "$n sits down, crosses $s legs and starts meditating.", ch, NULL, NULL, TO_ROOM );
			ch->position = POS_MEDITATING;
			break;
			
		case POS_FIGHTING:
			send_to_char( "You are already fighting!\n\r", ch );
			break;
	}
	
	return;
}

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

    switch ( ch->position )
    {
    case POS_SLEEPING:
	send_to_char( "You are already sleeping.\n\r", ch );
	break;

    case POS_RESTING:
    case POS_SITTING:
    case POS_STANDING: 
	if (argument[0] == '\0' && ch->on == NULL)
	{
	    send_to_char( "You go to sleep.\n\r", ch );
	    act( "$n goes to sleep.", ch, NULL, NULL, TO_ROOM );
	    ch->position = POS_SLEEPING;
	}
	else  /* find an object and sleep on it */
	{
		if (argument[0] == '\0')
			obj = ch->on;
		else
			obj = get_obj_list( ch, argument,  ch->in_room->contents );

		if (obj == NULL)
		{
			send_to_char("You don't see that here.\n\r",ch);
			return;
		}
		if (obj->item_type != ITEM_FURNITURE
				||  (!IS_SET(obj->value[2],SLEEP_ON) 
					&&   !IS_SET(obj->value[2],SLEEP_IN)
					&&	 !IS_SET(obj->value[2],SLEEP_AT)))
		{
			send_to_char("You can't sleep on that!\n\r",ch);
			return;
		}

		if (ch->on != obj && count_users(obj) >= obj->value[0])
		{
			act("There is no room on $p for you.",
					ch,obj,NULL,TO_CHAR);
			return;
		}

		ch->on = obj;
		if (IS_SET(obj->value[2],SLEEP_AT))
		{
			act("You go to sleep at $p.",ch,obj,NULL,TO_CHAR);
			act("$n goes to sleep at $p.",ch,obj,NULL,TO_ROOM);
		}
		else if (IS_SET(obj->value[2],SLEEP_ON))
		{
			act("You go to sleep on $p.",ch,obj,NULL,TO_CHAR);
			act("$n goes to sleep on $p.",ch,obj,NULL,TO_ROOM);
		}
		else
		{
			act("You go to sleep in $p.",ch,obj,NULL,TO_CHAR);
			act("$n goes to sleep in $p.",ch,obj,NULL,TO_ROOM);
		}
		ch->position = POS_SLEEPING;

		if (!IS_NPC(ch) && IS_SET(ch->added, ADDED_CALM))
		{
			send_to_char("You no longer feel so apathetic.\n\r",ch);
			REMOVE_BIT(ch->added, ADDED_CALM);
		}
	}
	break;

    case POS_FIGHTING:
	send_to_char( "You are already fighting!\n\r", ch );
	break;
    }

    return;
}

void do_wake( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	
	one_argument( argument, arg );
	if ( arg[0] == '\0' )
	{ do_stand( ch, argument ); return; }
	
	if ( !IS_AWAKE(ch) )
	{ send_to_char( "You are asleep yourself!\n\r",       ch ); return; }
	
	if ( ( victim = get_char_room( ch, arg ) ) == NULL )
	{ send_to_char( "They aren't here.\n\r",              ch ); return; }
	
	if ( IS_AWAKE(victim) )
	{ act( "$N is already awake.", ch, NULL, victim, TO_CHAR ); return; }
	
	if ( IS_AFFECTED(victim, AFF_SLEEP) )
	{ act( "You can't wake $M!",   ch, NULL, victim, TO_CHAR );  return; }
	
	if (victim->position < POS_SLEEPING)
	{ act( "$E doesn't respond!",   ch, NULL, victim, TO_CHAR );  return; }
	
	act( "You wake $M.", ch, NULL, victim, TO_CHAR );
	act( "$n wakes you.", ch, NULL, victim, TO_VICT );
	victim->position = POS_STANDING;
	return;
}



void do_sneak( CHAR_DATA *ch, char *argument )
{
	AFFECT_DATA af;
	
	send_to_char( "You attempt to move silently.\n\r", ch );
	affect_strip( ch, gsn_sneak );
	
	if ( IS_NPC(ch) || number_percent( ) < ch->pcdata->learned[gsn_sneak] )
	{
		af.type      = gsn_sneak;
		af.duration  = ch->level;
		af.location  = APPLY_NONE;
		af.modifier  = 0;
		af.bitvector = AFF_SNEAK;
		affect_to_char( ch, &af );
	}
	
	return;
}



void do_hide( CHAR_DATA *ch, char *argument )
{
	send_to_char( "You attempt to hide.\n\r", ch );
	
	if ( IS_AFFECTED(ch, AFF_HIDE) )
		REMOVE_BIT(ch->affected_by, AFF_HIDE);
	
	if ( IS_NPC(ch) || number_percent( ) < ch->pcdata->learned[gsn_hide] )
		SET_BIT(ch->affected_by, AFF_HIDE);
	
	return;
}



/*
 * Contributed by Alander.
 */
void do_visible( CHAR_DATA *ch, char *argument )
{
	affect_strip ( ch, gsn_invis			);
	affect_strip ( ch, gsn_mass_invis			);
	affect_strip ( ch, gsn_sneak			);
	REMOVE_BIT   ( ch->affected_by, AFF_HIDE		);
	REMOVE_BIT   ( ch->affected_by, AFF_INVISIBLE	);
	REMOVE_BIT   ( ch->affected_by, AFF_SNEAK		);
	send_to_char( "Ok.\n\r", ch );
	return;
}



void do_unpolymorph( CHAR_DATA *ch, char *argument )
{
	if (!is_affected(ch, gsn_polymorph) )
	{
		send_to_char("But you are not polymorphed!\n\r",ch);
		return;
	}
	act("$n's body begins to distort.",ch,NULL,NULL,TO_ROOM);
	affect_strip ( ch, gsn_polymorph );
	act("$n resumes $s normal form.",ch,NULL,NULL,TO_ROOM);
	send_to_char( "You resume your normal form.\n\r", ch );
	return;
}



void do_recall( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	CHAR_DATA *victim;
	CHAR_DATA *mount;
	ROOM_INDEX_DATA *location;
	
	if (ch->fighting != NULL && !IS_NPC(ch->fighting))
	{
		send_to_char("Not in a PK fight, you don't!\n\r", ch);
		return;
	}
	
    if (((ch->hit * 100)/ch->max_hit) <= 5 && IS_AVATAR(ch))
    {
        send_to_char("Your health is too low to recall, use escape!\n\r",ch);
        return;
    }

	act( "$n's body flickers with green energy.", ch, NULL, NULL, TO_ROOM );
	act( "Your body flickers with green energy.", ch, NULL, NULL, TO_CHAR );
	
	if ( ( ch->home  == 1 ) || 
		( ch->home  == 2 ) )
	{
		send_to_char( "You don't feel at home there anymore.\n\r", ch );
		return;
	}
	
	if ( ( location = get_room_index( ch->home ) ) == NULL )
	{
		send_to_char( "You are completely lost.\n\r", ch );
		return;
	}
	
	if ( ch->in_room == location )
		return;
	
	if ( IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL)
		||   IS_AFFECTED(ch, AFF_CURSE) )
	{
		send_to_char( "You are unable to recall.\n\r", ch );
		return;
	}
	
	if ( ( victim = ch->fighting ) != NULL )
	{
		if ( number_bits( 1 ) == 0 )    
		{
			WAIT_STATE( ch, 4 );
			sprintf( buf, "You failed!\n\r" );
			send_to_char( buf, ch );
			return;
		}
		sprintf( buf, "You recall from combat!\n\r");
		send_to_char( buf, ch );
		stop_fighting( ch, TRUE );
	}
	
	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" );
	if ( ( mount = ch->mount ) == NULL ) return;
	char_from_room( mount );
	char_to_room( mount, ch->in_room );
	return;
}

void do_home( CHAR_DATA *ch, char *argument )
{
	char arg [MAX_INPUT_LENGTH];
	
	argument = one_argument( argument, arg );
	
	if ( IS_NPC(ch) ) return;
	
	if ( arg[0] == '\0' || str_cmp(arg,"here") )
	{
		send_to_char( "If you wish this to be your room, you must type 'home here'.\n\r", ch );
		return;
	}
	
	if ( ch->in_room->vnum == ch->home )
	{
		send_to_char( "But this is already your home!\n\r", ch );
		return;
	}
	
	if ( IS_SET(ch->in_room->room_flags, ROOM_NO_RECALL) ||
		is_tempsafe(ch) ||
		ch->in_room->vnum == 1 || ch->in_room->vnum == 2)
	{
		send_to_char( "You are unable to make this room your home.\n\r", ch );
		return;
	}
	
	ch->home = ch->in_room->vnum;
	send_to_char( "This room is now your home.\n\r", ch );
	
	return;
}


void do_escape( CHAR_DATA *ch, char *argument )
{
	GString *buf;
	GString *AreaName;
	int x;
	bool found = FALSE;
	
	if (IS_NPC(ch) || !IS_HERO(ch))
		return;

	if (ch->pcdata->obeah > 0)
	{
		send_to_char("No you must wait a while till you can use this command again.\n\r",ch);
		return;
	}
	
	if ( ch->position == POS_STUNNED )
	{
		send_to_char("Your too stunned to do anything!.\n\r",ch);
		return;
	}
	if ( ch->position >= POS_SLEEPING )
	{
		send_to_char( "You can only do this if you are dying.\n\r", ch );
		return;
	}
	
	teleport_char(ch);
	ch->move = 0;
	ch->mana = 0;
	update_pos(ch);
	clear_stats(ch);
	send_to_char("You feel dizzy after escaping..\n\r",ch);
	WAIT_STATE(ch,36);

	buf = g_string_new(ch->in_room->area->name);
	AreaName = g_string_new(""); 

	for (x = 0; x < buf->len; x++)
	{
		if (buf->str[x] == '/')
		{
			found = TRUE;
			continue;
		}
		if (found == TRUE)
			AreaName = g_string_append_c(AreaName,buf->str[x]);
	}
	
	g_string_sprintf(buf,"%s has escaped defenseless from a fight to %s.",ch->name->str,AreaName->str);
	do_info(ch,buf->str);
	g_string_free(AreaName,TRUE);
	g_string_free(buf,TRUE);
	ch->pcdata->obeah += 5;
	return;
}


void do_train( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_STRING_LENGTH];
	char arg2[MAX_STRING_LENGTH];
	char buf[MAX_STRING_LENGTH];
	sh_int *pAbility = NULL;
	int *pintAbility = NULL;
	int *pLongAbility = NULL;
	char *pOutput = NULL;
	double cost;
	int immcost, willexp;
	int primal;
	int silver;
	int max_stat = 18;
	bool last = TRUE;
	bool is_ok = FALSE;
	bool IS_ARETE = FALSE;

	argument = one_argument( argument, arg1 );
	argument = one_argument( argument, arg2 );

	if ( IS_NPC(ch) )
		return;

	if (IS_CLASS(ch,CLASS_WRAITH)){
		send_to_char("You cannot train anymore, use the "" command.\n\r",ch);
		return;
	}
	if ( arg1[0] == '\0' )
	{
		sprintf( buf, "You have %d experience points.\n\r", ch->exp );
		send_to_char( buf, ch );
		str_cpy(arg1,"foo");
	}

	if (!str_cmp(arg1,"str")   ) is_ok = TRUE;
	else if (!str_cmp(arg1,"int")   ) is_ok = TRUE;
	else if (!str_cmp(arg1,"wis")   ) is_ok = TRUE;
	else if (!str_cmp(arg1,"dex")   ) is_ok = TRUE;
	else if (!str_cmp(arg1,"con")   ) is_ok = TRUE;
	else if (!str_cmp(arg1,"hp")    ) is_ok = TRUE;
	else if (!str_cmp(arg1,"mana")  ) is_ok = TRUE;
	else if (!str_cmp(arg1,"move")  ) is_ok = TRUE;
	else if (!str_cmp(arg1,"primal")) is_ok = TRUE;
	else if (!str_cmp(arg1,"rpstatus")) is_ok = TRUE;
	else if (!str_cmp(arg1,"honor") && IS_CLASS(ch,CLASS_WEREWOLF)) is_ok = TRUE;
	else if (!str_cmp(arg1,"glory") && IS_CLASS(ch,CLASS_WEREWOLF)) is_ok = TRUE;
	else if (!str_cmp(arg1,"wisdom") && IS_CLASS(ch,CLASS_WEREWOLF)) is_ok = TRUE;
	//else if (!str_cmp(arg1,"renown")) is_ok = TRUE;
	else if (!str_cmp(arg1,"arete") && IS_CLASS(ch,CLASS_MAGE))  is_ok = TRUE;
	else if (!str_cmp(arg1,"silver") && IS_CLASS(ch,CLASS_WEREWOLF))
		is_ok = TRUE;
	if ( arg2[0] != '\0' && is_ok )
	{
		int amount = 0;

		if (!is_number(arg2))
		{
			send_to_char("Please enter a numeric value.\n\r",ch);
			return;
		}
		amount = atoi( arg2 );
		if (amount < 1 || amount > 100)
		{
			send_to_char("Please enter a value between 1 and 100.\n\r",ch);
			return;
		}
		if (amount > 1)
		{
			sprintf(buf,"%s %d",arg1,amount-1);
			do_train(ch,buf);
			last = FALSE;
		}
	}

	cost = 200;
	immcost = count_imms(ch);
	primal = (1+ch->practice)*500;

	//Willpower Cost.. Subject To change.. per Dominion's Descression

	if (IS_MERIT(ch,MERIT_WILLFULL))
	{
		willexp = (1+ch->pcdata->willpower)*3000*ch->race;
	}
	else if (IS_FLAW(ch,FLAW_WEAKWILLED))
	{
		willexp = (1+ch->pcdata->willpower)*7000*ch->race;
	}
	else
	{
		willexp = (1+ch->pcdata->willpower)*5000*ch->race;
	}	
	silver = (1+ch->pcdata->powers[WPOWER_SILVER])*2500;
	/*arete  = 50 * ch->arete + 1*/
	if (IS_CLASS(ch, CLASS_HIGHLANDER)) max_stat = 25;

	if ( !str_cmp( arg1, "str" ) )
	{
		pAbility    = &ch->pcdata->perm_str;
		pOutput     = "strength";
	}

	else if (IS_CLASS(ch,CLASS_MAGE) && !str_cmp( arg1, "arete" ) && ch->arete < 6)
	{
		cost        = ((ch->arete + 1) * 50) + 50;
		pAbility    = &ch->arete;
		pOutput     = "arete";
		IS_ARETE    = TRUE;
	}

	else if (IS_CLASS(ch,CLASS_SWWF) && !str_cmp( arg1, "honor" ) && ch->pcdata->Trenown[TRENOWN_HONOR] < 20)
	{
		cost        = 20 * ch->pcdata->Trenown[TRENOWN_HONOR] + 50;
		pAbility    = &ch->pcdata->Trenown[TRENOWN_HONOR];
		pOutput     = "honor";
		IS_ARETE    = TRUE;
	}
	else if (IS_CLASS(ch,CLASS_SWWF) && !str_cmp( arg1, "wisdom" ) && ch->pcdata->Trenown[TRENOWN_WISDOM] < 20)
	{
		cost        = 20 * ch->pcdata->Trenown[TRENOWN_WISDOM] + 50;
		pAbility    = &ch->pcdata->Trenown[TRENOWN_WISDOM];
		pOutput     = "wisdom";
		IS_ARETE    = TRUE;
	}
	else if (IS_CLASS(ch,CLASS_SWWF) && !str_cmp( arg1, "glory" ) && ch->pcdata->Trenown[TRENOWN_GLORY] < 20)
	{
		cost        = 20 * ch->pcdata->Trenown[TRENOWN_GLORY] + 50;
		pAbility    = &ch->pcdata->Trenown[TRENOWN_GLORY];
		pOutput     = "glory";
		IS_ARETE    = TRUE;
	}

	else if ( !str_cmp( arg1, "int" ) )
	{
		pAbility    = &ch->pcdata->perm_int;
		pOutput     = "intelligence";
	}

	else if ( !str_cmp( arg1, "wis" ) )
	{
		pAbility    = &ch->pcdata->perm_wis;
		pOutput     = "wisdom";
	}

	else if ( !str_cmp( arg1, "dex" ) )
	{
		pAbility    = &ch->pcdata->perm_dex;
		pOutput     = "dexterity";
	}

	else if ( !str_cmp( arg1, "con" ) )
	{
		pAbility    = &ch->pcdata->perm_con;
		pOutput     = "constitution";
	}

	else if ( !str_cmp( arg1, "avatar") && (ch->level == 2 ))
	{
		if ((ch->max_hit < 4000) 
				|| (ch->max_move < 4000) 
				|| (ch->max_mana < 4000)
				|| (((get_age(ch) - 17) * 2 ) < 25 ) )
		{
			send_to_char( "You are not ready to train avatar.\n\r", ch );
			send_to_char( "You need AT LEAST 4k hps, mana, moves and 25 hrs...the more, the better.\n\r", ch );
			return;
		}
		if ( ch->pk_timer > 0 )
		{
			send_to_char("Let's settle down and take a break before you jump back into the PK frenzy.\n\r",ch);
			return;
		}
		if (!strcmp(ch->description->str,""))
		{
			send_to_char("You cannot train avatar until you have a roleplay description for your character.\n\r",ch );
			send_to_char("Type 'help description' for instructions.\n\r",ch);
			send_to_char("If you choose to disregard this step, you will be asked to fix it once.\n\r",ch);
			send_to_char("After that, you will be punished for improper roleplay.\n\r", ch);
			return;
		}	
		cost        = 100000;
		pAbility    = &ch->level;
		pOutput     = "level";
	}

	else if ( !str_cmp( arg1, "hp") && ch->max_hit < 120000)
	{
		if ( ch->max_hit < 1 )
		{
			send_to_char("You can not train hit points when you are that low.\n\r",ch);
			return;
		}

		cost        = (ch->max_hit - ch->pcdata->perm_con - (get_disc(ch,DISC_FORTITUDE) * 5));

		if (IS_MERIT(ch,MERIT_TOUGH))
			cost -= cost * .2 ;

		if (IS_FLAW(ch,FLAW_FRAGILE))
			cost += cost * .2;

		pLongAbility    = &ch->max_hit;
		pOutput     = "hp";
	}

	else if ( !str_cmp( arg1, "mana") && ch->max_mana < 120000)
	{
		if ( ch->max_mana < 1 )
		{ 
			send_to_char("You can not train mana when you are that low.\n\r",ch);
			return;
		}   
		cost        = (ch->max_mana - ch->pcdata->perm_wis);
		if (IS_MERIT(ch,MERIT_STUDIOUS))
			cost -= cost * .2 ;

		if (IS_FLAW(ch,FLAW_DUMB))
			cost += cost * .2;

		pLongAbility    = &ch->max_mana;
		pOutput     = "mana";
	}

	else if ( !str_cmp( arg1, "move") && ch->max_move < 120000)
	{
		if ( ch->max_move < 1 )
		{
			send_to_char("You can not train movement when you are that low.\n\r",ch);
			return;
		}  
		cost        = (ch->max_move - ch->pcdata->perm_con);
		pLongAbility    = &ch->max_move;
		pOutput     = "move";
	}

	else if ( !str_cmp( arg1, "primal") && ch->practice < 4000)
	{
		cost        = primal;
		pAbility    = &ch->practice;
		pOutput     = "primal";
	}
	/**
	 * - FIXME -
	 * Need to make this something that is more expensive.
	 */
	else if ( !str_cmp( arg1, "willpower") && ch->pcdata->willpower < ch->race)
	{

		cost        = willexp;
		pAbility    = &ch->pcdata->willpower;
		pOutput     = "willpower";
	}

	else if ( !str_cmp( arg1, "silver") && IS_CLASS(ch, CLASS_WEREWOLF) &&
			ch->pcdata->powers[WPOWER_SILVER] < 100)
	{
		sh_int quiet_pointer = ch->pcdata->powers[WPOWER_SILVER]; 
		/* 
		   different type of int
		 */
		cost        = silver;
		pAbility    = &quiet_pointer;
		pOutput     = "tolerance to silver";
		if ( cost > ch->exp )
		{
			if (last) send_to_char( "You don't have enough exp.\n\r", ch );
			return;
		}
		ch->pcdata->powers[WPOWER_SILVER] += 1; 
	}
	else
	{
		sprintf( buf, "You can train the following:\n\r" );
		send_to_char( buf, ch );

		send_to_char( "Stats:", ch );
		if ( ch->pcdata->perm_str < max_stat ) send_to_char( " Str", ch );
		if ( ch->pcdata->perm_int < max_stat ) send_to_char( " Int", ch );
		if ( ch->pcdata->perm_wis < max_stat ) send_to_char( " Wis", ch );
		if ( ch->pcdata->perm_dex < max_stat ) send_to_char( " Dex", ch );
		if ( ch->pcdata->perm_con < max_stat ) send_to_char( " Con", ch );
		if ( ( ch->pcdata->perm_str >= max_stat )
				&& ( ch->pcdata->perm_wis >= max_stat )
				&& ( ch->pcdata->perm_int >= max_stat )
				&& ( ch->pcdata->perm_dex >= max_stat )
				&& ( ch->pcdata->perm_con >= max_stat ) )
			send_to_char( " None left to train.\n\r", ch );
		else
			send_to_char( ".\n\r", ch );

		if ( ch->level == 2 )
		{
			sprintf( buf, "Become an avatar - 100000 exp.\n\r" );
			send_to_char( buf, ch );
		}
		if ( IS_CLASS(ch,CLASS_SWWF) && ch->pcdata->Trenown[TRENOWN_HONOR] <= 20 )
		{
			sprintf( buf, "Temp Honor             - %d primal per point.\n\r",(20 * ch->pcdata->Trenown[TRENOWN_HONOR] + 50));
			send_to_char( buf, ch );
		}
		if ( IS_CLASS(ch,CLASS_SWWF) && ch->pcdata->Trenown[TRENOWN_GLORY] <= 20 )
		{
			sprintf( buf, "Temp Glory             - %d primal per point.\n\r",(20 * ch->pcdata->Trenown[TRENOWN_GLORY] + 50));
			send_to_char( buf, ch );
		}
		if ( IS_CLASS(ch,CLASS_SWWF) && ch->pcdata->Trenown[TRENOWN_WISDOM] <= 20 )
		{
			sprintf( buf, "Temp Wisdom             - %d primal per point.\n\r",(20 * ch->pcdata->Trenown[TRENOWN_WISDOM] + 50));
			send_to_char( buf, ch );
		}
		if ( IS_CLASS(ch,CLASS_MAGE) && ch->arete <= MAX_SPHERE )
		{
			sprintf( buf, "Arete             - %d primal per point.\n\r",((ch->arete + 1) * 50) + 50);
			send_to_char( buf, ch );
		}
		if ( ch->max_hit       < 120000 )
		{
			cost        = (ch->max_hit - ch->pcdata->perm_con - (get_disc(ch,DISC_FORTITUDE)
						* 5));

			if (IS_MERIT(ch,MERIT_TOUGH))
				cost -= cost * .2 ;

			if (IS_FLAW(ch,FLAW_FRAGILE))
				cost += cost * .2;

			sprintf( buf, "Hp               - %d exp per point.\n\r",(int)cost);
			send_to_char( buf, ch );
		}
		if ( ch->max_mana      < 120000 )
		{
			cost        = (ch->max_mana - ch->pcdata->perm_wis);
			if (IS_MERIT(ch,MERIT_STUDIOUS))
				cost -= cost * .2 ;

			if (IS_FLAW(ch,FLAW_DUMB))
				cost += cost * .2;


			sprintf( buf, "Mana             - %d exp per point.\n\r",(int)cost);
			send_to_char( buf, ch );
		}
		if ( ch->max_move      < 120000 )
		{
			sprintf( buf, "Move             - %d exp per point.\n\r",(ch->max_move - ch->pcdata->perm_con) );
			send_to_char( buf, ch );
		}
		if ( ch->practice        < 4000 )
		{
			sprintf( buf, "Primal           - %d exp per point of primal energy.\n\r", primal );
			send_to_char( buf, ch );
		}
		if ( ch->pcdata->willpower        < ch->race)
		{
			sprintf( buf, "Willpower           - %d exp per point of Willpower.\n\r", willexp );
			send_to_char( buf, ch );
		}
		sprintf( buf, "Exp              	- 1 RPts per 500,000.\n\r");
		send_to_char (buf,ch);
		if ( ch->pcdata->powers[WPOWER_SILVER] < 100 && IS_CLASS(ch, CLASS_WEREWOLF))
		{
			sprintf( buf, "Silver tolerance - %d exp per point of tolerance.\n\r", silver );
			send_to_char( buf, ch );
		}

	}

	if (pOutput == NULL){
		return;
	}

	if (IS_CLASS(ch,CLASS_MAGE) && (!str_cmp( arg1, "arete")) && (*pAbility > MAX_SPHERE) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}

	if ( (!str_cmp( arg1, "rpstatus")) && (*pintAbility >= 26 ) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}

	if ( (!str_cmp( arg1, "str")) && (*pAbility >= max_stat) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "int")) && (*pAbility >= max_stat) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "wis")) && (*pAbility >= max_stat) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "dex")) && (*pAbility >= max_stat) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "con")) && (*pAbility >= max_stat) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "hp")) && ( *pLongAbility >= 120000) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "mana")) && ( *pLongAbility >= 120000) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "move")) && ( *pLongAbility >= 120000) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "primal")) && (*pAbility >= 4000) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "willpower")) && (*pAbility >= 20) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "silver")) && (*pAbility >= 100) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}

	if (!str_cmp(arg1,"willpower"))
	{
		if ( (int)cost > ch->exp )
		{
			if (last) send_to_char( "You don't have enough exp.\n\r", ch );
			return;
		}
		
		ch->exp		-= (int)cost;
		send_to_char("Your willpower increases!\n\r",ch);
		*pAbility		+= 1;

		send_to_char("You might wanna backup your character, type {Rpbackup{x.\n\r",ch);
		return;
	}
	if (!str_cmp(arg1,"honor") ){
		if ( ch->practice < 20 * ch->pcdata->Trenown[TRENOWN_HONOR] + 50 )
		{
			send_to_char( "You don't have enough Primal.\n\r", ch );
			return;
		}
		ch->practice  -= 20 * ch->pcdata->Trenown[TRENOWN_HONOR] + 50;
		ch->pcdata->Trenown[TRENOWN_HONOR]++;
		send_to_char("Your Honor increases.\n\r",ch);	
		send_to_char("You might wanna backup your character, type {Rpbackup{x.\n\r",ch);
		return;	
	}
	if (!str_cmp(arg1,"wisdom") ){
		if (ch->practice < 20 * ch->pcdata->Trenown[TRENOWN_WISDOM] + 50 )
		{
			send_to_char( "You don't have enough Primal.\n\r", ch );
			return;
		}
		ch->practice  -= 20 * ch->pcdata->Trenown[TRENOWN_WISDOM] + 50;
		ch->pcdata->Trenown[TRENOWN_WISDOM]++;
		send_to_char("Your Wisdom increases.\n\r",ch);	
		send_to_char("You might wanna backup your character, type {Rpbackup{x.\n\r",ch);
		return;	
	}
	if (!str_cmp(arg1,"glory") ){
		if ( ch->practice < 20 * ch->pcdata->Trenown[TRENOWN_GLORY] + 50 )
		{
			send_to_char( "You don't have enough Primal.\n\r", ch );
			return;
		}
		ch->practice  -= 20 * ch->pcdata->Trenown[TRENOWN_GLORY] + 50;
		ch->pcdata->Trenown[TRENOWN_GLORY]++;
		send_to_char("Your Glory increases.\n\r",ch);	
		send_to_char("You might wanna backup your character, type {Rpbackup{x.\n\r",ch);
		return;	
	}
	
    if (IS_ARETE)
	{
		if ( cost > ch->practice )
		{
			if (last) send_to_char( "You don't have enough primal.\n\r", ch );
			return;
		}

		ch->practice		-= (int)cost;
		ch->pcdata->spent[SPENT_P] = (int)((double)ch->pcdata->spent[SPENT_P] + cost);
	}
	else
	{
		if ( cost > ch->exp )
		{
			if (last) send_to_char( "You don't have enough exp.\n\r", ch );
			return;
		}

		ch->exp		-= (int)cost;
	}	
	if (!str_cmp( arg1, "hp") || !str_cmp( arg1, "mana") || !str_cmp( arg1, "move"))
	{
		*pLongAbility		+= 1;
	}
	else 
	{
		*pAbility		+= 1;
	}
	if ( !str_cmp( arg1, "avatar") )
	{
		act( "You become an avatar!", ch, NULL, NULL, TO_CHAR );
		sprintf( buf, "%s has become an avatar!",ch->name->str );
		SET_BIT(ch->immune, IMM_MAGE);
		SET_BIT(ch->immune, IMM_VAMPIRE);
		SET_BIT(ch->immune, IMM_WEREWOLF);
		do_info(ch,buf);
		if (ch->level < ch->trust) ch->level = ch->trust;
		if (!IS_NPC(ch) && IS_VAMPAFF(ch, VAM_MORTAL))
			do_mortalvamp(ch,"");
		send_to_char("You might wanna backup your character, type {Rpbackup{x.\n\r",ch);
	}
	else if (last)
	{
		act( "Your $T increases!", ch, NULL, pOutput, TO_CHAR );
		send_to_char("You might wanna backup your character, type {Rpbackup{x.\n\r",ch);
	}
	return;
}

void do_mount( CHAR_DATA *ch, char *argument )
{
	char buf  [MAX_STRING_LENGTH];
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	
	argument = one_argument( argument, arg );
	
	if ( arg[0] == '\0' )
	{
		send_to_char( "Mount what?\n\r", ch );
		return;
	}
	
	if (IS_AFFECTED(ch, AFF_POLYMORPH) && !IS_VAMPAFF(ch, VAM_DISGUISED))
	{
		send_to_char( "You cannot ride in this form.\n\r",ch );
		return;
	}
	
	if ( ( victim = get_char_room( ch, arg ) ) == NULL )
	{
		send_to_char( "They aren't here.\n\r",ch );
		return;
	}
	
	if ( ch == victim )
	{
		send_to_char( "You cannot ride on your own back!\n\r",ch );
		return;
	}
	
	if ( ch->mounted > 0 )
	{
		send_to_char( "You are already riding.\n\r",ch );
		return;
	}
	
	if ( !IS_NPC(victim) || victim->mounted > 0 || (IS_NPC(victim) && !IS_SET(victim->act, ACT_MOUNT) ) )
	{
		send_to_char( "You cannot mount them.\n\r",ch );
		return;
	}
	
	if ( victim->position < POS_STANDING )
	{
		if ( victim->position < POS_SLEEPING )
			act( "$N is too badly hurt for that.", ch, NULL, victim, TO_CHAR );
		else if ( victim->position == POS_SLEEPING )
			act( "First you better wake $m up.", ch, NULL, victim, TO_CHAR );
		else if ( victim->position == POS_RESTING )
			act( "First $e better stand up.", ch, NULL, victim, TO_CHAR );
		else if ( victim->position == POS_MEDITATING )
			act( "First $e better stand up.", ch, NULL, victim, TO_CHAR );
		else if ( victim->position == POS_SITTING )
			act( "First $e better stand up.", ch, NULL, victim, TO_CHAR );
		else if ( victim->position == POS_SLEEPING )
			act( "First you better wake $m up.", ch, NULL, victim, TO_CHAR );
		else if ( victim->position == POS_FIGHTING )
			act( "Not while $e's fighting.", ch, NULL, victim, TO_CHAR );
		return;
	}
	
	if (!IS_NPC(ch) && ch->stance[0] != -1) do_stance(ch,"");
	
	ch->mounted     = IS_RIDING;
	victim->mounted = IS_MOUNT;
	ch->mount = victim;
	victim->mount = ch;
    /* Send MSP String if triggered */
	if ( IS_SET(ch->deaf, CHANNEL_MSP ))
	{
		sprintf(buf,"\n\r!!SOUND(%s T=sound L=1 V=100 U=http://%s%s )\n\r",msp_general_table[5].msp_string, msp_general_table[5].msp_server, msp_general_table[5].msp_dirinfo);
		send_to_char(buf,ch);
	}
	act( "You clamber onto $N's back.", ch, NULL, victim, TO_CHAR );
	act( "$n clambers onto $N's back.", ch, NULL, victim, TO_ROOM );
	return;
}

void do_dismount( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	
	if ( ch->mounted == 0 )
	{
		send_to_char( "But you are not riding!\n\r",ch );
		return;
	}
	
	if ( (victim = ch->mount) == NULL )
	{
		send_to_char( "But you are not riding!\n\r",ch );
		return;
	}
	
	act( "You clamber off $N's back.", ch, NULL, victim, TO_CHAR );
	act( "$n clambers off $N's back.", ch, NULL, victim, TO_ROOM );
	
	ch->mounted     = IS_ON_FOOT;
	victim->mounted = IS_ON_FOOT;
	
	ch->mount = NULL;
	victim->mount = NULL;
	
	return;
}

void do_tie( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg [MAX_INPUT_LENGTH];
	char buf [MAX_INPUT_LENGTH];
	int victimclass;
	int chclass;
	
	argument = one_argument( argument, arg );
	if ( ( victim = get_char_room( ch, arg ) ) == NULL )
	{
		send_to_char( "They aren't here.\n\r", ch );
		return;
	}
	if (victim == ch)
	{
		send_to_char( "You cannot tie yourself up!\n\r", ch );
		return;
	}
	if (IS_EXTRA(victim,TIED_UP))
	{
		send_to_char( "But they are already tied up!\n\r", ch );
		return;
	}
	if (victim->position > POS_STUNNED || victim->hit > 0)
	{
		send_to_char( "You can only tie up a defenseless person.\n\r", ch );
		return;
	}
	if ((ch->race > 1) && (victim->race < 1 ))
	{
		send_to_char( "How about picking on someone your own size, Pansy!\n\r", ch);
		return;
	}

	
	if (ch->race <= 0 ) chclass = 0;
	else if (ch->race <= 4 ) chclass = 1;
	else if (ch->race <= 9 ) chclass = 2;
	else if (ch->race <= 14) chclass = 3;
	else if (ch->race <= 19) chclass = 4;
	else if (ch->race <= 24) chclass = 5;
	else chclass = 6;
	
	if (victim->race <= 0 ) victimclass = 0;
	else if (victim->race <= 4 ) victimclass = 1;
	else if (victim->race <= 9 ) victimclass = 2;
	else if (victim->race <= 14) victimclass = 3;
	else if (victim->race <= 19) victimclass = 4;
	else if (victim->race <= 24) victimclass = 5;
	else victimclass = 6;
	
	if (!IS_NPC(ch) && IS_SET(ch->pcdata->comm,COMM_AUTOPROTECT) && victimclass < chclass )
	{
			send_to_char("You have been protected from tieing a lower stat player\n\r",ch);
			return;
	}


	if ( victimclass < chclass )
	{
			/**
			 * Need to code back in KILLER FLAG...
			 */
			set_attack_flag(ch,victim);
			victim->last_attacked = NULL;

	}
	
	act("You quickly tie up $N.",ch,NULL,victim,TO_CHAR);
	act("$n quickly ties up $N.",ch,NULL,victim,TO_ROOM);
	send_to_char("You have been tied up!\n\r",victim);
	SET_BIT(victim->extra,TIED_UP);
	sprintf(buf,"%s has been tied up by %s.",victim->name->str,ch->name->str);
	do_info(ch,buf);
	return;
}

void do_untie( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg [MAX_INPUT_LENGTH];
	
	argument = one_argument( argument, arg );
	if ( ( victim = get_char_room( ch, arg ) ) == NULL )
	{
		send_to_char( "They aren't here.\n\r", ch );
		return;
	}
	if (!IS_EXTRA(victim,TIED_UP))
	{
		send_to_char( "But they are not tied up!\n\r", ch );
		return;
	}
	if (victim == ch)
	{
		send_to_char( "You cannot untie yourself!\n\r", ch );
		return;
	}
	act("You quickly untie $N.",ch,NULL,victim,TO_CHAR);
	act("$n quickly unties $N.",ch,NULL,victim,TO_NOTVICT);
	act("$n quickly unties you.",ch,NULL,victim,TO_VICT);
	REMOVE_BIT(victim->extra,TIED_UP);
	return;
}

void do_gag( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg [MAX_INPUT_LENGTH];
	
	argument = one_argument( argument, arg );
	if ( ( victim = get_char_room( ch, arg ) ) == NULL )
	{
		send_to_char( "They aren't here.\n\r", ch );
		return;
	}
	if (victim == ch && !IS_EXTRA(victim,GAGGED) && IS_EXTRA(victim,TIED_UP))
	{
		send_to_char( "You cannot gag yourself!\n\r", ch );
		return;
	}
	if (!IS_EXTRA(victim,TIED_UP) && !IS_EXTRA(victim,GAGGED))
	{
		send_to_char( "You can only gag someone who is tied up!\n\r", ch );
		return;
	}
	if (!IS_EXTRA(victim,GAGGED))
	{
		act("You place a gag over $N's mouth.",ch,NULL,victim,TO_CHAR);
		act("$n places a gag over $N's mouth.",ch,NULL,victim,TO_NOTVICT);
		act("$n places a gag over your mouth.",ch,NULL,victim,TO_VICT);
		SET_BIT(victim->extra,GAGGED);
		return;
	}
	if (ch == victim)
	{
		act("You remove the gag from your mouth.",ch,NULL,victim,TO_CHAR);
		act("$n removes the gag from $s mouth.",ch,NULL,victim,TO_ROOM);
		REMOVE_BIT(victim->extra,GAGGED);
		return;
	}
	act("You remove the gag from $N's mouth.",ch,NULL,victim,TO_CHAR);
	act("$n removes the gag from $N's mouth.",ch,NULL,victim,TO_NOTVICT);
	act("$n removes the gag from your mouth.",ch,NULL,victim,TO_VICT);
	REMOVE_BIT(victim->extra,GAGGED);
	return;
}

void do_blindfold( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg [MAX_INPUT_LENGTH];
	
	argument = one_argument( argument, arg );
	if ( ( victim = get_char_room( ch, arg ) ) == NULL )
	{
		send_to_char( "They aren't here.\n\r", ch );
		return;
	}
	if (victim == ch && !IS_EXTRA(victim,BLINDFOLDED) && IS_EXTRA(victim,TIED_UP))
	{
		send_to_char( "You cannot blindfold yourself!\n\r", ch );
		return;
	}
	if (!IS_EXTRA(victim,TIED_UP) && !IS_EXTRA(victim,BLINDFOLDED))
	{
		send_to_char( "You can only blindfold someone who is tied up!\n\r", ch );
		return;
	}
	if (!IS_EXTRA(victim,BLINDFOLDED))
	{
		act("You place a blindfold over $N's eyes.",ch,NULL,victim,TO_CHAR);
		act("$n places a blindfold over $N's eyes.",ch,NULL,victim,TO_NOTVICT);
		act("$n places a blindfold over your eyes.",ch,NULL,victim,TO_VICT);
		SET_BIT(victim->extra,BLINDFOLDED);
		return;
	}
	if (ch == victim)
	{
		act("You remove the blindfold from your eyes.",ch,NULL,victim,TO_CHAR);
		act("$n removes the blindfold from $s eyes.",ch,NULL,victim,TO_ROOM);
		REMOVE_BIT(victim->extra,BLINDFOLDED);
		return;
	}
	act("You remove the blindfold from $N's eyes.",ch,NULL,victim,TO_CHAR);
	act("$n removes the blindfold from $N's eyes.",ch,NULL,victim,TO_NOTVICT);
	act("$n removes the blindfold from your eyes.",ch,NULL,victim,TO_VICT);
	REMOVE_BIT(victim->extra,BLINDFOLDED);
	return;
}



void do_track( CHAR_DATA *ch, char *argument )
{
	bool found = FALSE;
	if (!IS_NPC(ch) && number_percent() > ch->pcdata->learned[gsn_track])
	{
		send_to_char("You cannot sense any trails from this room.\n\r",ch);
		return;
	}
	if (check_track(ch,0)) found = TRUE;
	if (check_track(ch,1)) found = TRUE;
	if (check_track(ch,2)) found = TRUE;
	if (check_track(ch,3)) found = TRUE;
	if (check_track(ch,4)) found = TRUE;
	if (found == FALSE)
	{
		send_to_char("You cannot sense any trails from this room.\n\r",ch);
		return;
	}
	act("$n carefully examines the ground for tracks.",ch,NULL,NULL,TO_ROOM);
	return;
}

void check_hunt( CHAR_DATA *ch )
{
	CHAR_DATA *victim;
	bool found = FALSE;
	int direction = 0;
	ROOM_INDEX_DATA *in_room;
	
	in_room = ch->in_room;
	if (!IS_NPC(ch) && number_percent() > ch->pcdata->learned[gsn_track])
	{
		send_to_char("You cannot sense any trails from this room.\n\r",ch);
		ch->hunting = g_string_assign(ch->hunting,"");
		return;
	}
	if (check_track(ch,0)) {found = TRUE;direction = ch->in_room->track_dir[0];}
	else if (check_track(ch,1)) {found = TRUE;direction = ch->in_room->track_dir[1];}
	else if (check_track(ch,2)) {found = TRUE;direction = ch->in_room->track_dir[2];}
	else if (check_track(ch,3)) {found = TRUE;direction = ch->in_room->track_dir[3];}
	else if (check_track(ch,4)) {found = TRUE;direction = ch->in_room->track_dir[4];}
	else if ( ( victim = get_char_room( ch, ch->hunting->str ) ) == NULL )
	{
		send_to_char("You cannot sense any trails from this room.\n\r",ch);
		ch->hunting = g_string_assign(ch->hunting,"");
		return;
	}
	if (ch->hunting->len < 2) return;
	if ( ( victim = get_char_room( ch, ch->hunting->str ) ) != NULL ) return;
	act("$n carefully examines the ground for tracks.",ch,NULL,NULL,TO_ROOM);
	move_char(ch,direction);
	if (in_room == ch->in_room || victim != NULL)
	{
		ch->hunting = g_string_assign(ch->hunting,"");
	}
	return;
}

void add_tracks( CHAR_DATA *ch, int direction )
{
	int loop;
	
	if (IS_NPC(ch)) return;
	if (IS_CLASS(ch, CLASS_WEREWOLF) && ch->pcdata->powers[WPOWER_LYNX] > 0)
		return;
	if (IS_SWWF(ch) && get_auspice(ch,AUSPICE_RAGABASH) > 1)
		return;
	if (IS_IMMORTAL(ch))
		return;
	
	if (IS_ITEMAFF(ch, ITEMA_STALKER)) return;
	for ( loop = 0; loop <= 4; loop++ )
	{
		if (ch->in_room->track[loop] != NULL && !str_cmp(ch->in_room->track[loop]->str,ch->name->str))
		{
			ch->in_room->track[loop] = g_string_assign(ch->in_room->track[loop],"");
		}
	}
	if (ch->in_room->track[0]->len < 2)
	{
		ch->in_room->track[0] = g_string_assign(ch->in_room->track[0],ch->name->str);
		ch->in_room->track_dir[0] = direction;
	}
	else if (ch->in_room->track[1]->len < 2)
	{
		ch->in_room->track[1] = g_string_assign(ch->in_room->track[1],ch->name->str);
		ch->in_room->track_dir[1] = direction;
	}
	else if (ch->in_room->track[2]->len < 2)
	{
		ch->in_room->track[2] = g_string_assign(ch->in_room->track[2],ch->name->str);
		ch->in_room->track_dir[2] = direction;
	}
	else if (ch->in_room->track[3]->len < 2)
	{
		ch->in_room->track[3] = g_string_assign(ch->in_room->track[3],ch->name->str);
		ch->in_room->track_dir[3] = direction;
	}
	else if (ch->in_room->track[4]->len < 2)
	{
		ch->in_room->track[4] = g_string_assign(ch->in_room->track[4],ch->name->str);
		ch->in_room->track_dir[4] = direction;
	}
	else
	{
		ch->in_room->track[0] = g_string_assign(ch->in_room->track[0],ch->name->str);
		ch->in_room->track_dir[0] = ch->in_room->track_dir[1];
		ch->in_room->track[1] = g_string_assign(ch->in_room->track[1],ch->name->str);
		ch->in_room->track_dir[1] = ch->in_room->track_dir[2];
		ch->in_room->track[2] = g_string_assign(ch->in_room->track[2],ch->name->str);
		ch->in_room->track_dir[2] = ch->in_room->track_dir[3];
		ch->in_room->track[3] = g_string_assign(ch->in_room->track[3],ch->name->str);
		ch->in_room->track_dir[3] = ch->in_room->track_dir[4];
		ch->in_room->track[4] = g_string_assign(ch->in_room->track[4],ch->name->str);
		ch->in_room->track_dir[4] = direction;
	}
	return;
}

bool check_track( CHAR_DATA *ch, int direction )
{
	CHAR_DATA *victim;
	char buf [MAX_INPUT_LENGTH];
	char vict [MAX_INPUT_LENGTH];
	int door;
	
	str_cpy(vict,ch->hunting->str);
	if (!str_cmp(ch->hunting->str,vict))
	{
		if ( ( victim = get_char_room( ch, vict ) ) != NULL )
		{
			act("You have found $N!",ch,NULL,victim,TO_CHAR);
			ch->hunting = g_string_assign(ch->hunting,"");
			return TRUE;
		}
	}
	if (ch->in_room->track[direction]->len < 2) return FALSE;
	if (!str_cmp(ch->in_room->track[direction]->str,ch->name->str)) return FALSE;
	if (ch->hunting->len > 1 && str_cmp(ch->in_room->track[direction]->str,ch->hunting->str)) return FALSE;
	door = ch->in_room->track_dir[direction];
	sprintf(buf,"You sense the trail of %s leading $X from here.",ch->in_room->track[direction]->str);
	act( buf, ch, NULL, dir_name[door], TO_CHAR );
	return TRUE;
}

void do_autostance( CHAR_DATA *ch, char *argument )
{
	char arg [MAX_INPUT_LENGTH];
	int selection;	
	one_argument( argument, arg );
	if (IS_NPC(ch))
		return;
	if (!str_cmp(arg,"none")    )
	{
		selection = STANCE_NONE;
		send_to_char("Your autostance has been removed.\n\r",ch);
		REMOVE_BIT(ch->extra, EXTRA_STANCE);
	}
	else if (!str_cmp(arg,"viper"))
	{
		selection = STANCE_VIPER;
		send_to_char("Viper stance set.\n\r",ch);
	}
	else if (!str_cmp(arg,"crane")   ) 
	{
		selection = STANCE_CRANE;
		send_to_char("Crane stance set.\n\r",ch);
	}
	else if (!str_cmp(arg,"crab")    ) 
	{
		selection = STANCE_CRAB;
		send_to_char("Crab stance set.\n\r",ch);
	}
	else if (!str_cmp(arg,"mongoose")) 
	{
		selection = STANCE_MONGOOSE;
		send_to_char("Mongoose stance set.\n\r",ch);
	}
	else if (!str_cmp(arg,"bull")    ) 
	{
		selection = STANCE_BULL;
		send_to_char("Bull stance set.\n\r",ch);
	}
	else
	{
		if (!str_cmp(arg,"mantis") && ch->stance[STANCE_CRANE] >= 200 &&
			ch->stance[STANCE_VIPER] >= 200)
		{
			selection = STANCE_MANTIS;
			send_to_char("Mantis stance set.\n\r",ch);
		}
		else if (!str_cmp(arg,"dragon") && ch->stance[STANCE_BULL] >= 200 &&
			ch->stance[STANCE_CRAB] >= 200)
		{
			selection = STANCE_DRAGON;
			send_to_char("Dragon stance set.\n\r",ch);
		}
		else if (!str_cmp(arg,"tiger") && ch->stance[STANCE_BULL] >= 200 &&
			ch->stance[STANCE_VIPER] >= 200)
		{
			selection = STANCE_TIGER;
			send_to_char("Tiger stance set.\n\r",ch);
		}
		else if (!str_cmp(arg,"monkey") && ch->stance[STANCE_CRANE] >= 200 &&
			ch->stance[STANCE_MONGOOSE] >= 200)
		{
			selection = STANCE_MONKEY;
			send_to_char("Monkey stance set.\n\r",ch);
		}
		else if (!str_cmp(arg,"swallow") && ch->stance[STANCE_CRAB] >= 200 &&
			ch->stance[STANCE_MONGOOSE] >= 200)
		{
			selection = STANCE_SWALLOW;
			send_to_char("Swallow  stance set.\n\r",ch);
		}
		else
		{
			send_to_char("Syntax: autostance <style>.\n\r\n\r",ch);
			send_to_char("Style being one of:\n\r",ch);
			send_to_char("  None, Viper, Crane, Crab, Mongoose, Bull.\n\r",ch);
			send_to_char("  Mantis, Dragon, Tiger, Monkey, Swallow.\n\r",ch);
			return;
		}
	}
	ch->stance[11] = selection;
	SET_BIT(ch->extra, EXTRA_STANCE);
	return;
}

/************************************************************************/
/* mlkesl@stthomas.edu	=====>	Ascii Automapper utility		*/
/* Let me know if you use this. Give a newbie some _credit_,		*/
/* at least I'm not asking how to add classes...			*/
/* Also, if you fix something could ya send me mail about, thanks	*/
/* PLEASE mail me if you use this or like it, that way I will keep it up*/
/************************************************************************/
/* MapArea -> 	when given a room, ch, x, and y,...			*/
/*	   	this function will fill in values of map as it should 	*/
/* ShowMap -> 	will simply spit out the contents of map array		*/
/*		Would look much nicer if you built your own areas	*/
/*		without all of the overlapping stock Rom has		*/
/* do_map  ->	core function, takes map size as argument		*/
/************************************************************************/
/* To install:: 							*/
/*	remove all occurances of "u1." (unless your exits are unioned)	*/
/*	add do_map prototypes to interp.c and merc.h (or interp.h)	*/
/*	customize the first switch with your own sectors (add road :)	*/
/*	remove the color codes or change to suit your own color coding	*/
/* Other stuff::							*/
/*	make a skill, call from do_move (only if ch is not in city etc) */
/*	allow players to actually make ITEM_MAP objects			*/
/* 	change your areas to make them more suited to map code! :)	*/
/* 	I WILL be making MANY enhancements as they come but a lot of	*/
/*	  people want the code, and want it now :p			*/
/*	Kermit's page also has this snippet, mail me for any q's though */
/************************************************************************/ 	
/* mlk update: map is now a 2 dimensional array of integers		*/
/*	uses SECT_MAX for null					*/
/*	uses SECT_MAX+1 for mazes or one ways to SECT_ENTER		*/
/*	use the SECTOR numbers to represent sector types :)		*/
/************************************************************************/ 	
#define MAX_MAP 160
#define MAX_MAP_DIR 4

int map[MAX_MAP][MAX_MAP];
int offsets[4][2] ={ {-1, 0},{ 0, 1},{ 1, 0},{ 0,-1} };

void MapArea 
(ROOM_INDEX_DATA *room, CHAR_DATA *ch, int x, int y, int min, int max)
{
	ROOM_INDEX_DATA *prospect_room;
	EXIT_DATA *pexit;
	int door;
	
/* marks the room as visited */
	map[x][y]=room->sector_type;
	
	for ( door = 0; door < MAX_MAP_DIR; door++ ) 
	{ /* cycles through for each exit */
		if (
			(pexit = room->exit[door]) != NULL
			&&   pexit->to_room != NULL 
			&&   !IS_SET(pexit->exit_info, EX_CLOSED)
			)
		{ /* if exit there */
			
			if ((x<min)||(y<min)||(x>max)||(y>max)) return;
			
			prospect_room = pexit->to_room;
			
			if ( prospect_room->exit[rev_dir[door]] &&
				prospect_room->exit[rev_dir[door]]->to_room!=room)
			{ /* if not two way */
				map[x][y]=SECT_MAX+1; /* one way into area OR maze */	
				return;
			} /* end two way */
			
			if( (prospect_room->sector_type==SECT_HILLS) 
				||(prospect_room->sector_type==SECT_CITY) 
				||(prospect_room->sector_type==SECT_INSIDE) 
				)
			{ /* players cant see past these */
				map[x+offsets[door][0]][y+offsets[door][1]]=prospect_room->sector_type;
			}
			
			if (map[x+offsets[door][0]][y+offsets[door][1]]==SECT_MAX) {
				MapArea (pexit->to_room,ch,
					x+offsets[door][0], y+offsets[door][1],min,max);
			}
			
		} /* end if exit there */
	}
	return;
}

/* mlk :: shows a map, specified by size */
void ShowMap( CHAR_DATA *ch, int min, int max)
{
	int x,y;
	
	for (x = min; x < max; ++x) 
	{ /* every row */
		for (y = min; y < max; ++y)
		{ /* every column */
			if ( (y==min) || (map[x][y-1]!=map[x][y]) )
				switch(map[x][y])
				{
					case SECT_MAX:		send_to_char(" ",ch);		break;
					case SECT_FOREST:	send_to_char("{g@",ch);		break;
					case SECT_FIELD:	send_to_char("{G\"",ch);	break;
					case SECT_HILLS:	send_to_char("{G^",ch);		break;
					case SECT_MOUNTAIN:	send_to_char("{y^",ch);		break;
					case SECT_WATER_SWIM:	send_to_char("{B:",ch);		break;
					case SECT_WATER_NOSWIM:	send_to_char("{b:",ch);		break;
					case SECT_AIR:		send_to_char("{C%",ch);		break;
					case SECT_DESERT:	send_to_char("{Y=",ch);		break;
					case SECT_INSIDE:	send_to_char("{W%",ch);		break;
					case SECT_CITY:		send_to_char("{W#",ch);		break;
					case (SECT_MAX+1):	send_to_char("{D?",ch);		break;
					default: 		send_to_char("{R*",ch);
			} /* end switch1 */
			else 
			switch(map[x][y])
			{
				case SECT_MAX:		send_to_char(" ",ch);		break;
				case SECT_FOREST:	send_to_char("@",ch);		break;
				case SECT_FIELD:	send_to_char("\"",ch);		break;
				case SECT_HILLS:	send_to_char("^",ch);		break;
				case SECT_MOUNTAIN:	send_to_char("^",ch);		break;
				case SECT_WATER_SWIM:	send_to_char(":",ch);		break;
				case SECT_WATER_NOSWIM:	send_to_char(":",ch);		break;
				case SECT_AIR:		send_to_char("%",ch);		break;
				case SECT_DESERT:	send_to_char("=",ch);		break;
				case SECT_INSIDE:	send_to_char("%",ch);		break;
				case SECT_CITY:		send_to_char("#",ch);		break;
				case (SECT_MAX+1):	send_to_char("?",ch);		break;
				default: 		send_to_char("*",ch);
			} /* end switch2 */
		} /* every column */
		
		send_to_char("\n\r",ch); 
	} /*every row*/   
	
	return;
}

/* will put a small map with current room desc and title */
void ShowRoom( CHAR_DATA *ch, int min, int max)
{
	int x,y;
	
	map[min][min]=SECT_MAX;map[max-1][max-1]=SECT_MAX; /* mlk :: rounds edges */
	map[min][max-1]=SECT_MAX;map[max-1][min]=SECT_MAX;
	
	for (x = min; x < max; ++x) 
	{ /* every row */
		for (y = min; y < max; ++y)
		{ /* every column */
			if ( (y==min) || (map[x][y-1]!=map[x][y]) )
				switch(map[x][y])
				{
					case SECT_MAX:		send_to_char(" ",ch);		break;
					case SECT_FOREST:	send_to_char("{g@",ch);		break;
					case SECT_FIELD:	send_to_char("{G\"",ch);	break;
					case SECT_HILLS:	send_to_char("{G^",ch);		break;
					case SECT_MOUNTAIN:	send_to_char("{y^",ch);		break;
					case SECT_WATER_SWIM:	send_to_char("{B:",ch);		break;
					case SECT_WATER_NOSWIM:	send_to_char("{b:",ch);		break;
					case SECT_AIR:		send_to_char("{C%",ch);		break;
					case SECT_DESERT:	send_to_char("{Y=",ch);		break;
					case SECT_INSIDE:	send_to_char("{W%",ch);		break;
					case SECT_CITY:		send_to_char("{W#",ch);		break;
					case (SECT_MAX+1):	send_to_char("{D?",ch);		break;
					default: 		send_to_char("{R*",ch);
			} /* end switch1 */
			else 
			switch(map[x][y])
			{
				case SECT_MAX:		send_to_char(" ",ch);		break;
				case SECT_FOREST:	send_to_char("@",ch);		break;
				case SECT_FIELD:	send_to_char("\"",ch);		break;
				case SECT_HILLS:	send_to_char("^",ch);		break;
				case SECT_MOUNTAIN:	send_to_char("^",ch);		break;
				case SECT_WATER_SWIM:	send_to_char(":",ch);		break;
				case SECT_WATER_NOSWIM:	send_to_char(":",ch);		break;
				case SECT_AIR:		send_to_char("%",ch);		break;
				case SECT_DESERT:	send_to_char("=",ch);		break;
				case SECT_INSIDE:	send_to_char("%",ch);		break;
				case SECT_CITY:		send_to_char("#",ch);		break;
				case (SECT_MAX+1):	send_to_char("?",ch);		break;
				default: 		send_to_char("*",ch);
			} /* end switch2 */
		} /* every column */
		send_to_char("\n\r",ch);
	} /*else*/
	
	send_to_char("\n\r",ch); 
	return;
}  


void do_map( CHAR_DATA *ch, char *argument )
{
	int size,center,x,y,min,max;
	char arg1[10];
	
	one_argument( argument, arg1 );
	size = atoi (arg1);
	
	size=URANGE(6,size,MAX_MAP);
	center=MAX_MAP/2;
	
	min = MAX_MAP/2-size/2;
	max = MAX_MAP/2+size/2;
	
	for (x = 0; x < MAX_MAP; ++x)
		for (y = 0; y < MAX_MAP; ++y)
			map[x][y]=SECT_MAX;
		
/* starts the mapping with the center room */
	MapArea(ch->in_room, ch, center, center, min-1, max-1); 
	
/* marks the center, where ch is */
	map[center][center]=SECT_MAX+2; /* can be any number above SECT_MAX+1 	*/
				/* switch default will print out the *	*/
	
	if (   (!IS_IMMORTAL(ch))||(IS_NPC(ch))   )
	{
		if ( room_is_dark( ch->in_room) ) 
		{
			send_to_char( "{bThe wilderness is pitch black at night... {x\n\r", ch );
			return;
		}
		else   
		{
			ShowRoom(ch,MAX_MAP/2-3,MAX_MAP/2+3);
			return;
		}
	}
/* mortals not in city, enter or inside will always get a ShowRoom */
	if (IS_IMMORTAL(ch)) {
		if (arg1[0]=='\0') 
			ShowRoom (ch, min, max); 
		else 
			ShowMap (ch, min, max); 
		return;
	}
	
	send_to_char("{CHuh?{x\n\r",ch);
	return;
}

void do_smallmap( CHAR_DATA *ch, char *argument )
{
	int size,center,x,y,min,max;
	char arg1[10];
	
	one_argument( argument, arg1 );
	size = atoi (arg1);
	
	size=URANGE(6,size,MAX_MAP);
	center=MAX_MAP/2;
	
	min = MAX_MAP/2-size/2;
	max = MAX_MAP/2+size/2;
	
	for (x = 0; x < MAX_MAP; ++x)
		for (y = 0; y < MAX_MAP; ++y)
			map[x][y]=SECT_MAX;
		
/* starts the mapping with the center room */
	MapArea(ch->in_room, ch, center, center, min-1, max-1); 
	
/* marks the center, where ch is */
	map[center][center]=SECT_MAX+2; /* can be any number above SECT_MAX+1 	*/
				/* switch default will print out the *	*/
	
	if (IS_IMMORTAL(ch)) {
		ShowMap (ch, min, max); 
		return;
	}
	
	send_to_char("{CHuh?{x\n\r",ch);
	return;
}

/* mlk :: pass it (SECTOR_XXX,"") and get back the sector ascii 
 	  in a roleplaying format of course, not mountain_snow etc */
/* mlk ::
	when given (int array[5]) with vnum in [0], it will return
1	north sector_type, 
2	east sector_type, 
3	south sector_type,
4	east_sector_type &
5	number of exits leading to rooms of the same sector
 */
int *get_exit_sectors(int *exit_sectors)
{
	ROOM_INDEX_DATA *room;
	EXIT_DATA *pexit;
	int door;
	
	room=get_room_index(exit_sectors[0]);
	exit_sectors[4]=0;
	
	for ( door = 0; door < MAX_MAP_DIR; door++ ) 
	{ /* cycles through for each exit */
		if (
			(pexit = room->exit[door]) != NULL
			&&   pexit->to_room != NULL
			)
		{   
			exit_sectors[door]=pexit->to_room->sector_type;	
			if ((pexit->to_room->sector_type)==(room->sector_type))
				exit_sectors[4]+=1;
		} 
		else
			exit_sectors[door]=-1;	
	}	   
	
	return(exit_sectors);
}

void do_wash (CHAR_DATA *ch, char *argument)
{
	if (IS_NPC(ch))
		return;

	if (ch->in_room != NULL)
	{
		switch (ch->in_room->sector_type)
		{
			case SECT_WATER_SWIM:
				break;
			case SECT_WATER_NOSWIM:
				break;
			default:
				send_to_char("You need to find larger amounts of water to wash off all your filth.\n\r",ch);
				return;
			
		}
	}
	
	send_to_char("You cup your hands and fill them with water.\n\r",ch);
	send_to_char("As you splash yourself and rub off the stains of blood,\n\r",ch);
	send_to_char("you are no longer covered in the evidence of your bloody crimes.\n\r",ch);
	act("$n starts to wash off all their filth and blood.",ch,NULL,NULL,TO_ROOM);
	ch->blood_count = 0;


}





void do_trait(CHAR_DATA *ch, char *argument)
{
	int		cloop,cloop2;
	char	arg1[MAX_STRING_LENGTH];
	char	arg2[MAX_STRING_LENGTH];
	char	arg3[MAX_STRING_LENGTH];
	char 	buf[MAX_STRING_LENGTH]; 

	argument = one_argument(argument,arg1);
	argument = one_argument(argument,arg2);
	argument = one_argument(argument,arg3);
	
	if (IS_NPC(ch))
		return;

	if (arg1[0] == '\0')
	{
		send_to_char("Syntax:\n\r",ch); 
		send_to_char("  trait merit show      - Will list the merits you don't have.\n\r",ch);
		send_to_char("  trait merit stat      - Will list the merits you have.\n\r",ch);
		send_to_char("  trait merit (merit)   - Will buy the merit.\n\r",ch);
		send_to_char("  trait flaw  show      - Will list the flaws you don't have.\n\r",ch);
		send_to_char("  trait flaw  stat      - Will list the flaws you can take.\n\r",ch );
		send_to_char("  trait flaw  (flaw)    - Will take the flaw and give you character points.\n\r",ch);
		send_to_char("  trait flaw  bb (flaw) - Will buy back the flaw you have taken at double cost.\n\r",ch); 
		sprintf(buf,"\n\rYou have {B%d{x Character Points to Spend.\n\r",ch->pcdata->charpoints);
		send_to_char(buf,ch);
		return;
	}

	//Process Mertis First!
	if (!str_cmp(arg1,"merit"))
	{
		if (arg2[0] == '\0')
		{
		send_to_char("Syntax:\n\r",ch); 
		send_to_char("  trait merit show      - Will list the merits you don't have.\n\r",ch);
		send_to_char("  trait merit stat      - Will list the merits you have.\n\r",ch);
		send_to_char("  trait merit (merit)   - Will buy the merit.\n\r",ch);
		send_to_char("  trait flaw  show      - Will list the flaws you don't have.\n\r",ch);
		send_to_char("  trait flaw  stat      - Will list the flaws you can take.\n\r",ch );
		send_to_char("  trait flaw  (flaw)    - Will take the flaw and give you character points.\n\r",ch);
		send_to_char("  trait flaw  bb (flaw) - Will buy back the flaw you have taken at double cost.\n\r",ch); 
		sprintf(buf,"\n\rYou have {B%d{x Character Points to Spend.\n\r",ch->pcdata->charpoints);
		send_to_char(buf,ch);
		return;
		}

		if (!str_cmp(arg2,"show"))
		{
			cloop2 = 1;
			for (cloop = 0; trait_table[cloop].name != NULL; cloop++)
			{
				if(!IS_SET(ch->pcdata->trait_merit[REG_MERIT], trait_table[cloop].trait_flag) 
					&& trait_table[cloop].show_player == TRUE
					&& trait_table[cloop].trait_set == MERIT )
				{
					sprintf(buf,"{W%10s{x Cost: {B%2d{x",trait_table[cloop].name, trait_table[cloop].cp_cost);
					if ((cloop2 % 3) == 1)
						strcat(buf,"\n\r");
					else 
						strcat(buf,"    ");				
					send_to_char(buf,ch);
					cloop2++;				
				}
		   	}
			for (cloop = 0; trait_table[cloop].name != NULL; cloop++)
                        {
                                if(!IS_SET(ch->pcdata->trait_merit[IMM_MERIT], trait_table[cloop].trait_flag)
                                        && trait_table[cloop].show_player == TRUE
                                        && trait_table[cloop].trait_set == IM_MERIT)
                                {
                                        sprintf(buf,"{W%10s{x Cost: {B%2d{x",trait_table[cloop].name, trait_table[cloop]
.cp_cost);
                                        if ((cloop2 % 3) == 1)
                                                strcat(buf,"\n\r");
                                        else
                                                strcat(buf,"    ");
                                        send_to_char(buf,ch);
                                        cloop2++;
                                }
                        }
                        
			send_to_char("\n\r",ch);
			sprintf(buf,"\n\rYou have {B%d{x Character Points to Spend.\n\r",ch->pcdata->charpoints);
			send_to_char(buf,ch);
			return;
		}
		if (!str_cmp(arg2,"stat"))
		{
			cloop2 = 1;
			for (cloop = 0; trait_table[cloop].name != NULL; cloop++)
			{
				if(IS_SET(ch->pcdata->trait_merit[REG_MERIT], trait_table[cloop].trait_flag) 
					&& trait_table[cloop].show_player == TRUE
					&& trait_table[cloop].trait_set == MERIT)
				{
					sprintf(buf,"{W%10s{x Cost: {B%2d{x",trait_table[cloop].name, trait_table[cloop].cp_cost);
					if ((cloop2 % 3) == 1)
						strcat(buf,"\n\r");
					else
						strcat(buf,"     ");
					send_to_char(buf,ch);
					cloop2++;				
				}
			        if(IS_SET(ch->pcdata->trait_merit[IMM_MERIT], trait_table[cloop].trait_flag)
                                        && trait_table[cloop].show_player == TRUE
                                        && trait_table[cloop].trait_set == IM_MERIT )
                                {
                                        sprintf(buf,"{W%10s{x Cost: {B%2d{x",trait_table[cloop].name, trait_table[cloop]
.cp_cost);
                                        if ((cloop2 % 3) == 1)
                                                strcat(buf,"\n\r");
                                        else
                                                strcat(buf,"     ");
                                        send_to_char(buf,ch);
                                        cloop2++;
                                }
                        
			}
			send_to_char("\n\r",ch);
			sprintf(buf,"\n\rYou have {B%d{x Character Points to Spend.\n\r",ch->pcdata->charpoints);
			send_to_char(buf,ch);
			return;
		}
		for (cloop = 0; trait_table[cloop].name != NULL; cloop++)
		{
			if(trait_table[cloop].show_player == TRUE
				&& (trait_table[cloop].trait_set == MERIT || trait_table[cloop].trait_set == IM_MERIT)
				&& !str_cmp(arg2,trait_table[cloop].name))
			{
				if (trait_table[cloop].trait_set == MERIT && IS_SET(ch->pcdata->trait_merit[REG_MERIT], trait_table[cloop].trait_flag) )
				{
					send_to_char("You have that merit already.\n\r",ch);
					return;
				}
				if (trait_table[cloop].trait_set == MERIT && IS_SET(ch->pcdata->trait_flaw[REG_MERIT], trait_table[cloop].trait_flag) )
				{
					send_to_char("You have that as a flaw.\n\r",ch);
					return;
				}
				if (trait_table[cloop].trait_set == IM_MERIT && IS_SET(ch->pcdata->trait_merit[IMM_MERIT], trait_table[cloop].trait_flag) )
                                {
                                        send_to_char("You have that merit already.\n\r",ch);
                                        return;
                                }
                                if (trait_table[cloop].trait_set == IM_MERIT && IS_SET(ch->pcdata->trait_flaw[IMM_MERIT], trait_table[cloop].trait_flag) )
                                {
                                        send_to_char("You have that as a flaw.\n\r",ch);
                                        return;
                                }
                                
				if (ch->pcdata->charpoints < trait_table[cloop].cp_cost)
				{
					send_to_char("You cannot afford this merit.\n\r",ch);
					return;
				}
				ch->pcdata->charpoints -= trait_table[cloop].cp_cost;
				ch->pcdata->spent[SPENT_CP] += trait_table[cloop].cp_cost;
				
				if (trait_table[cloop].trait_set == IM_MERIT)
					SET_BIT(ch->pcdata->trait_merit[IMM_MERIT],trait_table[cloop].trait_flag); 
				else
					SET_BIT(ch->pcdata->trait_merit[REG_MERIT],trait_table[cloop].trait_flag); 	
				
				sprintf(buf,"You now have the %s merit.\n\r",trait_table[cloop].name);
				send_to_char(buf,ch);
				return;  
			}

		}
		send_to_char("Merit not found!\n\r",ch);
		return;
				
	}

	//Process Flaws Second!
	if (!str_cmp(arg1,"flaw"))
	{
	   	if (arg2[0] == '\0')
		{
		send_to_char("Syntax:\n\r",ch); 
		send_to_char("  trait merit show      - Will list the merits you don't have.\n\r",ch);
		send_to_char("  trait merit stat      - Will list the merits you have.\n\r",ch);
		send_to_char("  trait merit (merit)   - Will buy the merit.\n\r",ch);
		send_to_char("  trait flaw  show      - Will list the flaws you don't have.\n\r",ch);
		send_to_char("  trait flaw  stat      - Will list the flaws you can take.\n\r",ch );
		send_to_char("  trait flaw  (flaw)    - Will take the flaw and give you character points.\n\r",ch);
		send_to_char("  trait flaw  bb (flaw) - Will buy back the flaw you have taken at double cost.\n\r",ch); 
		sprintf(buf,"\n\rYou have {B%d{x Character Points to Spend.\n\r",ch->pcdata->charpoints);
		send_to_char(buf,ch);
		return;
		}

		if (!str_cmp(arg2,"show"))
	   	{
			cloop2 = 1;
	   		for (cloop = 0; trait_table[cloop].name != NULL; cloop++)
	   		{
	   			if(!IS_SET(ch->pcdata->trait_flaw[REG_FLAW], trait_table[cloop].trait_flag) 
					&& trait_table[cloop].show_player == TRUE
					&& trait_table[cloop].trait_set == FLAW ) 
				{
					sprintf(buf,"{W%10s{x Adds: {B%2d{x",trait_table[cloop].name, trait_table[cloop].cp_cost);
					if ((cloop2 % 3) == 1)
						strcat(buf,"\n\r");
					else
						strcat(buf,"     ");				
					send_to_char(buf,ch);
					cloop2++;				
				}
			        if(!IS_SET(ch->pcdata->trait_flaw[IMM_FLAW], trait_table[cloop].trait_flag)
                                        && trait_table[cloop].show_player == TRUE
                                        && trait_table[cloop].trait_set == IM_FLAW)
                                {
                                        sprintf(buf,"{W%10s{x Adds: {B%2d{x",trait_table[cloop].name, trait_table[cloop]
.cp_cost);
                                        if ((cloop2 % 3) == 1)
                                                strcat(buf,"\n\r");
                                        else
                                                strcat(buf,"     ");
                                        send_to_char(buf,ch);
                                        cloop2++;
                                }
                        
			}
			send_to_char("\n\r",ch);
			sprintf(buf,"\n\rYou have {B%d{x Character Points.\n\r",ch->pcdata->charpoints);
			send_to_char(buf,ch);
			return;
	   	}
	   	if (!str_cmp(arg2,"stat"))
	   	{
			cloop2 = 1;
	   		for (cloop = 0; trait_table[cloop].name != NULL; cloop++)
	   		{
	   			if(IS_SET(ch->pcdata->trait_flaw[REG_FLAW], trait_table[cloop].trait_flag) 
					&& trait_table[cloop].show_player == TRUE
					&& trait_table[cloop].trait_set == FLAW)
				{
					sprintf(buf,"{W%10s{x Adds: {B%2d{x",trait_table[cloop].name, trait_table[cloop].cp_cost);
					if ((cloop2 % 3) == 1)
						strcat(buf,"\n\r");
					else
						strcat(buf,"     ");				
					send_to_char(buf,ch);
					cloop2++;				
				}
			        if(IS_SET(ch->pcdata->trait_flaw[IMM_FLAW], trait_table[cloop].trait_flag)
                                        && trait_table[cloop].show_player == TRUE
                                        && trait_table[cloop].trait_set == IM_FLAW)
                                {
                                        sprintf(buf,"{W%10s{x Adds: {B%2d{x",trait_table[cloop].name, trait_table[cloop]
.cp_cost);
                                        if ((cloop2 % 3) == 1)
                                                strcat(buf,"\n\r");
                                        else
                                                strcat(buf,"     ");
                                        send_to_char(buf,ch);
                                        cloop2++;
                                }
                        
			}
			send_to_char("\n\r",ch);
			sprintf(buf,"\n\rYou have {B%d{x Character Points.\n\r",ch->pcdata->charpoints);
			send_to_char(buf,ch);
			return;
	   	}
		
		if (!str_cmp(arg2,"bb"))
		{
			if (arg3[0] == '\0')
			{
				send_to_char("Umm supply a flaw with this argument.\n\r",ch);
				return;
			}
			
			for (cloop = 0; trait_table[cloop].name != NULL; cloop++)
			{
				if(trait_table[cloop].show_player == TRUE
				&& (trait_table[cloop].trait_set == FLAW || trait_table[cloop].trait_set == IM_FLAW)
			 	&& !str_cmp(arg3,trait_table[cloop].name))
				{
				
					if (trait_table[cloop].trait_set == FLAW && !IS_SET(ch->pcdata->trait_flaw[REG_FLAW], trait_table[cloop].trait_flag) )
					{
						send_to_char("You don't have that flaw.\n\r",ch);
						return;
					}
				
					if (trait_table[cloop].trait_set == IM_FLAW && !IS_SET(ch->pcdata->trait_flaw[IMM_FLAW], trait_table[cloop].trait_flag) )
					{
						send_to_char("You don't have that flaw.\n\r",ch);
						return;
					}
				
                if (ch->pcdata->charpoints < trait_table[cloop].cp_cost * 2)
                {
					send_to_char("You don't have the requiered character points.\n\r",ch);
					return;
				}
                
                ch->pcdata->charpoints -= (trait_table[cloop].cp_cost * 2);
				
				if (trait_table[cloop].trait_set == IM_FLAW)
					REMOVE_BIT(ch->pcdata->trait_flaw[IMM_FLAW],trait_table[cloop].trait_flag); 
				else
					REMOVE_BIT(ch->pcdata->trait_flaw[REG_FLAW],trait_table[cloop].trait_flag); 	
				
				sprintf(buf,"You have bought back the %s flaw.\n\r",trait_table[cloop].name);
				send_to_char(buf,ch);
				return;
				}
			}
			send_to_char("Flaw not found.\n\r",ch);
			return;
		}
		
		for (cloop = 0; trait_table[cloop].name != NULL; cloop++)
		{
			if(trait_table[cloop].show_player == TRUE
				&& (trait_table[cloop].trait_set == FLAW || trait_table[cloop].trait_set == IM_FLAW)
			 	&& !str_cmp(arg2,trait_table[cloop].name))
			{
				if (trait_table[cloop].trait_set == FLAW && IS_SET(ch->pcdata->trait_flaw[REG_FLAW], trait_table[cloop].trait_flag) )
				{
					send_to_char("You have that flaw already.\n\r",ch);
					return;
				}
				if (trait_table[cloop].trait_set == FLAW && IS_SET(ch->pcdata->trait_merit[REG_FLAW], trait_table[cloop].trait_flag) )
				{
					send_to_char("You have that as a merit.\n\r",ch);
					return;
				}
				if (trait_table[cloop].trait_set == IM_FLAW && IS_SET(ch->pcdata->trait_flaw[IMM_FLAW], trait_table[cloop].trait_flag) )
                                {
                                        send_to_char("You have that flaw already.\n\r",ch);
                                        return;
                                }
                                if (trait_table[cloop].trait_set == IM_FLAW && IS_SET(ch->pcdata->trait_merit[IMM_FLAW], trait_table[cloop].trait_flag) )
                                {
                                        send_to_char("You have that as a merit.\n\r",ch);
                                        return;
                                }
                                
				if (ch->pcdata->charpoints > MAX_CPOINTS)
				{
					send_to_char("You cannot get anymore flaws.\n\r",ch);
					return;
				}
				ch->pcdata->charpoints += trait_table[cloop].cp_cost;
				if (trait_table[cloop].trait_set == IM_FLAW)
					SET_BIT(ch->pcdata->trait_flaw[IMM_FLAW],trait_table[cloop].trait_flag); 
				else
					SET_BIT(ch->pcdata->trait_flaw[REG_FLAW],trait_table[cloop].trait_flag); 	
				
				sprintf(buf,"You now have the %s flaw.\n\r",trait_table[cloop].name);
				send_to_char(buf,ch);
				return;
			}

		}
		send_to_char("Flaw not found!\n\r",ch);
		return;
		
	}		
}

void do_pettrain( CHAR_DATA *ch, char *argument )
{
	char arg0[MAX_STRING_LENGTH];
	char arg1[MAX_STRING_LENGTH];
	char arg2[MAX_STRING_LENGTH];
	char buf[MAX_STRING_LENGTH];
	sh_int *pAbility = NULL;
	int *pLongAbility = NULL;
	char *pOutput;
	CHAR_DATA *vch;
	int cost;
	int immcost;
	int primal;
	bool last = TRUE;
	bool is_ok = FALSE;
	
	argument = one_argument( argument, arg0 );
	argument = one_argument( argument, arg1 );
	argument = one_argument( argument, arg2 );
	
	if ( (vch = get_char_world(ch,arg0)) == NULL )
	{
		send_to_char("Get a petscore on who?\n\r", ch);
		return;
	}
	
	if ( IS_NPC(vch) && !IS_PET(vch))
		return;
	
	if ( !IS_NPC(vch))
		return;
		
	if ( vch->pet_master != ch )
		return;	

	if ( arg1[0] == '\0' )
	{
		sprintf( buf, "You have %d experience points.\n\r", vch->exp );
		send_to_char( buf, ch );
		str_cpy(arg1,"foo");
	}
	
	if (!str_cmp(arg1,"str")   ) is_ok = TRUE;
	else if (!str_cmp(arg1,"int")   ) is_ok = TRUE;
	else if (!str_cmp(arg1,"wis")   ) is_ok = TRUE;
	else if (!str_cmp(arg1,"dex")   ) is_ok = TRUE;
	else if (!str_cmp(arg1,"con")   ) is_ok = TRUE;
	else if (!str_cmp(arg1,"hp")    ) is_ok = TRUE;
	else if (!str_cmp(arg1,"mana")  ) is_ok = TRUE;
	else if (!str_cmp(arg1,"move")  ) is_ok = TRUE;
	else if (!str_cmp(arg1,"primal")) is_ok = TRUE;
	else if (!str_cmp(arg1,"rpstatus")) is_ok = TRUE;
		is_ok = TRUE;
	if ( arg2[0] != '\0' && is_ok )
	{
		int amount = 0;
		
		if (!is_number(arg2))
		{
			send_to_char("Please enter a numeric value.\n\r",ch);
			return;
		}
		amount = atoi( arg2 );
		if (amount < 1 || amount > 100)
		{
			send_to_char("Please enter a value between 1 and 100.\n\r",ch);
			return;
		}
		if (amount > 1)
		{
			sprintf(buf,"%s %d",arg1,amount-1);
			do_train(vch,buf);
			last = FALSE;
		}
	}
	
	cost = 200;
	immcost = count_imms(ch);
	primal = (1+vch->practice)*500;
	
	
	if ( !str_cmp( arg1, "hp") && vch->max_hit < 120000)
	{
                if ( vch->max_hit < 1 )
                {
                    send_to_char("You can not train hit points when you are that low.\n\r",ch);
                    return;
                }

		cost        = (vch->max_hit * 5);
		
		pLongAbility    = &vch->max_hit;
		pOutput     = "hp";
	}
	
	else if ( !str_cmp( arg1, "mana") && vch->max_mana < 120000)
	{
                if ( ch->max_mana < 1 )
                {
                    send_to_char("You can not train mana when you are that low.\n\r",ch);
                    return;
                }
		cost        = (vch->max_mana * 5);
		
		pLongAbility    = &vch->max_mana;
		pOutput     = "mana";
	}
	
	else if ( !str_cmp( arg1, "move") && vch->max_move < 120000)
	{
                if ( vch->max_move < 1 )
                {
                    send_to_char("You can not train movement when you are that low.\n\r",ch);
                    return;
                }
		cost        = (vch->max_move * 5);
		pLongAbility    = &vch->max_move;
		pOutput     = "move";
	}
	
	else if ( !str_cmp( arg1, "primal") && vch->practice < 4000)
	{
		cost        = primal;
		pAbility    = &vch->practice;
		pOutput     = "primal";
	}
	
	else
	{
		sprintf( buf, "You can train the following:\n\r" );
		send_to_char( buf, ch );
		
		if ( ch->max_hit       < 120000 )
		{
			cost        = (ch->max_hit - ch->pcdata->perm_con - (get_disc(ch,DISC_FORTITUDE)
* 5));
		sprintf( buf, "Hp               - %d exp per point.\n\r",cost);
			send_to_char( buf, ch );
		}
		if ( ch->max_mana      < 120000 )
		{
        		cost        = (ch->max_mana - ch->pcdata->perm_wis);

			sprintf( buf, "Mana             - %d exp per point.\n\r",cost);
			send_to_char( buf, ch );
		}
		if ( ch->max_move      < 120000 )
		{
			sprintf( buf, "Move             - %d exp per point.\n\r",(ch->max_move - ch->pcdata->perm_con) );
			send_to_char( buf, ch );
		}
		if ( ch->practice        < 4000 )
		{
			sprintf( buf, "Primal           - %d exp per point of primal energy.\n\r", primal );
			send_to_char( buf, ch );
		}
		return;
	}
	
	if ( (!str_cmp( arg1, "hp")) && ( *pLongAbility >= 120000) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "mana")) && ( *pLongAbility >= 120000) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "move")) && ( *pLongAbility >= 120000) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	if ( (!str_cmp( arg1, "primal")) && (*pAbility >= 4000) )
	{
		if (last) act( "Your $T is already at maximum.", ch, NULL, pOutput, TO_CHAR );
		return;
	}
	
	if ( cost > vch->exp )
	{
		if (last) send_to_char( "They don't have enough exp.\n\r", ch );
		return;
	}
	
	vch->exp		-= cost;
	
	if (!str_cmp( arg1, "hp") || !str_cmp( arg1, "mana") || !str_cmp( arg1, "move"))
	{
		*pLongAbility		+= 1;
	}
	else
	{
		*pAbility		+= 1;
	}
	
	if (last)
	{
		act( "Thier $T increases!", vch, NULL, pOutput, TO_CHAR );
		send_to_char("You might wanna backup your character, type {Rpbackup{x.\n\r",ch);
	}
	return;
}