bast/
bast/area/
bast/backup/
bast/clans/
bast/doc/MSP/
bast/doc/OLC11/
bast/doc/OLC11/doc/
bast/doc/OLC11/options/
bast/log/
bast/mobprogs/
bast/player/
/***************************************************************************
 *  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.                              *
 *                                                                         *
 *  Envy Diku Mud improvements copyright (C) 1994 by Michael Quan, David   *
 *  Love, Guilherme 'Willie' Arnold, and Mitchell Tse.                     *
 *                                                                         *
 *  EnvyMud 2.0 improvements copyright (C) 1995 by Michael Quan and        *
 *  Mitchell Tse.                                                          *
 *                                                                         *
 *  EnvyMud 2.2 improvements copyright (C) 1996, 1997 by Michael Quan.     *
 *                                                                         *
 *  In order to use any part of this Envy Diku Mud, you must comply with   *
 *  the original Diku license in 'license.doc', the Merc license in        *
 *  'license.txt', as well as the Envy license in 'license.nvy'.           *
 *  In particular, you may not remove either of these copyright notices.   *
 *                                                                         *
 *  Much time and thought has gone into this software and you are          *
 *  benefitting.  We hope that you share your changes too.  What goes      *
 *  around, comes around.                                                  *
 ***************************************************************************/

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


/* JPG Following list should match merc.h Equipment wear loc list
 *
 * However, any unused locations need to be left in as placeholders
 * - Veygoth
 */
char *	const	where_name	[] =
{
    "&+y<invalid location>  &n", // 0
    "&+y<worn on finger>    &n", // 1
    "&+y<worn on finger>    &n", // 2
    "&+y<worn around neck>  &n", // 3
    "&+y<worn around neck>  &n", // 4
    "&+y<worn on body>      &n", // 5
    "&+y<worn on head>      &n", // 6
    "&+y<worn on legs>      &n", // 7
    "&+y<worn on feet>      &n", // 8
    "&+y<worn on hands>     &n", // 9
    "&+y<worn on arms>      &n", // 10
    "&+y<worn as shield>    &n", // 11
    "&+y<worn about body>   &n", // 12
    "&+y<worn about waist>  &n", // 13
    "&+y<worn around wrist> &n", // 14
    "&+y<worn around wrist> &n", // 15
    "&+y<primary hand>      &n", // 16
    "&+y<held>              &n", // 17
    "&+y<secondary hand>    &n", // 18
    "&+y<worn on eyes>      &n", // 19
    "&+y<worn on face>      &n", // 20
    "&+y<worn in left ear>  &n", // 21
    "&+y<worn in right ear> &n", // 22
    "&+y<worn as badge>     &n", // 23
    "&+y<worn on back>      &n", // 24
    "&+y<attached to belt>  &n", // 25
    "&+y<attached to belt>  &n", // 26
    "&+y<attached to belt>  &n", // 27
    "&+y<worn as quiver>    &n"  // 28
};

const int topdown_eq [MAX_WEAR] =
{ 0, 23, 6, 19, 21, 22, 20, 3, 4, 5, 12, 13, 25, 10, 14, 15, 9,
  1, 2, 11, 16, 18, 17, 25, 26, 27, 7, 8 }; 


/*
 * Local functions.
 */
char *	format_obj_to_char	args( ( OBJ_DATA *obj, CHAR_DATA *ch,
				       bool fShort ) );
void	show_list_to_char	args( ( OBJ_DATA *list, CHAR_DATA *ch,
				       bool fShort, bool fShowNothing ) );
void	show_char_to_char_0	args( ( CHAR_DATA *victim, CHAR_DATA *ch ) );
void	show_char_to_char_1	args( ( CHAR_DATA *victim, CHAR_DATA *ch ) );
void	show_char_to_char	args( ( CHAR_DATA *list, CHAR_DATA *ch ) );



char *format_obj_to_char( OBJ_DATA *obj, CHAR_DATA *ch, bool fShort )
{
    static char buf [ MAX_STRING_LENGTH ];


    buf[0] = '\0';
    if( IS_OBJ_STAT( obj, ITEM_NOSHOW ) && IS_IMMORTAL( ch ))
       strcat( buf, "(Noshow) " );
    else if( IS_OBJ_STAT( obj, ITEM_NOSHOW ))
       return buf;
    if ( IS_OBJ_STAT( obj, ITEM_INVIS)     )   strcat( buf, "(Invis) "     );
    if ( ( IS_AFFECTED( ch, AFF_DETECT_EVIL  )
	  || ( IS_SET( race_table[ ch->race ].race_abilities,
		      RACE_DETECT_ALIGN )
	      && IS_GOOD( ch ) ) )
	&& IS_OBJ_STAT( obj, ITEM_EVIL )   )   strcat( buf, "(Red Aura) " );
    if ( ( IS_AFFECTED( ch, AFF_DETECT_GOOD  )
	  || ( IS_SET( race_table[ ch->race ].race_abilities,
		      RACE_DETECT_ALIGN )
	      && IS_EVIL( ch ) ) )
	&& IS_OBJ_STAT( obj, ITEM_BLESS )   )   strcat( buf, "(Blue Aura) " );
    if ( IS_AFFECTED( ch, AFF_DETECT_MAGIC )
	&& IS_OBJ_STAT( obj, ITEM_MAGIC )  )   strcat( buf, "(Magical) "   );
    if ( IS_OBJ_STAT( obj, ITEM_GLOW )     )   strcat( buf, "(Glowing) "   );
    if ( IS_OBJ_STAT( obj, ITEM_HUM )      )   strcat( buf, "(Humming) "   );
    if ( IS_OBJ_STAT( obj, ITEM_POISONED ) )   strcat( buf, "(Poisoned) "  );
    strcat ( buf, "");
    
    if ( fShort )
    {
	if ( obj->short_descr )
	    strcat( buf, obj->short_descr );
    }
    else
    {
	if ( obj->description )
	    strcat( buf, obj->description );
    }
    strcat ( buf, "&n");

    return buf;
}



/*
 * Show a list to a character.
 * Can coalesce duplicated items.
 */
void show_list_to_char( OBJ_DATA *list, CHAR_DATA *ch, bool fShort, bool fShowNothing )
{
    OBJ_DATA  *obj;
    char       buf [ MAX_STRING_LENGTH ];
    char       buf1[ MAX_STRING_LENGTH * 4 ];
    char     **prgpstrShow;
    char      *pstrShow;
    int       *prgnShow;
    int        nShow;
    int        iShow;
    int        count;
    bool       fCombine;

    if ( !ch->desc || !list )
	return;

    buf1[0] = '\0';
    /*
     * Alloc space for output lines.
     */
    count = 0;
    for ( obj = list; obj; obj = obj->next_content )
    {
	if ( obj->deleted )
	    continue;
	count++;
    }

    prgpstrShow	= alloc_mem( count * sizeof( char * ) );
    prgnShow    = alloc_mem( count * sizeof( int )    );
    nShow	= 0;

    /*
     * Format the list of objects.
     */
    for ( obj = list; obj; obj = obj->next_content )
    { 
	if ( obj->wear_loc == WEAR_NONE && can_see_obj( ch, obj ) )
	{
	    pstrShow = format_obj_to_char( obj, ch, fShort );
	    fCombine = FALSE;

	    if ( IS_NPC( ch ) || IS_SET( ch->act, PLR_COMBINE ) )
	    {
		/*
		 * Look for duplicates, case sensitive.
		 * Matches tend to be near end so run loop backwords.
		 */
		for ( iShow = nShow - 1; iShow >= 0; iShow-- )
		{
		    if ( !strcmp( prgpstrShow[iShow], pstrShow ) )
		    {
			prgnShow[iShow]++;
			fCombine = TRUE;
			break;
		    }
		}
	    }

	    /*
	     * Couldn't combine, or didn't want to.
	     */
	    if ( !fCombine )
	    {
		prgpstrShow [nShow] = str_dup( pstrShow );
		prgnShow    [nShow] = 1;
		nShow++;
	    }
	}
    }

    /*
     * Output the formatted list.
     */
    for ( iShow = 0; iShow < nShow; iShow++ )
    {
	if ( IS_NPC( ch ) || IS_SET( ch->act, PLR_COMBINE ) )
	{
	    if ( prgnShow[iShow] != 1 )
	    {
		sprintf( buf, "(%d) ", prgnShow[iShow] );
		strcat( buf1, buf );
	    }
	}
	strcat( buf1, prgpstrShow[iShow] );
	strcat( buf1, "\n\r" );
	free_string( prgpstrShow[iShow] );
    }

    if ( fShowNothing && nShow == 0 )
    {
	if ( IS_NPC( ch ) || IS_SET( ch->act, PLR_COMBINE ) )
	    strcat( buf1, "     " );
	strcat( buf1, "Nothing.\n\r" );
    }

    /*
     * Clean up.
     */
    free_mem( prgpstrShow, count * sizeof( char * ) );
    free_mem( prgnShow,    count * sizeof( int )    );

    send_to_char( buf1, ch );
    return;
}



void show_char_to_char_0( CHAR_DATA *victim, CHAR_DATA *ch )
{
    char buf [ MAX_STRING_LENGTH ];

    buf[0] = '\0';

    if ( !victim || !ch )
	return;

    if ( victim->rider
	&& victim->rider->in_room == ch->in_room )
        return;

    if ( !IS_NPC( victim ) && IS_SET( victim->act, PLR_WIZINVIS )
	&& get_trust( victim ) < get_trust( ch ) )
                                                strcat( buf, "(Wizinvis) "   );
    if ( IS_AFFECTED( victim, AFF_INVISIBLE )   )
                                                strcat( buf, "(Invis) "      );
    if ( IS_AFFECTED( victim, AFF_HIDE )        )
                                                strcat( buf, "(Hide) "       );
    if ( IS_AFFECTED( victim, AFF_CHARM )       )
                                                strcat( buf, "(Charmed) "    );
    if ( IS_AFFECTED( victim, AFF_PASS_DOOR )
	|| ( IS_SET( race_table[ victim->race ].race_abilities, RACE_PASSDOOR )
	    && (   !str_cmp( race_table[victim->race].name, "Undead" )
		|| !str_cmp( race_table[victim->race].name, "Vampire" ) ) ) )
                                                strcat( buf, "(Translucent) ");
    if ( IS_AFFECTED( victim, AFF_FAERIE_FIRE ) )
                                                strcat( buf, "(Pink Aura) "  );
    if ( IS_EVIL( victim )
	&& ( IS_AFFECTED( ch, AFF_DETECT_EVIL )
	    || ( IS_SET( race_table[ ch->race ].race_abilities,
			RACE_DETECT_ALIGN )
		&& IS_GOOD( ch ) ) ) )
                                                strcat( buf, "(Red Aura) "   );
    if ( IS_GOOD( victim )
	&& ( IS_AFFECTED( ch, AFF_DETECT_GOOD )
	    || ( IS_SET( race_table[ ch->race ].race_abilities,
			RACE_DETECT_ALIGN )
		&& IS_EVIL( ch ) ) ) )
                                                strcat( buf, "(Golden Aura) ");
    if ( IS_AFFECTED( victim, AFF_SANCTUARY )
	|| IS_SET( race_table[ victim->race ].race_abilities, RACE_SANCT ) )
                                                strcat( buf, "(White Aura) " );
    if ( IS_AFFECTED( victim, AFF_FLAMING ) )   strcat( buf, "(Black Aura) " );
    if ( !IS_NPC( victim ) && IS_SET( victim->act, PLR_AFK )  )
						strcat( buf, "[AFK] "        );

    strcat ( buf, "" );
    if ( victim->position == POS_STANDING && victim->long_descr[0] != '\0' )
    {
	strcat( buf, victim->long_descr );
        strcat( buf, "" );
	send_to_char( buf, ch );
	return;
    }

    strcat( buf, PERS( victim, ch ) );
    if ( !IS_NPC( victim ) && !IS_SET( ch->act, PLR_BRIEF ) )
	strcat( buf, victim->pcdata->title );

    switch ( victim->position )
    {
    case POS_DEAD:     strcat( buf, " is DEAD!!"              ); break;
    case POS_MORTAL:   strcat( buf, " is mortally wounded"   ); break;
    case POS_INCAP:    strcat( buf, " is incapacitated"      ); break;
    case POS_STUNNED:  strcat( buf, " is lying here stunned" ); break;
    case POS_SLEEPING: strcat( buf, " is sleeping here"      ); break;
    case POS_RESTING:  strcat( buf, " is resting here"       ); break;
    case POS_STANDING: strcat( buf, " is here"               ); break;
    case POS_SITTING:  strcat( buf, " is sitting here"       ); break;
    case POS_KNEELING: strcat( buf, " is kneeling here"      ); break;
    case POS_RECLINING:strcat( buf, " is lying here"         ); break;
    case POS_FIGHTING:
	strcat( buf, " is here," );
	if ( !victim->fighting )
	    strcat( buf, " fighting thin air??" );
	break;
    }

    // This code is to handle people sitting or prone in a fight.
    if( victim->fighting )
    {
        strcat( buf, " fighting " );
        if( victim->fighting == ch )
	    strcat( buf, "YOU!" );
	else if ( victim->in_room == victim->fighting->in_room )
	    strcat( buf, PERS( victim->fighting, ch ) );
	else
	    strcat( buf, "someone who left??" );
    }
 
    if ( victim->riding
	&& victim->riding->in_room == victim->in_room )
    {
        char buf1 [ MAX_STRING_LENGTH ];

        sprintf( buf1, ", mounted on %s.", PERS( victim->riding, ch ) );
        strcat( buf, buf1 );
    }
    else
    {
        // Show the player's race -- Veygoth
	strcat( buf, ". (" );
        strcat( buf, race_table[ victim->race ].colorname );
        strcat( buf, ")" );
    }

    strcat( buf, "\n\r" );
    buf[0] = UPPER( buf[0] );
    send_to_char( buf, ch );
    return;
}



void show_char_to_char_1( CHAR_DATA *victim, CHAR_DATA *ch )
{
    OBJ_DATA *obj;
    char      buf  [ MAX_STRING_LENGTH ];
    char      buf1 [ MAX_STRING_LENGTH ];
    int       iWear;
    int       percent;
    bool      found;

    if ( can_see( victim, ch ) )
    {
	act( "$n&n looks at you.", ch, NULL, victim, TO_VICT    );
	act( "$n&n looks at $N&n.",  ch, NULL, victim, TO_NOTVICT );
    }

    buf[0] = '\0';
    if ( victim->riding )
    {
	sprintf( buf1, "Mounted on %s, ", PERS( victim->riding, ch ) );
	strcat( buf, buf1 );
    }
    else
    if ( victim->rider )
    {
	sprintf( buf1, "Ridden by %s, ", PERS( victim->rider, ch ) );
	strcat( buf, buf1 );
    }

    sprintf( buf1, "$N&n the %s:\n\r", race_table[ victim->race ].colorname );
    strcat( buf, buf1 );

    if ( !IS_NPC( victim ) && is_clan( victim  ) )
    {
	sprintf( buf1, "%s of %s.\n\r", 
		flag_string( rank_flags, victim->pcdata->rank ),
		victim->pcdata->clan->name );
	buf1[0] = UPPER( buf1[0] );
	strcat( buf, buf1 );
    }
    
    act( buf, ch, NULL, victim, TO_CHAR );

    if ( victim->description[0] != '\0' )
    {
	send_to_char( victim->description, ch );
    }
    else
    {
	act( "You see nothing special about $M.", ch, NULL, victim, TO_CHAR );
    }

    if ( victim->max_hit > 0 )
	percent = ( 100 * victim->hit ) / victim->max_hit;
    else
	percent = -1;

    strcpy( buf, PERS( victim, ch ) );

         if ( percent >= 100 ) strcat( buf, " is in &+gperfect health&n.\n\r" );
    else if ( percent >=  90 ) strcat( buf, " is &+yslightly scratched&n.\n\r" );
    else if ( percent >=  80 ) strcat( buf, " has a &+yfew bruises&n.\n\r" );
    else if ( percent >=  70 ) strcat( buf, " has &+Ysome cuts&n.\n\r" );
    else if ( percent >=  60 ) strcat( buf, " has &+Mseveral wounds&n.\n\r" );
    else if ( percent >=  50 ) strcat( buf, " has &+mmany nasty wounds&n.\n\r" );
    else if ( percent >=  40 ) strcat( buf, " is &+Rbleeding freely&n.\n\r" );
    else if ( percent >=  30 ) strcat( buf, " is &+Rcovered in blood&n.\n\r" );
    else if ( percent >=  20 ) strcat( buf, " is &+rleaking guts&n.\n\r" );
    else if ( percent >=  10 ) strcat( buf, " is &+ralmost dead&n.\n\r" );
    else                       strcat( buf, " is &+rDYING&n.\n\r"  );

    buf[0] = UPPER( buf[0] );
    send_to_char( buf, ch );

    found = FALSE;
    for ( iWear = 0; iWear < MAX_WEAR; iWear++ )
    {
	if ( ( obj = get_eq_char( victim, topdown_eq[iWear] ) )
	    && can_see_obj( ch, obj ) )
	{
	    if ( !found )
	    {
		send_to_char( "\n\r", ch );
		act( "$E is using", ch, NULL, victim, TO_CHAR );
		found = TRUE;
	    }
	    send_to_char( where_name[topdown_eq[iWear]], ch );
	    send_to_char( format_obj_to_char( obj, ch, TRUE ), ch );
	    send_to_char( "\n\r", ch );
	}
    }

    // Keep in mind that players can spam looking at someone in order
    // to increase their skill in peek -- this will need to be fixed
    // - Veygoth
    if ( ( victim != ch
	 && !IS_NPC( ch ) && number_percent( ) < ch->pcdata->skl_lrn[gsn_peek] )
	|| ch->riding == victim 
	|| ch->rider  == victim )
    {
	send_to_char( "\n\rYou peek at the inventory:\n\r", ch );
        skill_practice( ch, gsn_peek );
	show_list_to_char( victim->carrying, ch, TRUE, TRUE );
    }

    return;
}



void show_char_to_char( CHAR_DATA *list, CHAR_DATA *ch )
{
    CHAR_DATA *rch;

    if ( !list )
        return;

    for ( rch = list; rch; rch = rch->next_in_room )
    {
        if ( rch->deleted || rch == ch )
	    continue;

	if ( !IS_NPC( rch )
	    && IS_SET( rch->act, PLR_WIZINVIS )
	    && get_trust( ch ) < get_trust( rch ) )
	    continue;

	if ( can_see( ch, rch ) )
	{
	    show_char_to_char_0( rch, ch );
	}
	else if ( room_is_dark( ch->in_room )
		 && ( IS_AFFECTED( rch, AFF_INFRARED )
		     || IS_SET( race_table[ rch->race ].race_abilities,
			       RACE_INFRAVISION ) ) )
	{
	    send_to_char( "You see glowing red eyes watching YOU!\n\r", ch );
	}
    }

    return;
} 

bool check_blind( CHAR_DATA *ch )
{
    if ( !IS_NPC( ch ) && IS_SET( ch->act, PLR_HOLYLIGHT ) )
	return TRUE;

    if ( IS_AFFECTED( ch, AFF_BLIND ) )
    {
	send_to_char( "You can't see a thing!\n\r", ch );
	return FALSE;
    }

    return TRUE;
}

void do_look( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA  *obj;
    CHAR_DATA *victim;
    EXIT_DATA *pexit;
    char       buf  [ MAX_STRING_LENGTH ];
    char       arg1 [ MAX_INPUT_LENGTH  ];
    char       arg2 [ MAX_INPUT_LENGTH  ];
    char      *pdesc;
    int        door;

    if ( !IS_NPC( ch ) && !ch->desc ) 
	return;

    if ( ch->position < POS_SLEEPING )
    {
	send_to_char( "You can't see anything but stars!  See how pretty!\n\r",
		     ch );
	return;
    }

    if ( ch->position == POS_SLEEPING )
    {
	send_to_char( "You can't see anything, you're sleeping!  Zzz.\n\r",
		     ch );
	return;
    }

    if ( !check_blind( ch ) )
	return;

    if ( !IS_NPC( ch )
	&& !IS_SET( ch->act, PLR_HOLYLIGHT )
	&& room_is_dark( ch->in_room )
        && !IS_SET( race_table[ch->race].race_abilities, RACE_ULTRAVISION )
        && !IS_AFFECTED( ch, AFF_ULTRAVISION ))
    {
	send_to_char( "It is pitch black ... \n\r", ch );
	show_char_to_char( ch->in_room->people, ch );
	return;
    }

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

    if ( arg1[0] == '\0' || !str_cmp( arg1, "auto" ) )
    {
	/* 'look' or 'look auto' */
	if ( !IS_SET( ch->act, PLR_EDIT_INFO ) )
	{
	    sprintf ( buf, "%s&n\n\r   ", ch->in_room->name );
	    send_to_char( buf, ch );
	}
	else
	    show_room_info( ch, ch->in_room );

	if ( arg1[0] == '\0'
	    || ( !IS_NPC( ch ) && !IS_SET( ch->act, PLR_BRIEF ) ) ) 
	{
            sprintf ( buf, "%s&n", ch->in_room->description );
	    send_to_char( buf, ch );
	}
	
        if ( IS_SET( ch->in_room->room_flags, ROOM_SILENT ) )
	    send_to_char( "It seems eerily quiet.\n\r", ch );

	if ( !IS_NPC( ch ) && IS_SET( ch->act, PLR_AUTOEXIT ) )
	    do_exits( ch, "auto" );

	show_list_to_char( ch->in_room->contents, ch, FALSE, FALSE );
	show_char_to_char( ch->in_room->people,   ch );
	return;
    }

    if ( !str_prefix( arg1, "in" ) )
    {
	/* 'look in' */
	if ( arg2[0] == '\0' )
	{
	    send_to_char( "Look in what?\n\r", ch );
	    return;
	}

	if ( !( obj = get_obj_here( ch, arg2 ) ) )
	{
	    send_to_char( "You do not see that here.\n\r", ch );
	    return;
	}

	switch ( obj->item_type )
	{
	default:
	    send_to_char( "That is not a container.\n\r", ch );
	    break;

	case TYPE_DRINK_CON:
	    if ( obj->value[1] <= 0 )
	    {
		send_to_char( "It is empty.\n\r", ch );
		break;
	    }

	    sprintf( buf, "It's %s full of a %s liquid.\n\r",
		obj->value[1] <     obj->value[0] / 4
		    ? "less than half" :
		obj->value[1] < 3 * obj->value[0] / 4
		    ? "about half"     : "more than half",
		liq_table[obj->value[2]].liq_color
		);

	    send_to_char( buf, ch );
	    break;

	case TYPE_CONTAINER:
	case TYPE_CORPSE_NPC:
	case TYPE_CORPSE_PC:
	    if ( IS_SET( obj->value[1], CONT_CLOSED ) )
	    {
		send_to_char( "It is closed.\n\r", ch );
		break;
	    }

	    act( "$p contains:", ch, obj, NULL, TO_CHAR );
	    show_list_to_char( obj->contains, ch, TRUE, TRUE );
	    break;
	}
	return;
    }

    if ( ( victim = get_char_room( ch, arg1 ) ) )
    {
	show_char_to_char_1( victim, ch );
	return;
    }

    for ( obj = ch->carrying; obj; obj = obj->next_content )
    {
	if ( can_see_obj( ch, obj ) )
	{
	    pdesc = get_extra_descr( arg1, obj->extra_descr );
	    if ( pdesc )
	    {
		send_to_char( pdesc, ch );
		return;
	    }

	    pdesc = get_extra_descr( arg1, obj->pIndexData->extra_descr );
	    if ( pdesc )
	    {
		send_to_char( pdesc, ch );
		return;
	    }
	}

	if ( is_name( arg1, obj->name ) )
	{
	    send_to_char( obj->description, ch );
	    send_to_char( "\n\r", ch );
	    return;
	}
    }

    for ( obj = ch->in_room->contents; obj; obj = obj->next_content )
    {
	if ( can_see_obj( ch, obj ) )
	{
	    pdesc = get_extra_descr( arg1, obj->extra_descr );
	    if ( pdesc )
	    {
		send_to_char( pdesc, ch );
		return;
	    }

	    pdesc = get_extra_descr( arg1, obj->pIndexData->extra_descr );
	    if ( pdesc )
	    {
		send_to_char( pdesc, ch );
		return;
	    }
	}

	if ( is_name( arg1, obj->name ) )
	{
	    send_to_char( obj->description, ch );
	    send_to_char( "\n\r", ch );
	    return;
	}
    }

    pdesc = get_extra_descr( arg1, ch->in_room->extra_descr );
    if ( pdesc )
    {
	send_to_char( pdesc, ch );
	return;
    }

         if ( !str_prefix( arg1, "north" ) ) door = 0;
    else if ( !str_prefix( arg1, "east"  ) ) door = 1;
    else if ( !str_prefix( arg1, "south" ) ) door = 2;
    else if ( !str_prefix( arg1, "west"  ) ) door = 3;
    else if ( !str_prefix( arg1, "up"    ) ) door = 4;
    else if ( !str_prefix( arg1, "down"  ) ) door = 5;
    else if ( !str_prefix( arg1, "northwest" ) ) door = 6;
    else if ( !str_prefix( arg1, "southwest" ) ) door = 7;
    else if ( !str_prefix( arg1, "northeast" ) ) door = 8;
    else if ( !str_prefix( arg1, "southeast" ) ) door = 9;
    else
    {
	send_to_char( "You do not see that here.\n\r", ch );
	return;
    }

    /* 'look direction' */
    if ( !( pexit = ch->in_room->exit[door] ) )
    {
	send_to_char( "Nothing special there.\n\r", ch );
	return;
    }

    if ( pexit->description && pexit->description[0] != '\0' )
	send_to_char( pexit->description, ch );
    else
	send_to_char( "Nothing special there.\n\r", ch );

    if (   pexit->keyword
	&& pexit->keyword[0] != '\0'
	&& pexit->keyword[0] != ' ' )
    {
             if ( IS_SET( pexit->exit_info, EX_BASHED ) )
	    act( "The $d has been bashed from its hinges.",
		ch, NULL, pexit->keyword, TO_CHAR );
	else if ( IS_SET( pexit->exit_info, EX_CLOSED ) )
	    act( "The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR );
	else if ( IS_SET( pexit->exit_info, EX_ISDOOR ) )
	    act( "The $d is open.",   ch, NULL, pexit->keyword, TO_CHAR );
    }

    return;
}

void do_examine( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *obj;
    char      buf [ MAX_STRING_LENGTH ];
    char      arg [ MAX_INPUT_LENGTH  ];

    one_argument( argument, arg );

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

    do_look( ch, arg );

    if ( ( obj = get_obj_here( ch, arg ) ) )
    {
	switch ( obj->item_type )
	{
	default:
	    break;

	case TYPE_DRINK_CON:
	case TYPE_CONTAINER:
	case TYPE_CORPSE_NPC:
	case TYPE_CORPSE_PC:
	    send_to_char( "When you look inside, you see:\n\r", ch );
	    sprintf( buf, "in %s", arg );
	    do_look( ch, buf );
	}
    }

    return;
}

/*
 * Thanks to Zrin for auto-exit part.
 */
void do_exits( CHAR_DATA *ch, char *argument )
{
           EXIT_DATA       *pexit;
    extern char *    const  dir_name [ ];
           char             buf      [ MAX_STRING_LENGTH ];
           int              door;
           bool             found;
           bool             fAuto;

    buf[0] = '\0';
    fAuto  = !str_cmp( argument, "auto" );

    if ( !check_blind( ch ) )
	return;

    strcpy( buf, fAuto ? "&+c[Exits:" : "Obvious exits:\n\r" );

    found = FALSE;

    // Veygoth - made it show the direction with an asterisk if it
    // has a closed door, and in exits command it shows up as a
    // closed <whatever>.  It was silly not to show that a room had
    // doors and such.
    for ( door = 0; door < MAX_DIR; door++ )
    {
	if ( ( pexit = ch->in_room->exit[door] )
	    && pexit->to_room )
	{
	    found = TRUE;
	    if ( fAuto )
	    {
		strcat( buf, " " );
                if(IS_SET( pexit->exit_info, EX_CLOSED ))
                  strcat( buf, "&+m*&+c" );
		strcat( buf, dir_name[door] );
	    }
	    else
	    {
                if(!IS_SET( pexit->exit_info, EX_CLOSED ))
		{
                  sprintf( buf + strlen( buf ), "%-5s - %s\n\r",
		    capitalize( dir_name[door] ),
		    room_is_dark( pexit->to_room )
			? "Too dark to tell" : pexit->to_room->name );
                }
                else
                {
                  sprintf( buf + strlen( buf ), "%-5s - closed %s\n\r",
		    capitalize( dir_name[door] ),
		    pexit->keyword );
                }
	    }
	}
    }

    if ( !found )
	strcat( buf, fAuto ? " none" : "None.\n\r" );

    if ( fAuto )
	strcat( buf, "]&n\n\r" );

    send_to_char( buf, ch );
    return;
}

/*
 * Enhanced version of do_exits() done by Zen.
 */
void show_room_info( CHAR_DATA *ch, ROOM_INDEX_DATA *room )
{
    char buf	[ MAX_STRING_LENGTH ];
    char buf1	[ MAX_STRING_LENGTH ];

    if ( !IS_SET( ch->act, PLR_EDIT_INFO ) )
	return;

    buf[0] = '\0';
    strcpy ( buf1, flag_string( room_flags, room->room_flags ) );
    sprintf( buf, "[%d] %s ( %s ) [ %s ]\n\r",
	    room->vnum,
	    room->name,
	    flag_string( sector_flags, room->sector_type ),
	    all_capitalize( buf1 ) );
    buf1[0] = '\0';
    strcat( buf1, buf );
    send_to_char( buf1, ch );

    return;
}

void do_score( CHAR_DATA *ch, char *argument )
{
    AFFECT_DATA *paf;
    char         buf  [ MAX_STRING_LENGTH ];
    char         buf1 [ MAX_STRING_LENGTH ];

    buf1[0] = '\0';

    sprintf( buf,
	    "&+WName: &+G%s&n%s\n\r",
	    ch->name,
	    IS_NPC( ch ) ? "" : ch->pcdata->title );
    strcat( buf1, buf );

    sprintf( buf,
	    "&+WRace: &n%-10.10s&n                 &+WClass: %-15.15s&n          &+WSex: %s\n\r",
	    race_table[ ch->race ].colorname,
            class_table[ch->class]->who_name,
	    capitalize( get_sex( ch )));
    strcat( buf1, buf );

    sprintf( buf,
	    "&+WLevel: %-5d                Played: %d hours\n\r",
	    ch->level,
	    ( ch->played / 3600 ) );
    strcat( buf1, buf );
// May want to throw character's age in here somewhere

    sprintf( buf,
            "&+WExperience: &+b%s&n\n\r\n\r",
            get_exp_string( ch ) );
    strcat( buf1, buf );

    sprintf( buf,
	    "&+WCurrent/Max Health: [&+g%4d&+W / &+g%-4d&+W]     Coins:     Carried     In Bank\n\r",
	    ch->hit,  ch->max_hit );
    strcat( buf1, buf );

    sprintf( buf,
	    "&+WCurrent/Max Moves:  [&+g%4d&+W / &+g%-4d&+W]     &+WPlatinum      %4d        %4d\n\r",
	    ch->move, ch->max_move,
            ch->money.platinum, ch->pcdata->bank.platinum );
    strcat( buf1, buf );

    sprintf( buf,
	    "Current/Max Mana:   [&+g%4d&+W / &+g%-4d&+W]     &+YGold          %4d        %4d\n\r",
	    ch->mana, ch->max_mana,
            ch->money.gold, ch->pcdata->bank.gold );
    strcat( buf1, buf );

    sprintf( buf,
	    "                                      &+wSilver        %4d        %4d\n\r",
            ch->money.silver, ch->pcdata->bank.silver );
    strcat( buf1, buf );

    sprintf( buf,
	    "&+WFrags: &+W%-3d&n                            &+yCopper        %4d        %4d\n\r\n\r",
	    ch->pcdata->frags,
            ch->money.copper, ch->pcdata->bank.copper );
    strcat( buf1, buf );

    if ( ch->affected )
    {
        bool printed = FALSE;

	for ( paf = ch->affected; paf; paf = paf->next )
	{
	    if ( paf->deleted )
	        continue;

	    if ( !printed )
	    {
		strcat( buf1, "&+BActive Spells:&+W\n\r" );
		printed = TRUE;
	    }

            if( paf->skill && paf->spell )
                log_string( "Possible bug - affect with both spell and skill type defined" );

            if( paf->skill )
            {
	      sprintf( buf, "%s", skills_table[paf->skill].name );
	      strcat( buf1, buf );
            }
            else if( paf->spell )
            {
	      sprintf( buf, "%s", spells_table[paf->spell].name );
	      strcat( buf1, buf );
            }
            else
            {
              log_string( "affect without spell or skill associated. possible bug" );
            }

	    if ( IS_IMMORTAL( ch ) )
	    {
		sprintf( buf,
			" modifies %s by %d for %d hours.",
			affect_loc_name( paf->location ),
			paf->modifier,
			paf->duration );
		strcat( buf1, buf );
	    }

	    strcat( buf1, "\n\r" );
	}
    }
    strcat( buf1, "&n" );
    send_to_char( buf1, ch );
    return;
}

void do_exp( CHAR_DATA *ch, char *arg )
{
    char buf[MAX_STRING_LENGTH];

    sprintf( buf, "&+b%s&n\n\r",
	    get_exp_string( ch ));
    send_to_char( buf, ch );
}

char *	const	day_name	[] =
{
    "the Moon", "the Bull", "Deception", "Thunder", "Freedom",
    "the Great Gods", "the Sun"
};

char *	const	month_name	[] =
{
    "Winter", "the Winter Wolf", "the Frost Giant", "the Old Forces",
    "the Grand Struggle", "the Spring", "Nature", "Futility", "the Dragon",
    "the Sun", "the Heat", "the Battle", "the Dark Shades", "the Shadows",
    "the Long Shadows", "the Ancient Darkness", "the Great Evil"
};

void do_time( CHAR_DATA *ch, char *argument )
{
           char  buf           [ MAX_STRING_LENGTH ];
    extern char  str_boot_time[];
           char *suf;
           int   day;

    day     = time_info.day + 1;

         if ( day > 4 && day <  20 ) suf = "th";
    else if ( day % 10 ==  1       ) suf = "st";
    else if ( day % 10 ==  2       ) suf = "nd";
    else if ( day % 10 ==  3       ) suf = "rd";
    else                             suf = "th";

    sprintf( buf,
	    "It is %d o'clock %s, Day of %s, %d%s the Month of %s.\n\rThe year is %d.\n\r",
	    ( time_info.hour % 12 == 0 ) ? 12 : time_info.hour % 12,
	    time_info.hour >= 12 ? "pm" : "am",
	    day_name[day % 7],
	    day, suf,
	    month_name[time_info.month],
            time_info.year );
    send_to_char( buf, ch );
    sprintf( buf,
	    "Magma MUD started up %s\rThe system time is %s\r",
	    str_boot_time,
	    (char *) ctime( &current_time ) );
    send_to_char( buf, ch );
    if ( down_time > 0 )
    {
	sprintf( buf, "%s will be at %s\r", Reboot ? "Reboot" : "Shutdown",
		(char *) ctime( &down_time ) );
	send_to_char( buf, ch );
    }
    return;
}

void do_weather( CHAR_DATA *ch, char *argument )
{
           char         buf     [ MAX_STRING_LENGTH ];
           char         descr   [ MAX_STRING_LENGTH ];
           int          wind;
    static char * const sky_look[ 8 ] =
    {
	"cloudless",
	"cloudy",
	"rainy",
	"lit by flashes of lightning",
	"slightly overcast",
	"scattered with a few flakes",
	"filled with flakes",
	"a blizzard of white"
    };

    if ( !IS_OUTSIDE( ch ) )
    {
	send_to_char( "You can't see the weather indoors.\n\r", ch );
	return;
    }

    wind = weather_info.windspeed;
    descr[0] = '\0';
    sprintf( buf, "The sky is %s ",
	    (time_info.month <= 4 || time_info.month >= 15)
	    ? sky_look[weather_info.sky + 4]
	    : sky_look[weather_info.sky] );
    strcat( descr, buf );
    sprintf( buf, "and a %s %sward %s blows.\n\r",
	    ( weather_info.temperature < 35 ) ? "cold" :
	    ( weather_info.temperature < 60 ) ? "cool" :
	    ( weather_info.temperature < 90 ) ? "warm" : "hot",
	    dir_name[abs( weather_info.winddir ) % 3],
	    wind <= 20 ? "breeze" :
	    wind <= 50 ? "wind" :
	    wind <= 80 ? "gust" :
			 "torrent" );
    strcat( descr, buf );

    send_to_char( descr, ch );
    return;
}

void do_help( CHAR_DATA *ch, char *argument )
{
    HELP_DATA *pHelp;
    bool       hfound = FALSE; /* modification to show multiple helps
				  by Robin Goodall from merc mailing list */

    if ( argument[0] == '\0' )
	argument = "summary";

    for ( pHelp = help_first; pHelp; pHelp = pHelp->next )
    {
	if ( pHelp->level > get_trust( ch ) )
	    continue;

	if ( is_name( argument, pHelp->keyword ) )
	{
	    if ( hfound )
	        send_to_char( "\n\r----------------------------------------------------------------------------\n\r\n\r", ch );

	    if ( pHelp->level >= 0 && str_cmp( argument, "imotd" ) )
	    {
		send_to_char( pHelp->keyword, ch );
		send_to_char( "\n\r", ch );
	    }

	    /*
	     * Strip leading '.' to allow initial blanks.
	     */
	    if ( pHelp->text[0] == '.' )
		send_to_char( pHelp->text+1, ch );
	    else
		send_to_char( pHelp->text  , ch );
	    hfound = TRUE;
	}
    }
    
    if ( !hfound )
        send_to_char( "No help on that word.\n\r", ch );
    return;
}



/*
 * New 'who' command originally by Alander of Rivers of Mud.
 *
 * 'who good' and 'who evil' added by Veygoth
 */
void do_who( CHAR_DATA *ch, char *argument )
{
    DESCRIPTOR_DATA *d;
    char             buf      [ MAX_STRING_LENGTH*3 ];
    int              iClass;
    int              iLevelLower;
    int              iLevelUpper;
    int              nNumber;
    int              nMatch;
    bool             rgfClass [ MAX_CLASS ];
    bool             fClassRestrict;
    bool             fImmortalOnly;
    bool             fGoodOnly; // for racewar wholist
    bool             fEvilOnly; // for racewar wholist

    WHO_DATA *curr_who		= NULL;
    WHO_DATA *next_who		= NULL;
    WHO_DATA *first_mortal	= NULL;
    WHO_DATA *first_imm		= NULL;

    /*
     * Set default arguments.
     */
    iLevelLower    = 0;
    iLevelUpper    = L_DIR; /*Used to be Max_level */
    fClassRestrict = FALSE;
    fImmortalOnly  = FALSE;
    fGoodOnly      = FALSE;
    fEvilOnly      = FALSE;
    for ( iClass = 0; iClass < MAX_CLASS; iClass++ )
	rgfClass[iClass] = FALSE;

    /*
     * Parse arguments.
     */
    nNumber = 0;
    for ( ;; )
    {
	char arg [ MAX_STRING_LENGTH ];

	argument = one_argument( argument, arg );
	if ( arg[0] == '\0' )
	    break;

	if ( is_number( arg ) )
	{
	    switch ( ++nNumber )
	    {
	    case 1: iLevelLower = atoi( arg ); break;
	    case 2: iLevelUpper = atoi( arg ); break;
	    default:
		send_to_char( "Only two level numbers allowed.\n\r", ch );
		return;
	    }
	}
	else
	{
	    int iClass;

	    /*
	     * Look for classes to turn on.
	     */
	    arg[3]    = '\0';
	    if ( !str_prefix( arg, "imm" ) )
	    {
		fImmortalOnly = TRUE;
	    }
            else if ( !str_prefix( arg, "good" ) )
            {
                fGoodOnly = TRUE;
            }
            else if( !str_prefix( arg, "evil" ) )
            {
                fEvilOnly = TRUE;
            }
	    else
	    {
		fClassRestrict = TRUE;
		for ( iClass = 0; iClass < MAX_CLASS; iClass++ )
		{
		    if ( !str_prefix( arg, class_table[iClass]->name ) )
		    {
			rgfClass[iClass] = TRUE;
			break;
		    }
		}

		if ( iClass == MAX_CLASS )
		{
		    send_to_char( "That's not a class.\n\r", ch );
		    return;
		}
	    }
	}
    }

    /*
     * Now show matching chars.
     */
    nMatch = 0;
    for ( d = descriptor_list; d; d = d->next )
    {
	CHAR_DATA       *wch;
	char      const *class;

	wch   = ( d->original ) ? d->original : d->character;

	/*
	 * Check for match against restrictions.
	 * Don't use trust as that exposes trusted mortals.
	 */
	if ( d->connected != CON_PLAYING || !can_see( ch, wch ) )
	    continue;

	if (   wch->level < iLevelLower
	    || wch->level > iLevelUpper
	    || ( fImmortalOnly  && wch->level < LEVEL_HERO )
	    || ( fClassRestrict && !rgfClass[wch->class] )
            || ( fGoodOnly && race_table[wch->race].racewar_side != RACEWAR_GOOD)
            || ( fEvilOnly && race_table[wch->race].racewar_side != RACEWAR_EVIL) )
	    continue;

	nMatch++;
	buf[0] = '\0';

	/*
	 * Figure out what to print for class.
	 */
	class = class_table[wch->class]->who_name;
	if ( wch->level >= LEVEL_HERO )
	    switch ( wch->level )
	      {
	      default: break;
	      case L_DIR: class = "&+r Overlord  &n";	break;
	      case L_SEN: class = "&+LImplementor&n";	break;
	      case L_JUN: class = "&+mGreater God&n";	break;
	      case L_APP: class = "&+MLesser God &n";	break;
              case L_DEM: class = "&+y  Demigod  &n";   break;
              case L_IMM: class = "&+c Immortal  &n";   break;
              case L_AVA: class = "&+R  Avatar   &n";   break;
              case L_BUI: class = "&+LBu&+wil&+Wder&n";   break;
	      }

	/*
	 * Format it up.
	 */
	if ( wch->level < LEVEL_IMMORTAL )
	{
	    char buf1 [ MAX_STRING_LENGTH ];
	    char buf2 [ MAX_STRING_LENGTH ];
	    char leftletter;
	    char rightletter;

	    sprintf( buf1, "%s%s%s (%s)",
		    IS_SET( wch->act, PLR_AFK      ) ? "[AFK] "    : "",
		    wch->name,
		    wch->pcdata->title,
		    race_table[wch->race].colorname );
	    leftletter = !is_clan( wch ) 
			? ' '
			: ( wch->pcdata->clan->clan_type == CLAN_GUILD ) ? '<'
			: '(';
	    rightletter = !is_clan( wch ) 
			? ' '
			: ( wch->pcdata->clan->clan_type == CLAN_GUILD ) ? '>'
			: ')';
	    sprintf( buf2, " %c%s%c",
		    leftletter,
		    !is_clan( wch ) ? "" : wch->pcdata->clan->who_name,
		    rightletter );
	    sprintf( buf + strlen( buf ), "&+L[&n%-2d %-12s&+L]&n %s%s\n\r",
		    wch->level,
		    class,
		    buf1,
		    buf2 );
	}
	else
	{
	    char buf1 [ MAX_STRING_LENGTH ];
	    char buf2 [ MAX_STRING_LENGTH ];
	    char leftletter;
	    char rightletter;

	    sprintf( buf1, "%s%s%s%s",
		    IS_SET( wch->act, PLR_WIZINVIS ) ? "(WIZINVIS) " : "", 
		    IS_SET( wch->act, PLR_AFK      ) ? "[AFK] "    : "",
		    wch->name,
		    wch->pcdata->title );
	    leftletter = !is_clan( wch ) 
			? ' '
			: ( wch->pcdata->clan->clan_type == CLAN_GUILD ) ? '<'
			: '(';
	    rightletter = !is_clan( wch ) 
			? ' '
			: ( wch->pcdata->clan->clan_type == CLAN_GUILD ) ? '>'
			: ')';
	    sprintf( buf2, " %c%s%c",
		    leftletter,
		    !is_clan( wch ) ? "" : wch->pcdata->clan->who_name,
		    rightletter );
	    sprintf( buf + strlen( buf ), "&+L[&n%-15s&+L]&n %s%s\n\r",
		    class,
		    buf1,
		    buf2 );
	}

	curr_who	= alloc_mem( sizeof( WHO_DATA ) );
	curr_who->text	= str_dup( buf );

	if ( wch->level < LEVEL_IMMORTAL )
	{
	    curr_who->next	= first_mortal;
	    first_mortal	= curr_who;
	}
	else
	{
	    curr_who->next	= first_imm;
	    first_imm		= curr_who;
	}
    }

    // Veygoth - made immortals show up above mortals because immortals
    // are more important.
    if ( first_imm )
	send_to_char( "&+b-----------------------------------[ &+BIMMORTALS&+b ]------------------------------&n\n\r", ch );

    for ( curr_who = first_imm; curr_who; curr_who = next_who )
    {
	send_to_char( curr_who->text, ch );
	next_who = curr_who->next;
	free_string( curr_who->text );
	free_mem( curr_who, sizeof( WHO_DATA ) ); 
    }

    if ( first_mortal )
	send_to_char( "&+b------------------------------------[ &+BMORTALS&+b ]-------------------------------&n\n\r", ch );

    for ( curr_who = first_mortal; curr_who; curr_who = next_who )
    {
	send_to_char( curr_who->text, ch );
	next_who = curr_who->next;
	free_string( curr_who->text );
	free_mem( curr_who, sizeof( WHO_DATA ) ); 
    }

    send_to_char( "&+b------------------------------------------------------------------------------&n\n\r", ch );

    sprintf( buf, "You see %d player%s in the game.\n\r",
	    nMatch, nMatch == 1 ? "" : "s" );
    send_to_char( buf, ch );
    return;
}

/* Contributed by Kaneda */
void do_whois( CHAR_DATA *ch, char *argument )
{
    char            *race;
    DESCRIPTOR_DATA *d;
    char             buf  [ MAX_STRING_LENGTH  ];
    char             name [ MAX_INPUT_LENGTH   ];
 
    race = "\0";

    one_argument( argument, name );

    if( name[0] == '\0' )
    {
	send_to_char( "Usage:  whois <name>\n\r", ch );
	return;
    }

    name[0] = UPPER( name[0] );

    buf[0] = '\0';
    for( d = descriptor_list ; d ; d = d->next )
    {
	CHAR_DATA       *wch;
	char      const *class;
	
	wch = ( d->original ) ? d->original : d->character; 

	if( d->connected != CON_PLAYING || !can_see( ch, wch ) )
	    continue;
  
	if( str_prefix( name, wch->name ) )
	    continue;

	class = class_table[ wch->class ]->who_name;
	if( wch->level >= LEVEL_IMMORTAL )
	    switch( wch->level )
	    {
	      case L_DIR: class = "&+r Overlord&n";	break;
	      case L_SEN: class = "&+LImplementor&n";	break;
	      case L_JUN: class = "&+mGreater God&n";	break;
	      case L_APP: class = "&+MLesser God&n";	break;
              case L_DEM: class = "&+y Demigod&n";      break;
              case L_IMM: class = "&+c Immortal&n";     break;
              case L_AVA: class = "&+R  Avatar&n";      break;
	    }

	/*
	 * Format it up.
	 */
	if ( wch->level < LEVEL_IMMORTAL )
	{
	    sprintf( buf + strlen( buf ), "%s%s\n\r",
		    wch->name,
		    wch->pcdata->title );
	    sprintf( buf + strlen( buf ), "%s\n\r",
		    IS_SET( wch->act, PLR_AFK      ) ? "[AFK] "    : "" );
	    sprintf( buf + strlen( buf ), "level %d %s %s.\n\r",
		    wch->level,
		    class,
                    race_table[wch->race].colorname );
	}
	else
	{
	    sprintf( buf + strlen( buf ), "%s%s\n\r",
		    wch->name,
		    wch->pcdata->title );
	    sprintf( buf + strlen( buf ), "%s%s\n\r",
		    IS_SET( wch->act, PLR_WIZINVIS ) ? "(WIZINVIS) " : "", 
		    IS_SET( wch->act, PLR_AFK      ) ? "[AFK] "    : "" );
	    sprintf( buf + strlen( buf ), "%s\n\r",
		    class );
	}

	if ( is_clan( wch ) )
	{
	    sprintf( buf + strlen( buf ), "%s of %s.\n\r",
		    flag_string( rank_flags, wch->pcdata->rank ),
		    wch->pcdata->clan->name );
	}

	strcat( buf, "-----------------------------------------------------------------------------\n\r" );
      }

    if ( buf[0] == '\0' )
        send_to_char( "No one matches the given criteria.\n\r", ch );
    else
        send_to_char( buf, ch );
    return;
}


void do_inventory( CHAR_DATA *ch, char *argument )
{
    send_to_char( "You are carrying:\n\r", ch );
    show_list_to_char( ch->carrying, ch, TRUE, TRUE );
    return;
}



void do_equipment( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *obj;
    int       iWear;
    bool      found;

    send_to_char( "You are using:\n\r", ch );
    found = FALSE;
    for ( iWear = 0; iWear < MAX_WEAR; iWear++ )
    {
	if ( !( obj = get_eq_char( ch, topdown_eq[iWear] ) ) )
	    continue;

	send_to_char( where_name[topdown_eq[iWear]], ch );
	if ( can_see_obj( ch, obj ) )
	{
	    send_to_char( format_obj_to_char( obj, ch, TRUE ), ch );
	    send_to_char( "\n\r", ch );
	}
	else
	{
	    send_to_char( "something.\n\r", ch );
	}
	found = TRUE;
    }

    if ( !found )
	send_to_char( "Nothing.\n\r", ch );

    return;
}



void do_compare( CHAR_DATA *ch, char *argument )
{
    OBJ_DATA *obj1;
    OBJ_DATA *obj2;
    char     *msg;
    char      arg1 [ MAX_INPUT_LENGTH ];
    char      arg2 [ MAX_INPUT_LENGTH ];
    int       value1;
    int       value2;

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

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

    if ( !( obj1 = get_obj_carry( ch, arg1 ) ) )
    {
	send_to_char( "You do not have that item.\n\r", ch );
	return;
    }

    if ( arg2[0] == '\0' )
    {
	for ( obj2 = ch->carrying; obj2; obj2 = obj2->next_content )
	{
	    if ( obj2->wear_loc != WEAR_NONE
		&& can_see_obj( ch, obj2 )
		&& obj1->item_type == obj2->item_type
		&& ( obj1->wear_flags & obj2->wear_flags & ~ITEM_TAKE) != 0 )
		break;
	}

	if ( !obj2 )
	{
	    send_to_char( "You aren't wearing anything comparable.\n\r", ch );
	    return;
	}
    }
    else
    {
	if ( !( obj2 = get_obj_carry( ch, arg2 ) ) )
	{
	    char new_arg2 [ MAX_INPUT_LENGTH ];
	    int  number;

	    /*  Strip off number argument, subtract one, paste it together */
	    number = number_argument( arg2, arg2 );
	    if ( number > 1 )  number--;
	    sprintf( new_arg2, "%d.%s", number, arg2 );

	    if ( !( obj2 = get_obj_wear( ch, new_arg2 ) ) )
	    {
		send_to_char( "You do not have that item.\n\r", ch );
		return;
	    }
	
	    if ( ( obj1->wear_flags & obj2->wear_flags & ~ITEM_TAKE ) == 0 )
	    {
		send_to_char( "They are not comparable items.\n\r", ch );
		return;
	    }

	}
    }
	    
    msg		= NULL;
    value1	= 0;
    value2	= 0;

    if ( obj1 == obj2 )
    {
	msg = "You compare $p to itself.  It looks about the same.";
    }
    else if ( obj1->item_type != obj2->item_type )
    {
	msg = "You can't compare $p and $P.";
    }
    else
    {
	switch ( obj1->item_type )
	{
	default:
	    msg = "You can't compare $p and $P.";
	    break;

	case TYPE_ARMOR:
	    value1 = obj1->value[0];
	    value2 = obj2->value[0];
	    break;

	case TYPE_CLOTHING:
	    value1 = obj1->value[0];
	    value2 = obj2->value[0];
	    break;

	case TYPE_WEAPON:
	    value1 = obj1->value[1] + obj1->value[2];
	    value2 = obj2->value[1] + obj2->value[2];
	    break;
	}
    }

    if ( !msg )
    {
        if ( obj2->wear_loc != WEAR_NONE )
        {
                 if ( value1 == value2 )
                     msg = "$p and $P (equipped) look about the same.";
           else if ( value1  > value2 )
                     msg = "$p looks better than $P (equipped).";
            else
                     msg = "$p looks worse than $P (equipped).";
        }
        else
        {
             if ( value1 == value2 ) msg = "$p and $P look about the same.";
        else if ( value1  > value2 ) msg = "$p looks better than $P.";
        else                         msg = "$p looks worse than $P.";
        }

    }

    act( msg, ch, obj1, obj2, TO_CHAR );
    return;
}



void do_credits( CHAR_DATA *ch, char *argument )
{
    do_help( ch, "diku" );
    return;
}



void do_pwhere( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA       *victim;
    DESCRIPTOR_DATA *d;
    char             buf [ MAX_STRING_LENGTH ];
    char             arg [ MAX_INPUT_LENGTH  ];
    bool             found;

    if ( !check_blind( ch ) )
        return;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	send_to_char( "Players near you:\n\r", ch );
	found = FALSE;
	for ( d = descriptor_list; d; d = d->next )
	{
	    if ( d->connected == CON_PLAYING
		&& ( victim = d->character )
		&& !IS_NPC( victim )
		&& victim->in_room
		&& victim->in_room->area == ch->in_room->area
		&& can_see( ch, victim ) )
	    {
		found = TRUE;
		sprintf( buf, "%-28s %s\n\r",
			victim->name, victim->in_room->name );
		send_to_char( buf, ch );
	    }
	}
	if ( !found )
	    send_to_char( "None\n\r", ch );
    }
    else
    {
	found = FALSE;
	for ( victim = char_list; victim; victim = victim->next )
	{
	    if ( !victim->in_room
		|| IS_AFFECTED( victim, AFF_HIDE ) 
		|| IS_AFFECTED( victim, AFF_SNEAK ) )
	        continue;

	    if ( victim->in_room->area == ch->in_room->area
		&& can_see( ch, victim )
		&& is_name( arg, victim->name ) )
	    {
		found = TRUE;
		sprintf( buf, "%-28s %s\n\r",
			PERS( victim, ch ), victim->in_room->name );
		send_to_char( buf, ch );
		break;
	    }
	}
	if ( !found )
	    act( "You didn't find any $T.", ch, NULL, arg, TO_CHAR );
    }

    return;
}


void do_consider( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    char      *msg;
    char       arg [ MAX_INPUT_LENGTH ];
    int        diff;

    one_argument( argument, arg );

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

    if ( !( victim = get_char_room( ch, arg ) ) )
    {
	send_to_char( "They're not here.\n\r", ch );
	return;
    }

    // Veygoth - removed code that would not let you consider players.

    diff = victim->level - ch->level;

         if ( diff <= -10 ) msg = "You can kill $N&n naked and weaponless.";
    else if ( diff <=  -5 ) msg = "$N&n is no match for you.";
    else if ( diff <=  -2 ) msg = "$N&n looks like an easy kill.";
    else if ( diff <=   1 ) msg = "The perfect match!";
    else if ( diff <=   4 ) msg = "$N&n says 'Do you feel lucky, punk?'.";
    else if ( diff <=   9 ) msg = "$N&n laughs at you mercilessly.";
    else                    msg = "Death will thank you for your gift.";

    act( msg, ch, NULL, victim, TO_CHAR );

    /* Removed health comparison messages - Veygoth */

    return;
}

void do_glance( CHAR_DATA *ch, char *argument )
{
    CHAR_DATA *victim;
    char       msg[MAX_STRING_LENGTH];

    if ( argument[0] == '\0' )
    {
	send_to_char( "Glance at whom?\n\r", ch );
	return;
    }

    if ( !( victim = get_char_room( ch, argument ) ) )
    {
	send_to_char( "They're not here.\n\r", ch );
	return;
    }

    sprintf( msg, "You glance at $N&n.\n\r$N&n is %s.", condition_string( victim ) );

    act( msg, ch, NULL, victim, TO_CHAR );

    return;
}

void set_title( CHAR_DATA *ch, char *title )
{
    char buf [ MAX_STRING_LENGTH ];

    if ( IS_NPC( ch ) )
    {
	bug( "Set_title: NPC.", 0 );
	return;
    }

    buf[0] = '\0';

    sprintf( buf, " " );

    strcat( buf, title );

    strcat( buf, "&n" );

    free_string( ch->pcdata->title );
    ch->pcdata->title = str_dup( buf );
    return;
}

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

    if ( argument[0] == '\0' )
    {
	send_to_char( "Change your title to what?\n\r", ch );
	return;
    }

    if ( strlen( argument ) > 60 )
	argument[60] = '\0';

    smash_tilde( argument );
    set_title( ch, argument );
    send_to_char( "Ok.\n\r", ch );
}

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

    string_append( ch, &ch->description );
    return;
}

void do_report( CHAR_DATA *ch, char *argument )
{
    char buf [ MAX_INPUT_LENGTH ];

    sprintf( buf,
	    "You report: %d/%d hp %d/%d mana %d/%d mv.\n\r",
	    ch->hit,  ch->max_hit,
	    ch->mana, ch->max_mana,
	    ch->move, ch->max_move );

    send_to_char( buf, ch );

    sprintf( buf,
	    "$n&n reports: %d/%d hp %d/%d mana %d/%d mv.",
	    ch->hit,  ch->max_hit,
	    ch->mana, ch->max_mana,
	    ch->move, ch->max_move );

    act( buf, ch, NULL, NULL, TO_ROOM );

    return;
}

void do_practice( CHAR_DATA *ch, char *argument )
{
    send_to_char(
    "This MUD does not use practice.  Go use your skills instead!\n\r",
    ch );
    return;
}

/*
 * 'Wimpy' originally by Dionysos.
 */
void do_wimpy( CHAR_DATA *ch, char *argument )
{
    char buf [ MAX_STRING_LENGTH ];
    char arg [ MAX_INPUT_LENGTH  ];
    int  wimpy;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
	wimpy = ch->max_hit / 5;
    else
	wimpy = atoi( arg );

    if ( wimpy < 0 )
    {
	send_to_char( "Your courage exceeds your wisdom.\n\r", ch );
	return;
    }

    if ( wimpy > ch->max_hit )
    {
	send_to_char( "Such cowardice ill becomes you.\n\r", ch );
	return;
    }

    ch->wimpy	= wimpy;
    sprintf( buf, "Wimpy set to %d hit points.\n\r", wimpy );
    send_to_char( buf, ch );
    return;
}



void do_password( CHAR_DATA *ch, char *argument )
{
    extern const char echo_off_str [ ];

    if ( IS_NPC( ch ) )
	return;

    write_to_buffer( ch->desc, "Password: ", 0 );
    write_to_buffer( ch->desc, echo_off_str, 0 );
    ch->desc->connected = CON_PASSWD_GET_OLD;
    return;
}



void do_socials( CHAR_DATA *ch, char *argument )
{
    SOC_INDEX_DATA *social;
    char            buf  [ MAX_STRING_LENGTH * 2];
    char            buf1 [ MAX_STRING_LENGTH * 2 ];
    int             col;
    int             x;
    

    buf1[0] = '\0';
    col = 0;

    for ( x = 0; x < MAX_WORD_HASH; x++ )
    {
	for ( social = soc_index_hash[x]; social; social = social->next )
	{
	    if ( !social->name || social->name[0] == '\0' )
		continue;

	sprintf( buf, "%-12s", social->name );
	strcat( buf1, buf );
	if ( ++col % 6 == 0 )
	    strcat( buf1, "\n\r" );
	}
    }
 
    if ( col % 6 != 0 )
	strcat( buf1, "\n\r" );

    send_to_char( buf1, ch );
    return;
}



/*
 * Contributed by Alander.
 */
void do_commands( CHAR_DATA *ch, char *argument )
{
    char buf  [ MAX_STRING_LENGTH ];
    char buf1 [ MAX_STRING_LENGTH ];
    int  cmd;
    int  col;

    buf1[0] = '\0';
    col = 0;
    for ( cmd = 0; cmd_table[cmd].name[0] != '\0'; cmd++ )
    {
        if (   cmd_table[cmd].level <  LEVEL_HERO
	    && cmd_table[cmd].level <= get_trust( ch )
	    && cmd_table[cmd].show )
	{
		sprintf( buf, "%-16s", cmd_table[cmd].name );
		strcat( buf1, buf );
		if ( ++col % 5 == 0 )
		    strcat( buf1, "\n\r" );
	}
    }

    if ( col % 5 != 0 )
	strcat( buf1, "\n\r" );

    send_to_char( buf1, ch );
    return;
}



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

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
	if ( !IS_NPC( ch ) && IS_SET( ch->act, PLR_SILENCE ) )
	{
	    send_to_char( "You are silenced.\n\r", ch );
	    return;
	}

	send_to_char( "Channels:", ch );

	send_to_char( !IS_SET( ch->deaf, CHANNEL_SHOUT    )
		     ? " +SHOUT"
		     : " -shout",
		     ch );

	send_to_char( !IS_SET( ch->deaf, CHANNEL_YELL     )
		     ? " +YELL"
		     : " -yell",
		     ch );

	if ( is_clan( ch ) )
	{
	    send_to_char( !IS_SET( ch->deaf, CHANNEL_CLANTALK )
			 ? " +CLANTALK"
			 : " -clantalk",
			 ch );
	}


	if ( IS_HERO( ch ) )
	{
	    send_to_char( "\n\r", ch );
	    send_to_char( !IS_SET( ch->deaf, CHANNEL_IMMTALK )
			 ? " +IMMTALK"
			 : " -immtalk",
			 ch );
	}

	send_to_char( ".\n\r", ch );
    }
    else
    {
	int  bit;
	bool fClear;

	     if ( arg[0] == '+' ) fClear = TRUE;
	else if ( arg[0] == '-' ) fClear = FALSE;
	else
	{
	    send_to_char( "Channels -channel or +channel?\n\r", ch );
	    return;
	}

	     if ( !str_cmp( arg+1, "immtalk"  ) ) bit = CHANNEL_IMMTALK;
	else if ( !str_cmp( arg+1, "clantalk" ) ) bit = CHANNEL_CLANTALK;
	else if ( !str_cmp( arg+1, "shout"    ) ) bit = CHANNEL_SHOUT;
	else if ( !str_cmp( arg+1, "yell"     ) ) bit = CHANNEL_YELL;
	else
	{
	    send_to_char( "Set or clear which channel?\n\r", ch );
	    return;
	}

	if ( fClear )
	    REMOVE_BIT ( ch->deaf, bit );
	else
	    SET_BIT    ( ch->deaf, bit );

	send_to_char( "Ok.\n\r", ch );
    }

    return;
}



/*
 * Contributed by Grodyn.
 */
void do_config( CHAR_DATA *ch, char *argument )
{
    char arg [ MAX_INPUT_LENGTH ];

    if ( IS_NPC( ch ) )
	return;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
    {
        send_to_char( "[ Keyword  ] Option\n\r", ch );

	if ( IS_IMMORTAL( ch ) )
	send_to_char(  IS_SET( ch->act, PLR_EDIT_INFO  )
            ? "[+EDITINFO ] You see extra info on rooms.\n\r"
	    : "[-editinfo ] You don't see extra info on rooms.\n\r"
	    , ch );

	send_to_char(  IS_SET( ch->act, PLR_AUTOEXIT  )
            ? "[+AUTOEXIT ] You automatically see exits.\n\r"
	    : "[-autoexit ] You don't automatically see exits.\n\r"
	    , ch );

	send_to_char(  IS_SET( ch->act, PLR_BLANK     )
	    ? "[+BLANK    ] You have a blank line before your prompt.\n\r"
	    : "[-blank    ] You have no blank line before your prompt.\n\r"
	    , ch );

	send_to_char(  IS_SET( ch->act, PLR_BRIEF     )
	    ? "[+BRIEF    ] You see brief descriptions.\n\r"
	    : "[-brief    ] You see long descriptions.\n\r"
	    , ch );

        send_to_char(  IS_SET( ch->act, PLR_CAST_TICK )
            ? "[+CASTTICK ] You see your casting ticks.\n\r"
            : "[-CASTTICK ] For spam's sake, no casting ticks!\n\r"
            , ch );
         
	send_to_char(  IS_SET( ch->act, PLR_COMBINE   )
	    ? "[+COMBINE  ] You see object lists in combined format.\n\r"
	    : "[-combine  ] You see object lists in single format.\n\r"
	    , ch );

	send_to_char(  IS_SET( ch->act, PLR_COLOUR    )
	    ? "[+COLOUR   ] You see ANSI colours.\n\r"
	    : "[-colour   ] You don't see ANSI colours.\n\r"
	    , ch );

	send_to_char(  IS_SET( ch->act, PLR_PAGER     )
	    ? "[+PAGER    ] You have a pager.\n\r"
	    : "[-pager    ] You don't have a pager.\n\r"
	    , ch );

	send_to_char(  IS_SET( ch->act, PLR_PROMPT    )
	    ? "[+PROMPT   ] You have a prompt.\n\r"
	    : "[-prompt   ] You don't have a prompt.\n\r"
	    , ch );

        send_to_char(  IS_SET( ch->act, PLR_SHOUT     )
            ? "[+SHOUT    ] You can hear shouts.\n\r"
            : "[-shout    ] You cover your ears when someone is yelling.\n\r"
            , ch );

	send_to_char(  IS_SET( ch->act, PLR_TELNET_GA )
	    ? "[+TELNETGA ] You receive a telnet GA sequence.\n\r"
	    : "[-telnetga ] You don't receive a telnet GA sequence.\n\r"
	    , ch );

	send_to_char(  IS_SET( ch->act, PLR_SILENCE   )
	    ? "[+SILENCE  ] You are silenced.\n\r"
	    : ""
	    , ch );

	send_to_char( !IS_SET( ch->act, PLR_NO_EMOTE  )
	    ? ""
	    : "[-emote    ] You can't emote.\n\r"
	    , ch );

	send_to_char( !IS_SET( ch->act, PLR_NO_TELL   )
	    ? ""
	    : "[-tell     ] You can't use 'tell'.\n\r"
	    , ch );
    }
    else
    {
	char buf [ MAX_STRING_LENGTH ];
	int  bit;
	bool fSet;

	     if ( arg[0] == '+' ) fSet = TRUE;
	else if ( arg[0] == '-' ) fSet = FALSE;
	else
	{
	    send_to_char( "Config -option or +option?\n\r", ch );
	    return;
	}

             if ( !str_cmp( arg+1, "editinfo" )
		 && IS_IMMORTAL( ch ) ) bit = PLR_EDIT_INFO;
        else if ( !str_cmp( arg+1, "autoexit" ) ) bit = PLR_AUTOEXIT;
	else if ( !str_cmp( arg+1, "blank"    ) ) bit = PLR_BLANK;
	else if ( !str_cmp( arg+1, "brief"    ) ) bit = PLR_BRIEF;
        else if ( !str_cmp( arg+1, "casttick" ) ) bit = PLR_CAST_TICK;
	else if ( !str_cmp( arg+1, "combine"  ) ) bit = PLR_COMBINE;
	else if ( !str_cmp( arg+1, "colour"   ) ) bit = PLR_COLOUR;
        else if ( !str_cmp( arg+1, "pager"    ) ) bit = PLR_PAGER;
        else if ( !str_cmp( arg+1, "shout"    ) ) bit = PLR_SHOUT;
        else if ( !str_cmp( arg+1, "prompt"   ) ) bit = PLR_PROMPT;
	else if ( !str_cmp( arg+1, "telnetga" ) ) bit = PLR_TELNET_GA;
	else
	{
	    send_to_char( "Config which option?\n\r", ch );
	    return;
	}

	if ( fSet )
	{
	    SET_BIT    ( ch->act, bit );
	    sprintf( buf, "%s is now ON.\n\r", arg+1 );
	    buf[0] = UPPER( buf[0] );
	    send_to_char( buf, ch );
	}
	else
	{
	    REMOVE_BIT ( ch->act, bit );
	    sprintf( buf, "%s is now OFF.\n\r", arg+1 );
	    buf[0] = UPPER( buf[0] );
	    send_to_char( buf, ch );
	}

    }

    return;
}

void do_news ( CHAR_DATA *ch, char *argument )
{

    do_help ( ch, "news" );
    return;

}

void do_wizlist ( CHAR_DATA *ch, char *argument )
{

    do_help ( ch, "wizlist" );
    return;

}

// reformatted - Veygoth
void do_slist ( CHAR_DATA *ch, char *argument )
{
    char buf  [ MAX_STRING_LENGTH ];
    char buf1 [ MAX_STRING_LENGTH ];
    int  sn;
    int  level;
    bool pSpell;

    if ( IS_NPC( ch ) )
    {  
       send_to_char ( "You do not need any stinking skills!\n\r", ch );
       return;
    }

    buf1[0] = '\0';

    strcat ( buf1, "&+yALL Abilities available for your class.&n\n\r" );
    strcat ( buf1, "&+bLv      Abilities&n\n\r" );

    for ( level = 1; level <= LEVEL_HERO; level++ )
    {

      pSpell = TRUE;

      for ( sn = 0; sn < MAX_SKILL; sn++ )
      {
	if ( !skills_table[sn].name )
	  break;
	if ( skills_table[sn].skill_level[ch->class] != level )
	  continue;

	if ( pSpell )
	{
	  sprintf ( buf, "&+Y%2d&+y:&n", level );
	  strcat ( buf1, buf );
	  pSpell = FALSE;
	}
        else
          strcat( buf1, "   " );

	/* format fix by Koala */ 
        strcat ( buf1, "     " );

	sprintf ( buf, "&+c%-18s  &+Y%d&n", skills_table[sn].name,
           ch->pcdata->skl_lrn[sn] );
	strcat ( buf1, buf );

        strcat ( buf1, "\n\r" );

      }

    }

    send_to_char( buf1, ch );
    return;

}

void do_spells ( CHAR_DATA *ch, char *argument )
{
    char buf  [ MAX_STRING_LENGTH * 3 ];
    char buf1 [ MAX_STRING_LENGTH * 3 ];
    int  sn;
    int  circle;
    bool pSpell;

    if ( IS_NPC( ch ) )
    {  
       send_to_char ( "You do not need any stinking spells!\n\r", ch );
       return;
    }

    buf1[0] = '\0';

    strcat ( buf1, "&+yALL spells available for your class.&n\n\r" );
    strcat ( buf1, "&+bLv      Spell&n\n\r" );

    // Don't show 12th circle spells...
    for ( circle = 1; circle < MAX_CIRCLE; circle++ )
    {

      pSpell = TRUE;

      for ( sn = 0; sn < MAX_SPELL; sn++ )
      {
	if ( !spells_table[sn].name )
	  break;
	if ( spells_table[sn].spell_circle[ch->class] != circle )
	  continue;

	if ( pSpell )
	{
	  sprintf ( buf, "&+Y%2d&+y:&n", circle );
	  strcat ( buf1, buf );
	  pSpell = FALSE;
	}
        else
          strcat( buf1, "   " );

	/* format fix by Koala */ 
        strcat ( buf1, "     " );

	sprintf ( buf, "&+c%-18s  &+Y%d&n", spells_table[sn].name,
           ch->pcdata->spl_lrn[sn] );
	strcat ( buf1, buf );

        strcat ( buf1, "\n\r" );

      }

    }

    send_to_char( buf1, ch );
    return;

}

/* bypassing the config command - Kahn */
void do_autoexit ( CHAR_DATA *ch, char *argument )
{
    char buf[ MAX_STRING_LENGTH ];

    ( IS_SET ( ch->act, PLR_AUTOEXIT )
     ? sprintf( buf, "-autoexit" )
     : sprintf( buf, "+autoexit" ) );

    do_config( ch, buf );

    return;

}


void do_blank ( CHAR_DATA *ch, char *argument )
{
    char buf[ MAX_STRING_LENGTH ];

    ( IS_SET ( ch->act, PLR_BLANK )
     ? sprintf( buf, "-blank" )
     : sprintf( buf, "+blank" ) );

    do_config( ch, buf );

    return;

}

void do_brief ( CHAR_DATA *ch, char *argument )
{
    char buf[ MAX_STRING_LENGTH ];

    ( IS_SET ( ch->act, PLR_BRIEF )
     ? sprintf( buf, "-brief" )
     : sprintf( buf, "+brief" ) ) ; 

    do_config( ch, buf );

    return;

}

void do_combine ( CHAR_DATA *ch, char *argument )
{
    char buf[ MAX_STRING_LENGTH ];

    ( IS_SET ( ch->act, PLR_COMBINE )
     ? sprintf( buf, "-combine" )
     : sprintf( buf, "+combine" ) );

    do_config( ch, buf );

    return;

}
 
void do_pagelen ( CHAR_DATA *ch, char *argument )
{
    char buf [ MAX_STRING_LENGTH ];
    char arg [ MAX_INPUT_LENGTH  ];
    int  lines;

    if ( IS_NPC( ch ) )
        return;

    one_argument( argument, arg );

    if ( arg[0] == '\0' )
	lines = 20;
    else
	lines = atoi( arg );

    if ( lines < 19 )
    {
	send_to_char( "Less than 19 lines of paged text is not allowed", ch );
	return;
    }

    if ( lines > 60 )
    {
	send_to_char(
		"I don't know of a screen that is larger than 60 lines!\n\r",
		     ch );
	lines = 60;
    }

    ch->pcdata->pagelen = lines;
    sprintf( buf, "Page pause set to %d lines.\n\r", lines );
    send_to_char( buf, ch );
    return;
}

/* Do_prompt from Morgenes from Aldara Mud */
void do_prompt( CHAR_DATA *ch, char *argument )
{
   char buf [ MAX_STRING_LENGTH ];

   buf[0] = '\0';

   /* Unswitched NPC's get kicked out */
   if ( !ch->desc )
       return;

   /* Will always have a pc ch after this */
   ch = ( ch->desc->original ? ch->desc->original : ch->desc->character );

   if ( argument[0] == '\0' )
   {
       ( IS_SET ( ch->act, PLR_PROMPT )
	? sprintf( buf, "-prompt" )
	: sprintf( buf, "+prompt" ) );

       do_config( ch, buf );

       return;
   }

   if( !strcmp( argument, "all" ) )
      strcat( buf, "&+g<%hhp %mm %vmv>\n\r<&n%T %E&+g>&n ");
   else if( !strcmp( argument, "meter" ) )
      strcat( buf, "&+g<%hhp %mm %vmv>\n\r<&n%t %e&+g>&n ");
   else
   {
      if ( strlen( argument ) > 50 )
	  argument[50] = '\0';
      smash_tilde( argument );
      strcat( buf, argument );
   }

   free_string( ch->pcdata->prompt );
   ch->pcdata->prompt = str_dup( buf );
   send_to_char( "Ok.\n\r", ch );
   return;
} 

void do_auto( CHAR_DATA *ch, char *argument )
{

    do_config( ch, "" );
    return;

}

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

    if ( IS_SET( ch->act, PLR_AFK ) )
    {
	REMOVE_BIT( ch->act, PLR_AFK );
	send_to_char( "You are back at your keyboard.\n\r", ch        );
	act( "$n&n has returned to $s keyboard.", ch, NULL, ch, TO_ROOM );
    }
    else
    {
	SET_BIT( ch->act, PLR_AFK );
	send_to_char( "You are now away from keyboard.\n\r", ch       );
	act( "$n&n has left $s keyboard.", ch, NULL, ch, TO_ROOM        );
    }
    
    return;
}

void do_trophy( CHAR_DATA *ch, char *argument )
{
    int count;
    char buf[MAX_STRING_LENGTH];

    if( IS_NPC( ch ))
       return;

    send_to_char( "Trophy data:\n\r", ch );
    for( count = 0; count < MAX_LEVEL; count++ )
    {
        if( ch->pcdata->trophy[count].vnum == 0 )
            continue;
        if( ch->pcdata->trophy[count].number == 0 )
            continue;
        sprintf( buf, "   &+b(&+y%4.2f&+b)&n %s&n\n\r",
            (float)(ch->pcdata->trophy[count].number / 100),
            (get_mob_index( ch->pcdata->trophy[count].vnum ))->short_descr );
        send_to_char( buf, ch );
    }
    send_to_char( "\n\r", ch );
    return;
}

// Returns the text string of someone's sex - Veygoth
char *get_sex( CHAR_DATA *ch )
{
   switch( ch->sex )
   {
      case 0:
         return "neuter";
         break;
      case 1:
         return "male";
         break;
      case 2:
         return "female";
         break;
      default:
         return "mutant";
         break;
   }
}

// Returns how far a character is from their next level as a text string
// -- Veygoth
char *get_exp_string( CHAR_DATA *ch )
{
    int exp;

    exp = ch->exp - (ch->level * EXP_PER_LEVEL);

    if( exp < 200 )
      return "You have just begun the trek to your next level!";
    if( exp < 400 )
      return "You are still a very long way from your next level.";
    if( exp < 600 )
      return "Have gained some progress but still have a long way to your next level.";
    if( exp < 800 )
      return "You have gained some progress and are nearing the halfway point.";
    if( exp < 950 )
      return "You are close to the halfway point in the journey to your next level.";
    if( exp < 1050 )
      return "You are at the halfway point.";
    if( exp < 1200 )
      return "You have just passed the halfway point.";
    if( exp < 1400 )
      return "You are well on your way to the next level.";
    if( exp < 1600 )
      return "You are three quarters the way to your next level.";
    if( exp < 1800 )
      return "You are almost ready to attain your next level.";
    if( exp < 2000 )
      return "You should level anytime now!";

     return NULL;
}

void do_fraglist( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];
    char buf2[MAX_STRING_LENGTH];
    int count;

    sprintf( buf, "&+YTotal Frags&n\n\r" );

    sprintf( buf2, "Total Good Side Frags: %5d     Total Evil Side Frags: %5d\n\t",
             fraglist.total_side_frags[RACEWAR_GOOD],
             fraglist.total_side_frags[RACEWAR_EVIL] );
    strcat( buf, buf2 );
    strcat( buf, "\n\rRace Frags:\n\r" );

    for( count = 0; count < MAX_PC_RACE; count++ )
    {
     sprintf( buf2, "    %-10s: %5d",
              race_table[count].name,
              fraglist.total_race_frags[count] );
     strcat( buf, buf2 );
     if( count % 3 == 2 )
              strcat( buf, "\n\r" );
    }

    strcat( buf, "\n\rClass Frags:\n\r" );

    // Starting at one because we don't care about class_none frags
    for( count = 1; count < MAX_CLASS; count++ )
    {
     sprintf( buf2, "    %-18s: %5d",
              class_table[count]->who_name,
              fraglist.total_class_frags[count] );
     strcat( buf, buf2 );
     if( count % 3 == 0 )
              strcat( buf, "\n\r" );
    }

    strcat( buf, "\n\r" );
    send_to_char( buf, ch );
}

void do_innate( CHAR_DATA *ch, char *argument )
{
    char buf[MAX_STRING_LENGTH];

    sprintf( buf, "Innate abilities available to your race and class:\n\r" );

    if( IS_SET( race_table[ch->race].race_abilities, RACE_BODYSLAM ))
      strcat( buf, "  bodyslam\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_CHARGE ))
      strcat( buf, "  charge\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_FLY ))
      strcat( buf, "  fly\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_PASSDOOR ))
      strcat( buf, "  pass door\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_SWIM ))
      strcat( buf, "  swim\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_WATERBREATH ))
      strcat( buf, "  water breathing\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_INFRAVISION ))
      strcat( buf, "  infravision\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_ULTRAVISION ))
      strcat( buf, "  ultravision\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_DETECT_ALIGN ))
      strcat( buf, "  detect align\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_DETECT_INVIS ))
      strcat( buf, "  detect invis\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_DETECT_HIDDEN ))
      strcat( buf, "  detect hidden\n\r" );
    if( IS_SET( race_table[ch->race].race_abilities, RACE_MUTE ))
      strcat( buf, "  mute\n\r" );

    send_to_char( buf, ch );
    
    return;
}