SmaugWizard/Backup/
SmaugWizard/Backup/L/
SmaugWizard/Boards/
SmaugWizard/Building/
SmaugWizard/Corpses/
SmaugWizard/Councils/
SmaugWizard/Deity/
SmaugWizard/Gods/
SmaugWizard/MudProgs/
SmaugWizard/Player/L/
SmaugWizard/Src/
SmaugWizard/Src/res/
/****************************************************************************
 * [S]imulated [M]edieval [A]dventure multi[U]ser [G]ame      |				*
 * -----------------------------------------------------------|   \\._.//	*
 * SmaugWiz (C) 1998 by Russ Pillsbury (Windows NT version)   |   (0...0)	*
 * -----------------------------------------------------------|    ).:.(	*
 * SMAUG (C) 1994, 1995, 1996 by Derek Snider                 |    {o o}	*
 * -----------------------------------------------------------|   / ' ' \	*
 * SMAUG code team: Thoric, Altrag, Blodkai, Narn, Haus,      |~'~.VxvxV.~'~*
 * Scryn, Swordbearer, Rennard, Tricops, and Gorog.           |				*
 * ------------------------------------------------------------------------ *
 * Merc 2.1 Diku Mud improvments copyright (C) 1992, 1993 by Michael        *
 * Chastain, Michael Quan, and Mitchell Tse.                                *
 * Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,          *
 * Michael Seifert, Hans Henrik Staerfeldt, Tom Madsen, and Katja Nyboe.    *
 ****************************************************************************/

#include	"stdafx.h"
#include	<errno.h>

#include	"smaug.h"
#include	"SysData.h"
#include	"Language.h"
#include	"skill.h"
#include	"social.h"
#include	"commands.h"
#include	"mobiles.h"
#include	"objects.h"
#include	"rooms.h"
#include	"races.h"
#include	"deity.h"
#include	"area.h"
#include	"auction.h"
#include	"class.h"
#include	"SmaugWizDoc.h"
#include	"SmaugFiles.h"
#include	"descriptor.h"
#include	"character.h"
#include	"Exits.h"

#define RESTORE_INTERVAL 21600

// Local functions.
CRoomIndexData	*find_location (CCharacter *ch, char *arg);
void	save_banlist ();
void	close_area (CAreaData *pArea);
void	PrintConflict (CCharacter* ch, CCharacter* victim, CCharacter* mob);
int		get_color (char *argument);


// This version of wizhelp lists the commands sorted by level
void do_wizhelp (CCharacter *ch, char *argument)
{
	CCmdType	*cmd;
	int			hash;
	int			lvl;  

	int		col = 0;
	set_pager_color (AT_PLAIN, ch);

	for (lvl = LEVEL_AVATAR; lvl <= ch->GetTrustLevel (); ++lvl) {
		set_pager_color( AT_WHITE, ch );
		send_to_pager ("\n\r\n\r", ch);
		col = 1;
		pager_printf (ch, "[LEVEL %-2d]  ", lvl);
		set_pager_color( AT_GREEN, ch );
		for (hash = 0; hash < MAX_COMMANDS; ++hash)
			for (cmd = CommandTable.GetCommand (hash); cmd; cmd = cmd->GetNext ())
				if ((cmd->level == lvl)
				  && cmd->level <= ch->GetTrustLevel ()) {
					pager_printf (ch, "%-12s", cmd->GetName ());
					if (++col % 6 == 0)
						send_to_pager ("\n\r", ch);
				}
	}
	if (col % 6 != 0)
	send_to_pager ("\n\r", ch);
	set_pager_color( AT_PLAIN, ch );
	return;
}

#ifdef XXXX
// This version of wizhelp just lists all the commands in alpha order
void do_wizhelp (CCharacter *ch, char *argument)
{
	CCmdType	*cmd;

	int col = 0;
	set_pager_color (AT_PLAIN, ch);

	for (int hash = 0; hash < MAX_COMMANDS; ++hash)
		for (cmd = CommandTable.GetCommand (hash); cmd; cmd = cmd->GetNext ())
			if (cmd->level >= LEVEL_HERO
			  && cmd->level <= ch->GetTrustLevel ()) {
				pager_printf (ch, "%-12s", cmd->GetName ());
				if (++col % 6 == 0)
					send_to_pager ("\n\r", ch);
			}

	if (col % 6 != 0)
		send_to_pager ("\n\r", ch);
}
#endif


void do_restrict (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	char		buf [MAX_STRING_LENGTH];
	short		level;
	CCmdType	*cmd;
	BOOL		found;

	found = FALSE;

	argument = one_argument (argument, arg);
	if (arg[0] == '\0') {
		ch->SendText ("Restrict which command?\n\r");
		return;
	}

	argument = one_argument  (argument, arg2);
	if (arg2[0] == '\0')
		level = ch->GetTrustLevel ();
	else level = atoi (arg2);

	level = UMAX (UMIN (ch->GetTrustLevel (), level), 0);

	for (cmd = CommandTable.GetCommand (arg); cmd; cmd = cmd->GetNext ()) {
		if (!str_prefix (arg, cmd->GetName ())
		  && cmd->level <= ch->GetTrustLevel ()) {
			found = TRUE;
			break;
		}
	}

	if (found) {
		if (!str_prefix (arg2, "show")) {
    		sprintf (buf, "%s show", cmd->GetName ());
    		do_cedit (ch, buf);
//    		ch->SendTextf ("%s is at level %d.\n\r", cmd->name, cmd->level);
			return;
		}
		cmd->level = level;
		ch->SendTextf ("You restrict %s to level %d\n\r",
			cmd->GetName (), level);
		sprintf (buf, "%s restricting %s to level %d",
			ch->GetName (), cmd->GetName (), level);
		gpDoc->LogString (buf);
	}
	else ch->SendText ("You may not restrict that command.\n\r");
}


// Check if the name prefix uniquely identifies a char descriptor
CCharacter *get_waiting_desc (CCharacter *ch, char *name) 
{ 
	CCharacter		*ret_char; 
	static unsigned int number_of_hits; 

	number_of_hits = 0; 
	POSITION	pos = DList.GetHeadPosition ();
	while (pos) {
		CDescriptor	&Ds = *DList.GetNext (pos);
		if (Ds.IsDisconnecting ())
			continue;

		if (Ds.m_pCharacter
		  && (!str_prefix (name, Ds.m_pCharacter->GetName ()))
		  && Ds.m_pCharacter->IsWaitingForAuth ()) { 
			if (++number_of_hits > 1) { 
				ch->SendTextf ("%s does not uniquely identify a char.\n\r",
					name); 
				return NULL; 
			} 
			ret_char = Ds.m_pCharacter;       // return current char on exit
		} 
	} 
	if (number_of_hits == 1) 
		return ret_char; 
	else { 
		ch->SendText ("No one like that waiting for authorization.\n\r"); 
		return NULL; 
	} 
} 


void do_authorize (CCharacter *ch, char *argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	char		buf [MAX_STRING_LENGTH];
	CCharacter	*victim;

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

	if (arg1[0] == '\0') {
		ch->SendText ("Usage:  authorize <player> <yes|name|no/deny>\n\r");
		ch->SendText ("Pending authorizations:\n\r");
		ch->SendText (" Chosen Character Name\n\r");
		ch->SendText ("---------------------------------------------\n\r");

		POSITION	pos = DList.GetHeadPosition ();
		while (pos) {
			CDescriptor	&Ds = *DList.GetNext (pos);
			if (Ds.IsDisconnecting ())
				continue;

			if ((victim = Ds.m_pCharacter) != NULL
			  && victim->IsWaitingForAuth ()) {
				ch->SendTextf (" %s%s new %s %s...\n\r",
					victim->GetName (), victim->GetDesc ()->m_pHost,
					RaceTable.GetName (victim->GetRace ()),
					ClassTable.GetName (victim->GetClass ()));
			}
		}
		return;
	}

	victim = get_waiting_desc (ch, arg1);
	if (victim == NULL)
		return;

	if (arg2[0]=='\0' || !str_cmp (arg2,"accept") || !str_cmp (arg2,"yes")) {
		victim->GetPcData ()->auth_state = 3;
		if (victim->GetPcData ()->authed_by)
			STRFREE (victim->GetPcData ()->authed_by);
		victim->GetPcData ()->authed_by = QUICKLINK (ch->GetName ());
		sprintf (buf, "%s authorized %s", ch->GetName (),
			victim->GetName ());
		to_channel (buf, CHANNEL_MONITOR, "Monitor", ch->GetLevel ());
		ch->SendTextf ("You have authorized %s.\n\r", victim->GetName ());

		// Below sends a message to player when name is accepted - Brittany

		victim->SendTextf (
			"The MUD Administrators have accepted the name %s.\n\r"
			"You will be authorized to enter the %s at the end of "
			"this area.\n\r", victim->GetName (), SysData.GetShortTitle ());
		return;
	}
	else if (!str_cmp (arg2, "no") || !str_cmp (arg2, "deny")) {
		victim->SendText ("You have been denied access.\n\r");
		sprintf (buf, "%s denied authorization to %s", ch->GetName (),
			victim->GetName ());
		to_channel (buf, CHANNEL_MONITOR, "Monitor", ch->GetLevel ());
		ch->SendTextf ("You have denied %s.\n\r", victim->GetName ());
		do_quit (victim, "");
	}

	else if (!str_cmp (arg2, "name") || !str_cmp (arg2, "n")) {
		victim->GetPcData ()->auth_state = 2;
		sprintf (buf, "%s has denied %s's name", ch->GetName (),
			victim->GetName ());
		to_channel (buf, CHANNEL_MONITOR, "Monitor", ch->GetLevel ());
		victim->SendTextf (
			"The MUD Administrators have found the name %s "
			"to be unacceptable.\n\r"
			"You may choose a new name when you reach "			/* B */
			"the end of this area.\n\r"							/* B */
			"The name you choose must be medieval and original.\n\r"
			"No titles, descriptive words, or names close to any existing "
			"Immortal's name.\n\r", victim->GetName ());
		ch->SendTextf ("You requested %s change names.\n\r",
			victim->GetName ());
		return;
	}

	else ch->SendText ("Invalid argument.\n\r");
}


void do_AutoAuthorize (CCharacter *ch, char *argument)
{
	char		buf [MAX_STRING_LENGTH];
	pc_data		&Pc = *ch->GetPcData ();

	Pc.auth_state = 3;
	if (Pc.authed_by)
		STRFREE (Pc.authed_by);
	Pc.authed_by = QUICKLINK ("Auto Authorized");
	sprintf (buf, "Auto Authorized %s", ch->GetName ());
	to_channel (buf, CHANNEL_MONITOR, "Monitor", LEVEL_IMMORTAL);

	ch->SendTextf (
		"The MUD Administrators have accepted the name %s.\n\r"
		"Pull the rope again to enter the %s.\n\r",
		ch->GetName (), SysData.GetShortTitle ());
}


void do_bamfin (CCharacter *ch, char *argument)
{
	if (! ch->IsNpc ()) {
		smash_tilde (argument);
		delete ch->GetPcData ()->GetBamfin ();
		ch->GetPcData ()->SetBamfin (str_dup (argument));
		ch->SendText ("Ok.\n\r");
	}
}


void do_bamfout (CCharacter *ch, char *argument)
{
	if (! ch->IsNpc ()) {
		smash_tilde (argument);
		delete ch->GetPcData ()->GetBamfout ();
		ch->GetPcData ()->SetBamfout (str_dup (argument));
		ch->SendText ("Ok.\n\r");
	}
}


void do_rank (CCharacter *ch, char *argument)
{
	if (ch->IsNpc ())
		return;

	if (! argument || argument [0] == '\0') {
		ch->SendText ("Usage: rank <string>.\n\r");
		ch->SendText ("   or: rank none.\n\r");
		return;
	}

	smash_tilde (argument);
	delete ch->GetPcData ()->GetRank ();

	if (! str_cmp (argument, "none"))
		ch->GetPcData ()->SetRank (str_dup (""));
	else
		ch->GetPcData ()->SetRank (str_dup (argument));

	ch->SendText ("Ok.\n\r");
}


void do_retire (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);
	if (arg [0] == '\0') {
		ch->SendText ("Retire whom?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetTrustLevel () >= ch->GetTrustLevel ()) {
		ch->SendText ("You failed.\n\r");
		return;
	}

	if (victim->GetLevel () < LEVEL_SAVIOR) {
		ch->SendText ("The minimum level for retirement is savior.\n\r");
		return;
	}

	if (victim->IsRetired ()) {
		victim->ClrRetired ();
		ch->SendTextf ("%s returns from retirement.\n\r", victim->GetName ());
		victim->SendTextf ("%s brings you back from retirement.\n\r",
			ch->GetName ());
	} else { 
		victim->SetRetired ();
		ch->SendTextf ("%s is now a retired immortal.\n\r", victim->GetName ());
		victim->SendTextf (
			"Courtesy of %s, you are now a retired immortal.\n\r",
			ch->GetName ());
	}
}


void do_deny (CCharacter *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    CCharacter *victim;

    one_argument (argument, arg);
    if (arg[0] == '\0')
    {
	ch->SendText ("Deny whom?\n\r");
	return;
    }

    if ((victim = get_char_world (ch, arg)) == NULL)
    {
	ch->SendText ("They aren't here.\n\r");
	return;
    }

    if (victim->IsNpc ())
    {
	ch->SendText ("Not on NPC's.\n\r");
	return;
    }

    if (victim->GetTrustLevel () >= ch->GetTrustLevel ())
    {
	ch->SendText ("You failed.\n\r");
	return;
    }

    victim->SetActBit (PLR_DENY);
    victim->SendText ("You are denied access!\n\r");
    ch->SendText ("OK.\n\r");
    do_quit (victim, "");

    return;
}



void do_disconnect (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);
	if (arg [0] == '\0') {
		ch->SendText ("Disconnect whom?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->GetDesc () == NULL) {
		act (AT_PLAIN, "$N doesn't have a descriptor.",
			ch, NULL, victim, TO_CHAR);
		return;
	}

	if (ch->GetTrustLevel () <= victim->GetTrustLevel ()) {
		ch->SendText ("They might not like that...\n\r");
		return;
	}

	POSITION	pos = DList.GetHeadPosition ();
	while (pos) {
		CDescriptor	*d = DList.GetNext (pos);
		if (d == victim->GetDesc ()) {
			if (! d->IsDisconnecting ())
				RemoveCharacter (*d);
			ch->SendText ("Ok.\n\r");
			return;
		}
	}

	bug ("Do_disconnect: *** desc not found ***.");
	ch->SendText ("Descriptor not found!\n\r");
}


/*
 * Force a level one player to quit.             Gorog
 */
void do_fquit (CCharacter *ch, char *argument) 
{ 
  CCharacter *victim; 
  char arg1[MAX_INPUT_LENGTH]; 
  argument = one_argument (argument, arg1); 
 
  if (arg1[0] == '\0') 
     { 
     ch->SendText ("Force whom to quit?\n\r"); 
     return; 
     } 
 
  if (! (victim = get_char_world (ch, arg1)))
     { 
     ch->SendText ("They aren't here.\n\r"); 
     return; 
     } 
 
  if (victim->GetLevel () != 1)  
     { 
     ch->SendText ("They are not level one!\n\r"); 
     return; 
     } 
 
  victim->SendText ("The MUD administrators force you to quit\n\r");
  do_quit  (victim, "");
  ch->SendText ("Ok.\n\r"); 
  return; 
} 


void do_forceclose (CCharacter *ch, char *argument)
{
	char	arg [MAX_INPUT_LENGTH];
	int		desc;

	one_argument (argument, arg);
	if (arg [0] == '\0') {
		ch->SendText ("Usage: forceclose <descriptor#>\n\r");
		return;
	}
	desc = atoi (arg);

	POSITION	pos = DList.GetHeadPosition ();
	while (pos) {
		CDescriptor	*d = DList.GetNext (pos);
		if (d->m_DescNo == desc) {
			if (! d->IsDisconnecting ()) {
				if (d->m_pCharacter && d->m_pCharacter->GetTrustLevel ()
				  >= ch->GetTrustLevel ()) {
					ch->SendText ("They might not like that...\n\r");
					return;
				}
				RemoveCharacter (*d);
			}
			ch->SendText ("Ok.\n\r");
			return;
		}
	}

	ch->SendText ("Not found!\n\r");
}



void do_pardon (CCharacter *ch, char *argument)
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    CCharacter *victim;

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

    if (arg1[0] == '\0' || arg2[0] == '\0')
    {
	ch->SendText ("Syntax: pardon <character> <killer|thief|attacker>.\n\r");
	return;
    }

    if ((victim = get_char_world (ch, arg1)) == NULL)
    {
	ch->SendText ("They aren't here.\n\r");
	return;
    }

    if (victim->IsNpc ())
    {
	ch->SendText ("Not on NPC's.\n\r");
	return;
    }

    if (!str_cmp (arg2, "attacker"))
    {
	if (victim->IsAttacker ())
	{
	    victim->ClrAttacker ();
	    ch->SendText ("Attacker flag removed.\n\r");
	    victim->SendText ("You are no longer an ATTACKER.\n\r");
	}
	return;
    }

    if (!str_cmp (arg2, "killer"))
    {
	if (victim->IsKiller ())
	{
	    victim->ClrKiller ();
	    ch->SendText ("Killer flag removed.\n\r");
	    victim->SendText ("You are no longer a KILLER.\n\r");
	}
	return;
    }

    if (!str_cmp (arg2, "thief"))
    {
	if (victim->IsThief ())
	{
	    victim->ClrThief ();
	    ch->SendText ("Thief flag removed.\n\r");
	    victim->SendText ("You are no longer a THIEF.\n\r");
	}
	return;
    }

    ch->SendText ("Syntax: pardon <character> <killer|thief>.\n\r");
    return;
}


void echo_to_all (short AT_COLOR, const char *argument, short tar)
{
	if (!argument || argument[0] == '\0')
		return;

	POSITION	pos = DList.GetHeadPosition ();
	while (pos) {
		CDescriptor	&Ds = *DList.GetNext (pos);
		if (Ds.IsDisconnecting ())
			continue;
		// Added showing echoes to players who are editing, so they won't
		// miss out on important info like upcoming reboots. --Narn
		if (Ds.m_Connected == CON_PLAYING || Ds.m_Connected == CON_EDITING) {
			// This one is kinda useless except for switched..
			if (tar == ECHOTAR_PC && Ds.m_pCharacter->IsNpc ())
				continue;
			else if (tar == ECHOTAR_IMM && Ds.m_pCharacter->IsMortal ())
				continue;
			set_char_color (AT_COLOR, Ds.m_pCharacter);
			Ds.m_pCharacter->SendText (argument);
			Ds.m_pCharacter->SendText ("\n\r");
		}
	}
}


void do_echo (CCharacter *ch, char *argument)
{
	char	arg [MAX_INPUT_LENGTH];
	short	color;
	int		target;
	char	*parg;

	if (ch->IsAction (PLR_NO_EMOTE)) {
		ch->SendText ("You are noemoted and can not echo.\n\r");
		return;
	}

	if (argument [0] == '\0') {
		ch->SendText ("Echo what?\n\r");
		return;
	}

	if ((color = get_color (argument)))
		argument = one_argument (argument, arg);

	parg = argument;
	argument = one_argument (argument, arg);

	if (! str_cmp (arg, "PC") || ! str_cmp (arg, "player"))
		target = ECHOTAR_PC;
	else if (! str_cmp (arg, "imm"))
		target = ECHOTAR_IMM;
	else {
		target = ECHOTAR_ALL;
		argument = parg;
	}

	if (! color && (color = get_color (argument)))
		argument = one_argument (argument, arg);

	if (! color)
		color = AT_IMMORT;

	one_argument (argument, arg);

	if (! str_cmp (arg, SysData.GetSupremeEntity ())
	  || ! str_cmp (arg, "Rustry")
	  || ! str_cmp (arg, "Circe")
	  || ! str_cmp (arg, "Haus")
	  || ! str_cmp (arg, "Narn")
	  || ! str_cmp (arg, "Scryn")
	  || ! str_cmp (arg, "Damian")
	  || ! str_cmp (arg, "Blodkai"))
	{
		ch->SendTextf ("I don't think %s would like that!\n\r", arg);
		return;
	}
	echo_to_all  (color, argument, target);
}


void echo_to_room (short AT_COLOR, CRoomIndexData *room, char *argument)
{
	CCharacter	*vic;

	for (vic = room->first_person; vic; vic = vic->GetNextInRoom ()) {
		set_char_color (AT_COLOR, vic);
		vic->SendText (argument);
		vic->SendText ("\n\r");
	}
}


void do_recho (CCharacter *ch, char *argument)
{
	char	arg [MAX_INPUT_LENGTH];
	short	color;

	if (ch->IsAction (PLR_NO_EMOTE)) {
		ch->SendText ("You are noemoted and can not recho.\n\r");
		return;
	}

	if (argument [0] == '\0') {
		ch->SendText ("Recho what?\n\r");
		return;
	}

	one_argument (argument, arg);

	if (! str_cmp (arg, SysData.GetSupremeEntity ())
	  || ! str_cmp (arg, "Rustry")
	  || ! str_cmp (arg, "Circe")
	  || ! str_cmp (arg, "Haus")
	  || ! str_cmp (arg, "Narn")
	  || ! str_cmp (arg, "Scryn")
	  || ! str_cmp (arg, "Blodkai")
	  || ! str_cmp (arg, "Damian"))
	{
		ch->SendTextf ("I don't think %s would like that!\n\r", arg);
		return;
	}

	if ((color = get_color  (argument))) {
		argument = one_argument  (argument, arg);
		echo_to_room  (color, ch->GetInRoom (), argument);
	}
	else
		echo_to_room  (AT_IMMORT, ch->GetInRoom (), argument);
}


CRoomIndexData *find_location (CCharacter *ch, char *arg)
{
	CCharacter *victim;
	CObjData *obj;

	if (is_number (arg))
		return RoomTable.GetRoom (atoi (arg));

	if ((victim = get_char_world (ch, arg)) != NULL)
		return victim->GetInRoom ();

	if ((obj = get_obj_world (ch, arg)) != NULL)
		return obj->in_room;

	return NULL;
}



void do_transfer (CCharacter *ch, char *argument)
{
	char	arg1 [MAX_INPUT_LENGTH];
	char	arg2 [MAX_INPUT_LENGTH];

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

	if (arg1 [0] == '\0') {
		ch->SendText ("Transfer whom (and where)?\n\r");
		return;
	}

	CRoomIndexData *location;
	CCharacter *victim;

	if (! str_cmp (arg1, "all")) {
		POSITION	pos = DList.GetHeadPosition ();
		while (pos) {
			CDescriptor	&Ds = *DList.GetNext (pos);
			if (! Ds.IsDisconnecting () && Ds.m_Connected == CON_PLAYING
			  && Ds.m_pCharacter != ch
			  && Ds.m_pCharacter->GetInRoom ()
			  && Ds.newstate != 2
			  && can_see (ch, Ds.m_pCharacter)) {
				char buf [MAX_STRING_LENGTH];
				sprintf (buf, "%s %s", Ds.m_pCharacter->GetName (), arg2);
				do_transfer (ch, buf);
			}
		}
		return;
	}

	// Thanks to Grodyn for the optional location parameter.
	if (arg2 [0] == '\0')
		location = ch->GetInRoom ();

	else {
		if ((location = find_location (ch, arg2)) == NULL) {
			ch->SendText ("No such location.\n\r");
			return;
		}

		if (room_is_private (location)) {
			ch->SendText ("That room is private right now.\n\r");
			return;
		}
	}

	if ((victim = get_char_world (ch, arg1)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (! victim->IsAuthed ()) {
		ch->SendText ("They are not authorized yet!\n\r");
		return;
	}

	if (! victim->GetInRoom ()) {
		ch->SendText ("They are in limbo.\n\r");
		return;
	}

	if (victim->GetFightData ())
		stop_fighting (victim, TRUE);
	act (AT_MAGIC, "$n disappears in a cloud of swirling colors.",
		victim, NULL, NULL, TO_ROOM);
	victim->retran = victim->GetInRoom ()->vnum;
	victim->RemoveFromRoom ();
	victim->SendToRoom (location);
	act (AT_MAGIC, "$n arrives from a puff of smoke.",
		victim, NULL, NULL, TO_ROOM);

	if (ch != victim)
		act (AT_IMMORT, "$n has transferred you.", ch, NULL, victim, TO_VICT);
	do_look (victim, "auto");
	ch->SendText ("Ok.\n\r");

	if (victim->IsMortal () && !victim->IsNpc () 
		&& ! in_hard_range (victim, location->GetArea ())) 
			ch->SendText ("Warning: the player's level is not within "
				"the area's level range.\n\r");
}


void do_retran (CCharacter *ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	CCharacter *victim;
	char buf[MAX_STRING_LENGTH];
	
	argument = one_argument (argument, arg);
	if (arg[0] == '\0')
	{
		ch->SendText ("Retransfer whom?\n\r");
		return;
	}
	if (! (victim = get_char_world (ch, arg)))
	{
		ch->SendText ("They aren't here.\n\r");
		return;
	}
	sprintf (buf, "'%s' %d", victim->GetName (), victim->retran);
	do_transfer (ch, buf);
	return;
}

void do_regoto (CCharacter *ch, char *argument)
{
	char buf[MAX_STRING_LENGTH];
	
	sprintf (buf, "%d", ch->regoto);
	do_goto (ch, buf);
	return;
}

	
// Added do_atmob and do_atobj to reduce lag associated with at --Shaddai
void do_atmob (CCharacter* ch, char* argument)
{
	char			arg [MAX_INPUT_LENGTH];
	CRoomIndexData	*location;
	CRoomIndexData	*original;
	CCharacter		*wch;

	set_char_color (AT_IMMORT, ch);

	argument = one_argument (argument, arg);
	if (arg [0] == '\0' || argument [0] == '\0') {
		ch->SendText ("At where what?\n\r");
		return;
	}

	if ((wch = get_char_world (ch, arg)) == NULL 
	  || ! wch->IsNpc () || wch->GetInRoom () == NULL) {
		ch->SendText ("No such mobile in existance.\n\r");
		return;
	}

	location = wch->GetInRoom ();
	if (room_is_private (location)) {
		if (ch->GetTrustLevel () < LEVEL_GREATER) {
			ch->SendText ("That room is private right now.\n\r");
			return;
		}
		else ch->SendText ("Overriding private flag!\n\r");
	}

	set_char_color (AT_PLAIN, ch);
	original = ch->GetInRoom ();
	ch->RemoveFromRoom ();
	ch->SendToRoom (location);
	interpret (ch, argument);

	if (! char_died (ch)) {
		ch->RemoveFromRoom ();
		ch->SendToRoom (original);
	}
}


void do_atobj (CCharacter* ch, char* argument)
{
	char			arg [MAX_INPUT_LENGTH];
	CRoomIndexData	*location;
	CRoomIndexData	*original;
	CObjData		*obj;

	set_char_color (AT_IMMORT, ch);

	argument = one_argument (argument, arg);
	if (arg [0] == '\0' || argument [0] == '\0') {
		ch->SendText ("At where what?\n\r");
		return;
	}

	if ((obj = get_obj_world (ch, arg)) == NULL || ! obj->GetInRoom ()) {
		ch->SendText ("No such object in existance.\n\r");
		return;
	}

	location = obj->GetInRoom ();
	if (room_is_private (location)) {
		if (ch->GetTrustLevel () < LEVEL_GREATER) {
			ch->SendText ("That room is private right now.\n\r");
			return;
		}
		else ch->SendText ("Overriding private flag!\n\r");
	}

	set_char_color (AT_PLAIN, ch);
	original = ch->GetInRoom ();
	ch->RemoveFromRoom ();
	ch->SendToRoom (location);
	interpret (ch, argument);

	if (! char_died (ch)) {
		ch->RemoveFromRoom ();
		ch->SendToRoom (original);
	}
}


void do_at (CCharacter *ch, char *argument)
{
	char			arg [MAX_INPUT_LENGTH];
	CRoomIndexData	*original;
	CCharacter		*wch;

	set_char_color (AT_IMMORT, ch);
	argument = one_argument (argument, arg);

	if (arg [0] == '\0' || argument [0] == '\0') {
		ch->SendText ("At where what?\n\r");
		return;
	}

	CRoomIndexData	*location = NULL;
	if (is_number (arg))
		location = RoomTable.GetRoom (atoi (arg));
	else {
		POSITION	pos = DList.GetHeadPosition ();
		while (pos) {
			CDescriptor	&Ds = *DList.GetNext (pos);
			if ((Ds.m_Connected == CON_PLAYING
			  || Ds.m_Connected == CON_EDITING)
			  && can_see (ch, Ds.m_pCharacter)
			  && ! str_cmp (Ds.m_pCharacter->GetName (), arg)) {
				location = Ds.m_pCharacter->GetInRoom ();
				break;
			}
		}
	}

	if (! location) {
		ch->SendText ("No such location.\n\r");
		return;
	}

	if (room_is_private (location)) {
		if (ch->GetTrustLevel () < LEVEL_GREATER) {
			ch->SendText ("That room is private right now.\n\r");
			return;
		}
		else ch->SendText ("Overriding private flag!\n\r");
	}

	set_char_color (AT_PLAIN, ch);
	original = ch->GetInRoom ();
	ch->RemoveFromRoom ();
	ch->SendToRoom (location);
	interpret (ch, argument);

	// See if 'ch' still exists before continuing!
	// Handles 'at XXXX quit' case.
	for (wch = first_char; wch; wch = wch->GetNext ()) {
		if (wch == ch) {
			ch->RemoveFromRoom ();
			ch->SendToRoom (original);
			break;
		}
	}
}


void do_rat (CCharacter *ch, char *argument)
{
	char			arg1 [MAX_INPUT_LENGTH];
	char			arg2 [MAX_INPUT_LENGTH];
	CRoomIndexData	*location;
	CRoomIndexData	*original;
	int				Start, End, vnum;

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

	if (arg1[0] == '\0' || arg2[0] == '\0' || argument[0] == '\0') {
		ch->SendText ("Syntax: rat <start> <end> <command>\n\r");
		return;
	}

	Start = atoi (arg1);	End = atoi (arg2);

	if (Start < 1 || End < Start || Start > End || Start == End
	  || End > 2097152000) {	// was 32767
		ch->SendText ("Invalid range.\n\r");
		return;
	}

	if (!str_cmp (argument, "quit")) {
		ch->SendText ("I don't think so!\n\r");
		return;
	}

	original = ch->GetInRoom ();
	for (vnum = Start; vnum <= End; vnum++) {
		if ((location = RoomTable.GetRoom (vnum)) == NULL)
			continue;
		ch->RemoveFromRoom ();
		ch->SendToRoom (location);
		interpret (ch, argument);
	}

	ch->RemoveFromRoom ();
	ch->SendToRoom (original);
	ch->SendText ("Done.\n\r");
}


void do_rstat (CCharacter *ch, char *argument)
{
    char buf[MAX_STRING_LENGTH];
    char arg[MAX_INPUT_LENGTH];
    CRoomIndexData *location;
    CObjData *obj;
    CCharacter *rch;
    CExitData *pexit;
    int cnt;
    static char *dir_text[] = { "n", "e", "s", "w", "u", "d", "ne", "nw", "se", "sw", "?" };

	set_char_color (AT_DGREEN, ch);
    one_argument (argument, arg);
    if (!str_cmp (arg, "exits"))
    {
	location = ch->GetInRoom ();

	ch->SendTextf ("Exits for room '%s.' vnum %d\n\r",
		location->GetName (), location->vnum);

	for (cnt = 0, pexit = location->first_exit; pexit; pexit = pexit->GetNext ())
	    ch->SendTextf ("%2d) %2s to %-5d.  Key: %d  Flags: %s  "
			"Keywords: '%s'.\n\rDescription: %sExit links back to vnum: "
			"%d  Exit's RoomVnum: %d  Distance: %d\n\r",
			++cnt, dir_text [pexit->vdir],
			pexit->GetToRoom () ? pexit->GetToRoom ()->vnum : 0,
			pexit->key, pexit->PrintFlagVector (), pexit->keyword,
			pexit->description[0] != '\0' ? pexit->description : "(none).\n\r",
			pexit->rexit ? pexit->rexit->vnum : 0,
			pexit->rvnum, pexit->distance);
		return;
    }
    location =  (arg[0] == '\0') ? ch->GetInRoom () : find_location (ch, arg);
    if (!location)
    {
	ch->SendText ("No such location.\n\r");
	return;
    }

    if (ch->GetInRoom () != location && room_is_private (location))
    {
      if (ch->GetTrustLevel () < LEVEL_GREATER)
      {
        ch->SendText ("That room is private right now.\n\r");
        return;
      }
      else
      {
        ch->SendText ("Overriding private flag!\n\r");
      }

    }

    ch->SendTextf ("Name: %s.\n\rArea: %s  Filename: %s.\n\r",
		location->GetName (),
		location->GetArea () ? location->GetArea ()->GetName () : "None????",
		location->GetArea () ? location->GetArea ()->m_Filename : "None????");

    ch->SendTextf ("Vnum: %d.  Sector: %d.  Light: %d.  TeleDelay: %d.  "
		"TeleVnum: %d  Tunnel: %d.\n\r",
		location->vnum, location->sector_type, location->light,
		location->tele_delay, location->tele_vnum, location->tunnel);

    ch->SendTextf ("Room flags: %s\n\r",
	flag_string (location->GetRoomFlags (), r_flags));
    ch->SendTextf ("Description:\n\r%s", location->GetDescription ());

	if (! location->ExDesList.IsEmpty ()) {
		ch->SendText ("Extra description keywords: '");
		CPtrList	&EList = location->ExDesList;
		POSITION	pos = EList.GetHeadPosition ();
		while (pos) {
			CExtraDescrData	&Ed = *(CExtraDescrData*) EList.GetNext (pos);
			ch->SendText (Ed.keyword);
			if (pos)
				ch->SendText (" ");
		}
		ch->SendText ("'.\n\r");
	}

    ch->SendText ("Characters:");
    for (rch = location->first_person; rch; rch = rch->GetNextInRoom ())
    {
	if (can_see (ch, rch))
	{
	  ch->SendText (" ");
	  one_argument (rch->GetName (), buf);
	  ch->SendText (buf);
	}
    }

	ch->SendText (".\n\rObjects:   ");
	POSITION	pos = location->GetHeadContentPos ();
	while (obj = location->GetNextContent (pos)) {
		ch->SendText (" ");
		one_argument (obj->GetName (), buf);
		ch->SendText (buf);
	}
	ch->SendText (".\n\r");

    if (location->first_exit)
	ch->SendText ("------------------- EXITS -------------------\n\r");
    for (cnt = 0, pexit = location->first_exit; pexit; pexit = pexit->GetNext ())
	ch->SendTextf ( "%2d) %-2s to %-5d.  Key: %d  Flags: %s  Keywords: %s.\n\r",
		++cnt, dir_text [pexit->vdir],
		pexit->GetToRoom () ? pexit->GetToRoom ()->vnum : 0,
		pexit->key, pexit->PrintFlagVector (),
		pexit->keyword[0] != '\0' ? pexit->keyword : "(none)");
}


void do_ostat (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CObjData	*obj;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Ostat what?\n\r");
		return;
	}

	if (arg[0] != '\'' && arg[0] != '"' && strlen (argument) > strlen (arg))
		strcpy (arg, argument);

	if ((obj = get_obj_world (ch, arg)) == NULL) {
		ch->SendText ("Nothing like that in hell, earth, or heaven.\n\r");
		return;
	}

	ch->SendTextf ("Name: %s.\n\r", obj->GetName ());

	ch->SendTextf ("Vnum: %d.  Type: %s.  Count: %d  Gcount: %d\n\r",
		obj->pIndexData->vnum, item_type_name (obj), obj->pIndexData->count,
		obj->count);

	ch->SendTextf ("Serial#: %d  TopIdxSerial#: %d  TopSerial#: %d\n\r",
		obj->serial, obj->pIndexData->serial, cur_obj_serial);

	ch->SendColorf ("Short description: %s.\n\rLong description: %s\n\r",
		obj->GetShortDescr (), obj->GetDescription ());

	if (obj->GetActionDescr ()[0] != '\0')
		ch->SendTextf ("Action description: %s.\n\r", obj->GetActionDescr ());

	ch->SendTextf ("Wear flags : %s\n\r", flag_string (obj->wear_flags,
		w_flags));
	ch->SendTextf ("Extra flags: %s\n\r",
		obj->m_ExtraFlags.PrintString ());
	ch->SendTextf ("Anti Classes: %s\n\r", obj->AntiClassNames ());

	ch->SendTextf ("Number: %d/%d.  Weight: %d/%d.  Layers: %d\n\r",
		1, get_obj_number (obj), obj->weight, get_obj_weight (obj),
		obj->pIndexData->layers);

	ch->SendTextf ("Cost: %d.  Timer: %d.  Level: %d.\n\r",
		obj->cost, obj->timer, obj->level);

	ch->SendColorf (
		"In room: %d.  In object: %s.  Carried by: %s.  Wear_loc: %d.\n\r",
		obj->in_room == NULL ? 0 : obj->in_room->vnum,
		obj->in_obj == NULL ? "(none)" : obj->in_obj->GetShortDescr (),
		obj->carried_by == NULL ? "(none)" : obj->carried_by->GetName (),
		obj->wear_loc);

	ch->SendTextf ("Index Values : %d %d %d %d %d %d.\n\r",
		obj->pIndexData->value[0], obj->pIndexData->value[1],
		obj->pIndexData->value[2], obj->pIndexData->value[3],
		obj->pIndexData->value[4], obj->pIndexData->value[5]);

	ch->SendTextf ("Object Values: %d %d %d %d %d %d.\n\r",
		obj->value[0], obj->value[1], obj->value[2], obj->value[3],
		obj->value[4], obj->value[5]);

	if (! obj->pIndexData->ExDesList.IsEmpty ()) {
		ch->SendText ("Primary description keywords:   '");
		CPtrList	&EList = obj->pIndexData->ExDesList;
		POSITION	pos = EList.GetHeadPosition ();
		while (pos) {
			CExtraDescrData	&Ed = *(CExtraDescrData*) EList.GetNext (pos);
			ch->SendText (Ed.keyword);
			if (pos)
				ch->SendText (" ");
		}
		ch->SendText ("'.\n\r");
	}

	if (! obj->ExDesList.IsEmpty ()) {
		ch->SendText ("Secondary description keywords: '");
		CPtrList	&EList = obj->ExDesList;
		POSITION	pos = EList.GetHeadPosition ();
		while (pos) {
			CExtraDescrData	&Ed = *(CExtraDescrData*) EList.GetNext (pos);
			ch->SendText (Ed.keyword);
			if (pos)
				ch->SendText (" ");
		}
		ch->SendText ("'.\n\r");
	}

	int				aCount = 0;
	CAffectList		&IList = obj->pIndexData->AffList;
	POSITION		apos = IList.GetHeadPosition ();
	while (apos)
		IList.GetNext (apos)->ShowAffect (ch, ++aCount);

	CAffectList		&AList = obj->AffList;
	apos = AList.GetHeadPosition ();
	while (apos)
		AList.GetNext (apos)->ShowAffect (ch, ++aCount, TRUE);	// TRUE means
		// show as "(extra)" to indicate affect is added to idx properties.
}


void do_mstat (CCharacter* ch, char* argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CAffectData	*paf;
	CCharacter	*victim;
	CSkill		*skill;

	set_char_color (AT_PLAIN, ch);

	one_argument (argument, arg);
	if (arg [0] == '\0') {
		ch->SendText ("Mstat whom?\n\r");
		return;
	}
	if (arg [0] != '\'' && arg [0] != '"' && strlen (argument) > strlen (arg))
		strcpy (arg, argument);

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}
	if (ch->GetTrustLevel () < victim->GetTrustLevel () && !victim->IsNpc ()){
		set_char_color (AT_IMMORT, ch);
		ch->SendText (
			"Their godly glow prevents you from getting a good look.\n\r");
		return;
	}

	pc_data	&vPc = *victim->GetPcData ();

	ch->SendTextf ("Name: %s     Clan: %s     %s\n\r", victim->GetName (),
		(victim->IsNpc () || ! vPc.GetClan ()) ?
		"(none)" : vPc.GetClan ()->GetName (),
		victim->IsNpc () ? "" : victim->IsPkiller ()
		? "Path: Pkill" : "Path: Non-pkill");

	if (ch->GetTrustLevel () >= LEVEL_GOD && !victim->IsNpc ()
	  && victim->GetDesc ())
		ch->SendTextf ("User: %s%s   Descriptor: %d   Trust: %d   "
			"AuthedBy: %s\n\r",
			victim->GetDesc ()->user, victim->GetDesc ()->m_pHost,
			victim->GetDesc ()->m_DescNo,
			victim->GetTrust (), vPc.authed_by [0] != '\0'
			? vPc.authed_by : "(unknown)");

	if (! victim->IsNpc () && ! vPc.release_date.IsZero ())
		ch->SendTextf ("Helled until %s by %s.\n\r",
		vPc.release_date.GetString (), vPc.helled_by);

	ch->SendTextf (
		"Vnum: %d   Sex: %s   Room: %d   Count: %d  Killed: %d\n\r",
		victim->IsNpc () ? victim->GetMobIndex ()->vnum : 0,
		victim->GetSex () == SEX_MALE    ? "male"   :
		victim->GetSex () == SEX_FEMALE  ? "female" : "neutral",
		victim->GetInRoom () == NULL    ?        0 : victim->GetInRoom ()->vnum,
		victim->IsNpc () ? victim->GetMobIndex ()->count : 1,
		victim->IsNpc () ? victim->GetMobIndex ()->killed
		: vPc.mdeaths + vPc.pdeaths);

	ch->SendTextf ("Str: %d   Int: %d   Wis: %d   Dex: %d   Con: %d   "
		"Cha: %d   Lck: %d\n\r",
		victim->GetCurrentStrength (), victim->GetIntelligence (),
		victim->GetWisdom (), victim->GetDexterity (),
		victim->GetConstitution (), get_curr_cha (victim),
		get_curr_lck (victim));

	if (victim->IsVampire () && ! victim->IsNpc ())
		ch->SendTextf ("Hps: %d/%d   Blood: %d/%d   Move: %d/%d   "
			"Practices: %d\n\r",
			victim->GetHp (), victim->GetMaxHp (),
			vPc.condition [COND_BLOODTHIRST],
			10 + victim->GetLevel (), victim->GetMove (),
			victim->GetMaxMove (), victim->GetPractices ());
	else
		ch->SendTextf ("Hps: %d/%d   Mana: %d/%d   Move: %d/%d   "
			"Practices: %d\n\r",
			victim->GetHp (), victim->GetMaxHp (), victim->GetMana (),
			victim->GetMaxMana (), victim->GetMove (),
			victim->GetMaxMove (), victim->GetPractices ());  

	ch->SendTextf ("Level: %d  Class/Race: %d/%d  Align: %d  AC: %d  "
		"Gold: %d  XP: %d\n\r",
		victim->GetLevel (), victim->GetClass (), victim->GetRace (),
		victim->GetAlignment (), victim->GetAc (), victim->GetGold (),
		victim->GetExp ());

	if (victim->IsNpc ()) {
		if (victim->GetClass () < MAX_NPC_CLASS && victim->GetClass () >= 0
		  && victim->GetRace () < MAX_NPC_RACE  && victim->GetRace ()  >= 0)
			ch->SendTextf ("Class: %s  Race: %s\n\r",
				ClassTable.GetNpcClassName (victim->GetClass ()),
				RaceTable.GetNpcRaceName (victim->GetRace ()));
	} else {
		ch->SendTextf ("Class: %s  Race: %s  Deity: %s\n\r",
			ClassTable.GetName (victim->GetClass ()),
			RaceTable.GetName (victim->GetRace ()),
			vPc.deity ? vPc.deity->GetName () : "(none)");
	}

	ch->SendTextf ("Hitroll: %d   Damroll: %d   Position: %d   "
		"Wimpy: %d \n\r",
		GET_HITROLL (victim), GET_DAMROLL (victim),
		victim->GetPosition (), victim->GetWimpLevel ());

	ch->SendTextf ("Fighting: %s    Master: %s    Leader: %s\n\r",
		victim->GetFightData ()
			? victim->GetFightData ()->who->GetName () : "(none)",
		victim->GetMaster () ? victim->GetMaster ()->GetName ()   : "(none)",
		victim->GetLeader () ? victim->GetLeader ()->GetName ()   : "(none)");

	if (! victim->IsNpc ())
		ch->SendTextf ("Thirst: %d   Full: %d   Drunk: %d     "
			"Favor: %d    Glory: %d/%d\n\r",
			vPc.condition [COND_THIRST], vPc.condition [COND_FULL],
			vPc.condition [COND_DRUNK], vPc.favor,
			vPc.quest_curr, vPc.quest_accum);
	else
		ch->SendTextf ("Hit dice: %dd%d+%d.  Damage dice: %dd%d+%d.\n\r",
			victim->GetMobIndex ()->hitnodice,
			victim->GetMobIndex ()->hitsizedice,
			victim->GetMobIndex ()->hitplus,
			victim->GetMobIndex ()->damnodice,
			victim->GetMobIndex ()->damsizedice,
			victim->GetMobIndex ()->damplus);

	ch->SendTextf ("MentalState: %d   EmotionalState: %d\n\r",
		victim->GetMentalState (), victim->emotional_state);

	ch->SendTextf ("Saving throws: %d %d %d %d %d.\n\r",
		victim->saving_poison_death, victim->saving_wand,
		victim->saving_para_petri, victim->saving_breath,
		victim->saving_spell_staff);

	ch->SendTextf ("Carry figures: items  (%d/%d)  weight  (%d/%d)   "
		"Numattacks: %d\n\r",
		victim->carry_number, victim->GetMaxItems (), victim->GetCarryWeight (),
		can_carry_w (victim), victim->numattacks);

	ch->SendTextf (
		"Years: %d   Seconds Played: %d   Timer: %d   Act: %s\n\r",
		victim->GetAge (), (int) victim->GetPlayed (), victim->GetTimer (),
		victim->GetActFlags ().PrintVector ());

	ch->SendTextf ("%s flags: %s\n\r",
		victim->IsNpc () ? "Act" : "Player",
		victim->GetActFlags ().PrintString (victim->IsNpc ()));
	
	if (victim->IsMobInvis ())
		ch->SendTextf ("Mobinvis Level: %d\r\n", victim->GetMobInvisLevel ());

	if (! victim->IsNpc ())
		ch->SendTextf ("Pcflags: %s\n\r",
			flag_string (victim->GetPcFlags (), pc_flags));

	ch->SendTextf ("Affected by: %s\n\r",
		victim->GetAffectFlags ().PrintString ());

	ch->SendColorf ("&cSpeaks: &w%s   &cSpeaking: &w%d   &cExperience: &w%d\n\r",
		victim->GetSpeaksFlags ().PrintVector (), victim->GetSpeaking (),
		victim->GetExp ());

	ch->SendColor ("&cLanguages: &w");

	for (int lang=1; lang < LanguageTable.GetCount (); ++lang) {
		if (knows_language (victim, lang, victim)) {
			if (victim->IsSpeaking (lang))
				set_char_color (AT_RED, ch);
			else if (ch->IsSpeaking (lang))
				set_char_color (AT_PINK, ch);

			ch->SendText (LanguageTable.GetName (lang));
			ch->SendText (" ");
			set_char_color (AT_PLAIN, ch);
		}
	}
	ch->SendText ("\n\r");

	if (&vPc && vPc.HasBestowments ())
		ch->SendTextf ("Bestowments: %s\n\r", vPc.GetBestowments ());

	ch->SendTextf ("Description: %s\n\r", victim->GetDescription ());

	ch->SendTextf ("Short description: %s\n\rLong  description: %s",
		victim->GetShortDescr (),
		victim->HasLongDescription () ?
			victim->GetLongDescr () : "(none)\n\r");

	if (victim->IsNpc () && victim->GetSpecialMobFunction ())
		ch->SendTextf ("Mobile has spec fun: %s\n\r",
			lookup_spec (victim->GetSpecialMobFunction ()));

	ch->SendTextf ("Body Parts : %s\n\r",
		flag_string (victim->GetXFlags (), part_flags));

	ch->SendTextf ("Resistant  : %s\n\r",
		flag_string (victim->GetResistFlags (), ris_flags));

	ch->SendTextf ("Immune     : %s\n\r",
		flag_string (victim->GetImmuneFlags (), ris_flags));

	ch->SendTextf ("Susceptible: %s\n\r",
		flag_string (victim->GetSusceptFlags (), ris_flags));

	ch->SendTextf ("Attacks    : %s\n\r",
		victim->GetAttackFlags ().PrintString ());

	ch->SendTextf ("Defenses   : %s\n\r",
		victim->GetDefenseFlags ().PrintString ());

	POSITION	pos = victim->m_AffectList.GetHeadPosition ();
	while (pos) {
		paf = victim->m_AffectList.GetNext (pos);
		if ((skill = SkillTable.GetValidSkill (paf->type)) != NULL)
			ch->SendTextf (
				"%s: '%s' modifies %s by %d for %d rounds with bits %s.\n\r",
				skill_tname [skill->GetType ()], skill->GetName (),
				affect_loc_name (paf->location), paf->modifier,
				paf->duration, CAffectFlags::GetName (paf->bitvector));
	}
}



void do_mfind (CCharacter *ch, char *argument)
{
	char			arg [MAX_INPUT_LENGTH];
	CMobIndexData	*pMobIndex;
	int				hash;
	int				nMatch;
	BOOL			fAll;

	one_argument (argument, arg);
	if (arg[0] == '\0') {
		ch->SendText ("Mfind whom?\n\r");
		return;
	}

	fAll = !str_cmp (arg, "all");
	nMatch = 0;
	set_pager_color (AT_PLAIN, ch);

	/*
	 * Yeah, so iterating over all vnum's takes 10,000 loops.
	 * Get_mob_index is fast, and I don't feel like threading another link.
	 * Do you?
	 * -- Furey
	 */
	/*  for (vnum = 0; nMatch < MobTable.GetCount (); vnum++)
	{
	if ((pMobIndex = MobTable.GetMob (vnum)) != NULL)
	{
		if (fAll || is_name (arg, pMobIndex->player_name))
		{
		nMatch++;
		sprintf (buf, "[%5d] %s\n\r",
			pMobIndex->vnum, capitalize (pMobIndex->short_descr));
		ch->SendText (buf);
		}
	}
	}
	 */

	/*
	 * This goes through all the hash entry points  (1024), and is therefore
	 * much faster, though you won't get your vnums in order... oh well. :)
	 *
	 * Tests show that Furey's method will usually loop 32,000 times, calling
	 * get_mob_index ()... which loops itself, an average of 1-2 times...
	 * So theoretically, the above routine may loop well over 40,000 times,
	 * and my routine below will loop for as many index_mobiles are on
	 * your mud... likely under 3000 times.
	 * -Thoric
	 */
	for (hash = 0; hash < MAX_KEY_HASH; hash++)
		for (pMobIndex = MobTable.GetFirstByHash (hash); pMobIndex; pMobIndex = pMobIndex->GetNext ())
			if (fAll || nifty_is_name (arg, pMobIndex->GetPlayerName ())) {
				nMatch++;
				pager_printf (ch, "[%5d] %s\n\r",
					pMobIndex->vnum, capitalize (pMobIndex->GetShortDescr ()));
			}

	if (nMatch)
		pager_printf (ch, "Number of matches: %d\n", nMatch);
	else
		ch->SendText ("Nothing like that in hell, earth, or heaven.\n\r");
}



void do_ofind (CCharacter *ch, char *argument)
{
/*  extern int top_obj_index; */
    char arg[MAX_INPUT_LENGTH];
    CObjIndexData *pObjIndex;
/*  int vnum; */
    int hash;
    int nMatch;
    BOOL fAll;

    one_argument (argument, arg);
    if (arg[0] == '\0')
    {
	ch->SendText ("Ofind what?\n\r");
	return;
    }

    set_pager_color (AT_PLAIN, ch);
    fAll	= !str_cmp (arg, "all");
    nMatch	= 0;
/*  nLoop	= 0; */

    /*
     * Yeah, so iterating over all vnum's takes 10,000 loops.
     * Get_obj_index is fast, and I don't feel like threading another link.
     * Do you?
     * -- Furey
    for (vnum = 0; nMatch < top_obj_index; vnum++)
    {
	nLoop++;
	if ((pObjIndex = OIdxTable.GetObj (vnum)) != NULL)
	{
	    if (fAll || nifty_is_name (arg, pObjIndex->name))
	    {
		nMatch++;
		sprintf (buf, "[%5d] %s\n\r",
		    pObjIndex->vnum, capitalize (pObjIndex->short_descr));
		ch->SendText (buf);
	    }
	}
    }
     */

    /*
     * This goes through all the hash entry points  (1024), and is therefore
     * much faster, though you won't get your vnums in order... oh well. :)
     *
     * Tests show that Furey's method will usually loop 32,000 times, calling
     * OIdxTable.GetObj ()... which loops itself, an average of 2-3 times...
     * So theoretically, the above routine may loop well over 50,000 times,
     * and my routine bellow will loop for as many index_objects are on
     * your mud... likely under 3000 times.
     * -Thoric
     */
    for (hash = 0; hash < MAX_KEY_HASH; hash++)
		for (pObjIndex = OIdxTable.GetFirstByHash (hash); pObjIndex;
		  pObjIndex = pObjIndex->GetNext ())
		    if (fAll || nifty_is_name (arg, pObjIndex->GetName ())) {
				nMatch++;
				pager_printf (ch, "[%5d] %s\n\r",
					pObjIndex->vnum, capitalize (pObjIndex->GetShortDescr ()));
		    }

    if (nMatch)
	pager_printf (ch, "Number of matches: %d\n", nMatch);
    else
	ch->SendText ("Nothing like that in hell, earth, or heaven.\n\r");

    return;
}



void do_mwhere (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;
	BOOL		found;

	one_argument (argument, arg);
	if (arg [0] == '\0') {
		ch->SendText ("Mwhere whom?\n\r");
		return;
	}

	set_char_color (AT_PLAIN, ch);
	found = FALSE;
	for (victim = first_char; victim; victim = victim->GetNext ()) {
		if (victim->IsNpc () && victim->GetInRoom ()
		  && nifty_is_name (arg, victim->GetName ())) {
			found = TRUE;
			int	ColSiz = GetColorSize (victim->GetShortDescr ());
			pager_printf (ch, "[%5d] %-*s [%5d] %s\n\r",
				victim->GetMobIndex ()->vnum, 28 + ColSiz,
				victim->GetShortDescr (),
				victim->GetInRoom ()->vnum,
				victim->GetInRoom ()->GetName ());
		}
    }

    if (!found)
		act (AT_PLAIN, "You didn't find any $T.", ch, NULL, arg, TO_CHAR);
}


void do_showbytes (CCharacter *ch, char *argument)
{
    CTime	bt = SysData.GetByteTime ();

	ch->SendTextf ("Bytes sent this hour: %lu\n", SysData.GetSentHourBytes ());
	ch->SendTextf ("KBytes sent today:    %lu\n", SysData.GetSentDayKb ());
}


// gwhere will list all players or all mobs in the mud, with optional level
// restriction on the list.  If all mobs are listed with no level
// restrictions the pager will overflow.  This is not fatal, but some of
// the list will be lost.  To fix this, the value MAX_PAGER_BUFFER can be
// increased from the default 0x8000 to 0x10000 or even 0x20000.
// You will then be allocating 128 k of your system memory for just the
// pager. This could slow things down if you are short on available memory.
void do_gwhere (CCharacter* ch, char* argument)
{
	CCharacter	*victim;
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	char		arg3 [MAX_INPUT_LENGTH];
	BOOL		found = FALSE, pmobs = FALSE;
	int			low = 1, high = 65, count = 0; 

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

	if (arg1 [0] != '\0') {
		if (arg1 [0] == '\0' || arg2 [0] == '\0') {
			ch->PageColor ("\n\r&wSyntax:  gwhere | gwhere <low> <high>"
				" | gwhere <low> <high> mobs\n\r");
			return;
		}
		low = atoi (arg1);
		high = atoi (arg2);
	}

	if (low < 1 || high < low || low > high || high > 65) {
		ch->PageColor ("&wInvalid level range.\n\r");
		return;
	}

	argument = one_argument (argument, arg3);
	if (! str_cmp (arg3, "mobs"))
		pmobs = TRUE;

	ch->PageColorf ("\n\r&cGlobal %s locations:&w\n\r",
		pmobs ? "mob" : "player" );

	if (! pmobs) {
		POSITION	pos = DList.GetHeadPosition ();
		while (pos) {
			CDescriptor	&Ds = *DList.GetNext (pos);
			if ((Ds.m_Connected == CON_PLAYING || Ds.m_Connected == CON_EDITING)
			  && (victim = Ds.m_pCharacter) != NULL
			  && ! victim->IsNpc () && victim->GetInRoom ()
			  && can_see (ch, victim)
			  && victim->GetLevel () >= low && victim->GetLevel () <= high) {
				found = TRUE;
				ch->PageColorf ("&c(&C%2d&c) &w%-12.12s   [%-5d - %-19.19s]"
					"   &c%-25.25s\n\r",
					victim->GetLevel (), victim->GetName (),
					victim->GetInRoom ()->vnum,
					victim->GetInRoom ()->GetArea ()->GetName (),
					victim->GetInRoom ()->GetName ());
				++count;
			}
		}
	} else {
		for (victim = first_char; victim; victim = victim->GetNext ())
			if (victim->IsNpc ()
			  && victim->GetInRoom () && can_see (ch, victim)
			  && victim->GetLevel () >= low && victim->GetLevel () <= high) {
				found = TRUE;
				ch->PageColorf ("&c(&C%2d&c) &w%-12.12s   [%-5d - %-19.19s]"
					"   &c%-25.25s\n\r",
					victim->GetLevel (), victim->GetName (),
					victim->GetInRoom ()->vnum,
					victim->GetInRoom ()->GetArea ()->GetName (),
					victim->GetInRoom ()->GetName ());
				++count;
			}
	}

	ch->PageColorf ("&c%d %s found.\n\r", count,
		pmobs ? "mobs" : "characters");
}


void do_gfighting (CCharacter* ch, char* argument)
{
	CCharacter	*victim;
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	char		arg3 [MAX_INPUT_LENGTH];
	BOOL		bMobs = FALSE, bHating = FALSE, bHunting = FALSE;
	int			low = 1, high = 65, count = 0;

	argument = one_argument (argument, arg1);
	argument = one_argument (argument, arg2);
	if (arg1 [0] != '\0') {
		if (arg1 [0] == '\0' || arg2 [0] == '\0') {
			ch->PageColor ("\n\r&wSyntax:  gfighting | "
				"gfighting <low> <high> | gfighting <low> <high> mobs\n\r");
			return;
		}
		low = atoi (arg1);
		high = atoi (arg2);
	}
	if (low < 1 || high < low || low > high || high > 65) {
		ch->PageColor ("&wInvalid level range.\n\r");
		return;
	}

	argument = one_argument (argument, arg3);
	if (! str_cmp (arg3, "mobs"))
		bMobs = TRUE;
	else if (! str_cmp (arg3, "hating"))
		bHating = TRUE;
	else if (! str_cmp (arg3, "hunting"))
		bHunting = TRUE;

	if (bHating || bHunting)
		bMobs = TRUE;

	ch->PageColorf ("\n\r&cGlobal %s conflict:\n\r",
		bMobs ? "mob" : "character");

	if (! bMobs && ! bHating && ! bHunting) {
		POSITION	pos = DList.GetHeadPosition ();
		while (pos) {
			CDescriptor	&Ds = *DList.GetNext (pos);
			if ((Ds.m_Connected == CON_PLAYING || Ds.m_Connected == CON_EDITING)
			  && (victim = Ds.m_pCharacter) != NULL
			  && ! victim->IsNpc () && victim->GetInRoom ()
			  && can_see (ch, victim)
			  && victim->GetFightWho ()
			  && victim->GetLevel () >= low && victim->GetLevel () <= high) {
				PrintConflict (ch, victim, victim->GetFightWho ());
				++count;
			}
		}
	}
	else if (! bHating && ! bHunting) {
		for (victim = first_char; victim; victim = victim->GetNext ())
			if (victim->IsNpc ()
			  && victim->GetInRoom () && can_see (ch, victim)
			  && victim->GetFightWho ()
			  && victim->GetLevel () >= low && victim->GetLevel () <= high) {
				PrintConflict (ch, victim, victim->GetFightWho ());
				++count;
			}
	}
	else if (bHating) {
		for (victim = first_char; victim; victim = victim->GetNext ())
			if (victim->IsNpc ()
			&& victim->GetInRoom () && can_see (ch, victim)
			&& victim->hating
			&& victim->GetLevel () >= low && victim->GetLevel () <= high) {
				PrintConflict (ch, victim, victim->hating->who);
				++count;
			}
	}
	else if (bHunting) {
		for (victim = first_char; victim; victim = victim->GetNext ())
			if (victim->IsNpc ()
			&& victim->GetInRoom () && can_see (ch, victim)
			&& victim->hunting
			&& victim->GetLevel () >= low && victim->GetLevel () <= high) {
				PrintConflict (ch, victim, victim->hunting->who);
				++count;
			}
	}
	ch->PageColorf ("&c%d %s conflicts located.\n\r", count,
		bMobs ? "mob" : "character");
}


void PrintConflict (CCharacter* ch, CCharacter* victim, CCharacter* mob)
{
	ch->PageColorf ("&w%-12.12s &C|%2d &wvs &C%2d| &w"
		"%-16.16s [%5d] &c%-19.19s [%5d]\n\r",
		victim->GetName (), victim->GetLevel (),
		mob->GetLevel (),
		mob->IsNpc () ? mob->GetShortDescr () : mob->GetName (),
		mob->IsNpc () ? mob->GetMobIndex ()->vnum : 0,
		mob->GetInRoom ()->GetArea ()->GetName (),
		mob->GetInRoom ()->vnum);
}


void do_bodybag (CCharacter *ch, char *argument)
{
	char		buf2 [MAX_STRING_LENGTH];
	char		arg [MAX_INPUT_LENGTH];
	CObjData	*obj;

	one_argument (argument, arg);
	if (arg [0] == '\0') {
		ch->SendText ("Bodybag whom?\n\r");
		return;
	}

	// check to see if vict is playing?
	sprintf (buf2, "the corpse of %s", arg); 
	BOOL bFound = FALSE;

	// This will be a lot faster than looking thru the object list for
	// the whole mud.
	CObjIndexData	&Idx = *OIdxTable.Find (OBJ_VNUM_CORPSE_PC);
	if (! &Idx)
		bug ("do_bodybag: No object index for OBJ_VNUM_CORPSE_PC.");

	else {
		POSITION	pos = Idx.m_ObjList.GetHeadPosition ();
		while (pos) {
			obj = Idx.m_ObjList.GetNext (pos);
			if (obj->in_room && !str_cmp (buf2, obj->GetShortDescr ())) {
				bFound = TRUE;
				ch->SendTextf ("Bagging body: [%5d] %-28s [%5d] %s\n\r",
					obj->pIndexData->vnum, obj->GetShortDescr (),
					obj->in_room->vnum, obj->in_room->GetName ());
				obj_from_room (obj); 
				obj = obj_to_char (obj, ch);
				obj->timer = -1;
				save_char_obj (ch);
			}
		}
	}
	if (!bFound)
		ch->SendTextf (" You couldn't find any %s\n\r", buf2);
}


// New owhere by Altrag, 03/14/96
void do_owhere (CCharacter *ch, char *argument)
{
	char		buf [MAX_STRING_LENGTH];
	char		arg [MAX_INPUT_LENGTH];
	char		arg1 [MAX_INPUT_LENGTH];
	CObjData	*obj;
	int			icnt = 0;

	argument = one_argument (argument, arg);
	if (arg [0] == '\0') {
		ch->SendText ("Owhere what?\n\r");
		return;
	}
	argument = one_argument (argument, arg1);

	set_pager_color (AT_PLAIN, ch);
	if (arg1 [0] != '\0' && ! str_prefix (arg1, "nesthunt")) {
		if (! (obj = get_obj_world (ch, arg))) {
			ch->SendText ("Nesthunt for what object?\n\r");
			return;
		}
		for (; obj->in_obj; obj = obj->in_obj) {
			pager_printf (ch, "[%5d] %-28s in object [%5d] %s\n\r",
				obj->pIndexData->vnum, obj_short (obj),
				obj->in_obj->pIndexData->vnum, obj->in_obj->GetShortDescr ());
			++icnt;
		}
		sprintf (buf, "[%5d] %-28s in ", obj->pIndexData->vnum,
			obj_short (obj));
		if (obj->carried_by)
			sprintf (buf+strlen (buf), "invent [%5d] %s\n\r",
				(obj->carried_by->IsNpc ()
				? obj->carried_by->GetMobIndex ()->vnum : 0),
				PERS (obj->carried_by, ch));

		else if (obj->in_room)
			sprintf (buf+strlen (buf), "room   [%5d] %s\n\r",
				obj->in_room->vnum, obj->in_room->GetName ());

		else if (obj->in_obj) {
			bug ("do_owhere: obj->in_obj after NULL!");
			strcat (buf, "object??\n\r");
		} else {
			bug ("do_owhere: object doesnt have location!");
			strcat (buf, "nowhere??\n\r");
		}
		send_to_pager (buf, ch);
		++icnt;
		pager_printf (ch, "Nested %d levels deep.\n\r", icnt);
		return;
	}

	BOOL		bFound = FALSE;
	POSITION	Apos = AreaList.GetHeadPosition ();
	while (Apos) {
		CAreaData	&Area = *AreaList.GetNext (Apos);
		POSITION	Ipos = Area.m_ObjIdxList.GetHeadPosition ();
		while (Ipos) {
			CObjIndexData	&Idx =
				*(CObjIndexData*) Area.m_ObjIdxList.GetNext (Ipos);
			if (! nifty_is_name (arg, Idx.GetName ()))
				continue;
				
			POSITION	pos = Idx.m_ObjList.GetHeadPosition ();
			while (pos) {
				bFound = TRUE;
				CObjData	&Obj = *Idx.m_ObjList.GetNext (pos);

				char	*pShort = obj_short (&Obj);
				int		ColSiz = GetColorSize (pShort);
				int len = sprintf (buf, "(%3d) [%5d] %-*s in ",
					++icnt, Obj.pIndexData->vnum,
					28 + ColSiz, pShort);

				if (Obj.carried_by)
					sprintf (buf + len, "invent [%5d] %s\n\r",
						(Obj.carried_by->IsNpc ()
						? Obj.carried_by->GetMobIndex ()->vnum : 0),
						PERS (Obj.carried_by, ch));

				else if (Obj.in_room)
					sprintf (buf + len, "room   [%5d] %s\n\r",
						Obj.in_room->vnum, Obj.in_room->GetName ());

				else if (Obj.in_obj)
					sprintf (buf + len, "object [%5d] %s\n\r",
						Obj.in_obj->pIndexData->vnum, obj_short (Obj.in_obj));
				else {
					bug ("do_owhere: object doesn't have location!");
					strcat (buf, "nowhere??\n\r");
				}
				send_to_pager (buf, ch);
			}
		}
	}

	if (! bFound)
		act (AT_PLAIN, "You didn't find any $T.", ch, NULL, arg, TO_CHAR);
	else
		pager_printf (ch, "%d matches.\n\r", icnt);
}


void do_reboo (CCharacter *ch, char *argument)
{
    ch->SendText ("If you want to REBOOT, spell it out.\n\r");
    return;
}



void do_reboot (CCharacter *ch, char *argument)
{
	char		buf [MAX_STRING_LENGTH];
	CCharacter	*vch;

	if (str_cmp (argument, "mud now") && str_cmp (argument, "nosave")
	  && str_cmp (argument, "and sort skill table")) {
		ch->SendText ("Syntax: 'reboot mud now' or 'reboot nosave'\n\r");
		return;
	}

	if (auction->IsActive ())
		do_auction (ch, "stop");

	sprintf (buf, "Reboot by %s.", ch->GetName ());
	do_echo (ch, buf);

	if (!str_cmp (argument, "and sort skill table")) {
		SkillTable.Sort ();
		save_skill_table ();
	}

	// Save all characters before booting.
	if (str_cmp (argument, "nosave"))
		for (vch = first_char; vch; vch = vch->GetNext ())
			if (! vch->IsNpc ())
				save_char_obj (vch);

	gpDoc->SetReboot ();
	gpDoc->ShutSmaugDown ();
}


void do_shutdow (CCharacter *ch, char *argument)
{
	ch->SendText ("If you want to SHUTDOWN, spell it out.\n\r");
}



void do_shutdown (CCharacter *ch, char *argument)
{
	char		buf [MAX_STRING_LENGTH];
	CCharacter	*vch;

	if (str_cmp (argument, "mud now") && str_cmp (argument, "nosave")) {
		ch->SendText ("Syntax: 'shutdown mud now' or 'shutdown nosave'\n\r");
		return;
	}

	if (auction->IsActive ())
		do_auction (ch, "stop");

	sprintf (buf, "Shutdown by %s.", ch->GetName ());
	append_file (ch, FileTable.GetName (SM_SHUTDOWN_FILE), buf);
	strcat (buf, "\n\r");
	do_echo (ch, buf);

	// Save all characters before booting.
	if (str_cmp (argument, "nosave"))
		for (vch = first_char; vch; vch = vch->GetNext ())
			if (!vch->IsNpc ())
				save_char_obj (vch);

	gpDoc->ShutSmaugDown ();
}


void do_snoop (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CDescriptor	*d;
	CCharacter	*victim;

	one_argument (argument, arg);

	if (arg[0] == '\0') {
		ch->SendText ("Snoop whom?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (!victim->GetDesc ()) {
		ch->SendText ("No descriptor to snoop.\n\r");
		return;
	}

	if (victim == ch) {
		ch->SendText ("Cancelling all snoops.\n\r");
		POSITION	pos = DList.GetHeadPosition ();
		while (pos) {
			CDescriptor	&Ds = *DList.GetNext (pos);
			if (Ds.m_pSnoopBy == ch->GetDesc ())
				Ds.m_pSnoopBy = NULL;
		}
		return;
	}

	if (victim->GetDesc ()->m_pSnoopBy) {
		ch->SendText ("Busy already.\n\r");
		return;
	}

	// Minimum snoop level... a secret mset value
	// makes the snooper think that the victim is already being snooped
	if (victim->GetTrustLevel () >= ch->GetTrustLevel ()
	  || (victim->GetPcData ()
	  && victim->GetPcData ()->min_snoop > ch->GetTrustLevel ())) {
		ch->SendText ("Busy already.\n\r");
		return;
	}

	if (ch->GetDesc ()) {
		for (d = ch->GetDesc ()->m_pSnoopBy; d; d = d->m_pSnoopBy)
			if (d->m_pCharacter == victim || d->m_pOriginal == victim) {
				ch->SendText ("No snoop loops.\n\r");
				return;
			}
	}

	// Snoop notification for higher imms, if desired, uncomment this
	// if (victim->GetTrustLevel () > LEVEL_GOD && ch->GetTrustLevel () < LEVEL_SUPREME)
	// write_to_descriptor (victim->GetDesc ()->descriptor, "\n\rYou feel like someone is watching your every move...\n\r", 0);
	victim->GetDesc ()->m_pSnoopBy = ch->GetDesc ();
	ch->SendText ("Ok.\n\r");
}


void do_switch (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Switch into whom?\n\r");
		return;
	}

	if (! ch->GetDesc ())
		return;

	if (ch->GetDesc ()->m_pOriginal) {
		ch->SendText ("You are already switched.\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim == ch) {
		ch->SendText ("Ok.\n\r");
		return;
	}

	if (victim->GetDesc ()) {
		ch->SendText ("Character in use.\n\r");
		return;
	}

	if (! victim->IsNpc () && ch->GetLevel () < LEVEL_GREATER) {
		ch->SendText ("You cannot switch into a player!\n\r");
		return;
	}

	ch->GetDesc ()->m_pCharacter = victim;
	ch->GetDesc ()->m_pOriginal  = ch;
	victim->SetDesc (ch->GetDesc ());
	ch->SetDesc (NULL);
	ch->switched	= victim;
	victim->SendText ("Ok.\n\r");
}


void do_return (CCharacter *ch, char *argument)
{
	if (! ch->GetDesc ())
		return;

	if (! ch->GetDesc ()->m_pOriginal) {
		ch->SendText ("You aren't switched.\n\r");
		return;
	}

	if (ch->IsPolymorphed ()) {
		ch->SendText ("Use revert to return from a polymorphed mob.\n\r");
		return;
	}

	ch->SendText ("You return to your original body.\n\r");
	if (ch->IsNpc () && ch->IsPossessed ()) {
		affect_strip (ch, gsn_possess);
		ch->ClrPossessed ();
	}

	// if (IS_NPC (ch->GetDesc ()->m_pCharacter))
	// REMOVE_BIT (ch->GetDesc ()->m_pCharacter->affected_by, AFF_POSSESS);

	ch->GetDesc ()->m_pCharacter = ch->GetDesc ()->m_pOriginal;
	ch->GetDesc ()->m_pOriginal = NULL;
	ch->GetDesc ()->m_pCharacter->SetDesc (ch->GetDesc ());
	ch->GetDesc ()->m_pCharacter->switched = NULL;
	ch->SetDesc (NULL);
}


void do_minvoke (CCharacter *ch, char *argument)
{
	char			arg[MAX_INPUT_LENGTH];
	CMobIndexData	*pMobIndex;
	CCharacter		*victim;
	int				vnum;

	one_argument (argument, arg);

	if (arg[0] == '\0') {
		ch->SendText ("Syntax: minvoke <vnum>.\n\r");
		return;
	}

	if (!is_number (arg)) {
		char	arg2 [MAX_INPUT_LENGTH];
		int		hash, cnt;
		int		count = number_argument (arg, arg2);

		vnum = -1;
		for (hash = cnt = 0; hash < MAX_KEY_HASH; hash++)
			for (pMobIndex = MobTable.GetFirstByHash (hash); pMobIndex; pMobIndex = pMobIndex->GetNext ())
				if (nifty_is_name (arg2, pMobIndex->GetPlayerName ())
				  && ++cnt == count) {
					vnum = pMobIndex->vnum;
					break;
				}
			if (vnum == -1) {
				ch->SendText ("No such mobile exists.\n\r");
				return;
			}
	}
	else vnum = atoi (arg);

	if (ch->GetTrustLevel () < LEVEL_DEMI) {
		CAreaData	&Area = *ch->GetArea ();

		if (ch->IsNpc ()) {
			ch->SendText ("Huh?\n\r");
			return;
		}

		if (! ch->GetArea ()) {
			ch->SendText ("You must have an assigned area to invoke "
				"this mobile.\n\r");
			return;
		}
		if (vnum < Area.low_m_vnum && vnum > Area.hi_m_vnum) {
			ch->SendText ("That number is not in your allocated range.\n\r");
			return;
		}
	}

	if ((pMobIndex = MobTable.GetMob (vnum)) == NULL) {
		ch->SendText ("No mobile has that vnum.\n\r");
		return;
	}

	victim = create_mobile (pMobIndex);
	victim->SendToRoom (ch->GetInRoom ());
	act (AT_IMMORT, "$n has created $N!", ch, NULL, victim, TO_ROOM);
	ch->SendText ("Ok.\n\r");
}


void do_oinvoke (CCharacter *ch, char *argument)
{
	char			arg1 [MAX_INPUT_LENGTH];
	char			arg2 [MAX_INPUT_LENGTH];
	CObjIndexData	*pObjIndex;
	CObjData		*obj;
	int				vnum;
	int				level;

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

	if (arg1 [0] == '\0') {
		ch->SendText ("Syntax: oinvoke <vnum> <level>.\n\r");
		return;
	}

	if (arg2 [0] == '\0') {
		level = ch->GetTrustLevel ();
	} else {
		if (! is_number (arg2)) {
			ch->SendText ("Syntax: oinvoke <vnum> <level>.\n\r");
			return;
		}
		level = atoi (arg2);
		if (level < 0 || level > ch->GetTrustLevel ()) {
			ch->SendText ("Limited to your trust level.\n\r");
			return;
		}
	}

	if (! is_number (arg1)) {
		char	arg [MAX_INPUT_LENGTH];
		int		hash, cnt;
		int		count = number_argument (arg1, arg);

		vnum = -1;
		for (hash = cnt = 0; hash < MAX_KEY_HASH; hash++) {
			pObjIndex = OIdxTable.GetFirstByHash (hash);
			for (; pObjIndex; pObjIndex = pObjIndex->GetNext ())
				if (nifty_is_name (arg, pObjIndex->GetName ())
				  && ++cnt == count) {
					vnum = pObjIndex->vnum;
					break;
				}
		}
		if (vnum == -1) {
			ch->SendText ("No such object exists.\n\r");
			return;
		}
	}
	else vnum = atoi (arg1);

	if (ch->GetTrustLevel () < LEVEL_DEMI) {
		if (ch->IsNpc ()) {
			ch->SendText ("Huh?\n\r");
			return;
		}

		CAreaData	*pArea = ch->GetArea ();

		if (! pArea) {
			ch->SendText (
				"You must have an assigned area to invoke this object.\n\r");
			return;
		}

		if (vnum < pArea->low_o_vnum && vnum > pArea->hi_o_vnum) {
			ch->SendText ("That number is not in your allocated range.\n\r");
			return;
		}
	}

	if ((pObjIndex = OIdxTable.Find (vnum)) == NULL) {
		ch->SendText ("No object has that vnum.\n\r");
		return;
	}

	obj = create_object (pObjIndex, level);
		if (obj->CanWear (ITEM_TAKE)) {
			obj = obj_to_char (obj, ch);
		} else {
			obj = obj_to_room (obj, ch->GetInRoom ());
			act (AT_IMMORT, "$n has created $p!", ch, obj, NULL, TO_ROOM);
	}
	ch->SendText ("Ok.\n\r");
}


void do_purge (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;
	CObjData	*obj;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		// purge room
		CCharacter	*vnext;

		for (victim = ch->GetInRoom ()->first_person; victim; victim = vnext){
			vnext = victim->GetNextInRoom ();
			if (victim->IsNpc () && victim != ch && !victim->IsPolymorphed ())
				extract_char (victim, TRUE);
		}

		POSITION	pos = ch->GetInRoom ()->GetHeadContentPos ();
		while (pos)
			extract_obj (ch->GetInRoom ()->GetNextContent (pos));

		act (AT_IMMORT, "$n purges the room!", ch, NULL, NULL, TO_ROOM);
		ch->SendText ("Ok.\n\r");
		return;
	}

	victim = NULL; obj = NULL;

	// fixed to get things in room first -- i.e., purge portal  (obj),
	// no more purging mobs with that keyword in another room first
	// -- Tri */
	if ((victim = get_char_room (ch, arg)) == NULL 
	  && (obj = get_obj_here (ch, arg)) == NULL) {
		if ((victim = get_char_world (ch, arg)) == NULL
		  && (obj = get_obj_world (ch, arg)) == NULL) {	// no get_obj_room
			ch->SendText ("They aren't here.\n\r");
			return;
		}
	}

	// Single object purge in room for high level purge - Scryn 8/12
	if (obj) {
		separate_obj (obj);
		act (AT_IMMORT, "$n purges $p.", ch, obj, NULL, TO_ROOM);
		act (AT_IMMORT, "You make $p disappear in a puff of smoke!",
			ch, obj, NULL, TO_CHAR);          
		extract_obj (obj);
		return;
	}


	if (! victim->IsNpc ()) {
		ch->SendText ("Not on PC's.\n\r");
		return;
	}

	if (victim == ch) {
		ch->SendText ("You cannot purge yourself!\n\r");
		return;
	}

	if (victim->IsPolymorphed ()) {
		ch->SendText ("You cannot purge a polymorphed player.\n\r");
		return;
	}

	act (AT_IMMORT, "$n purges $N.", ch, NULL, victim, TO_NOTVICT);
	extract_char (victim, TRUE);
}


void do_low_purge (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;
	CObjData	*obj;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Purge what?\n\r");
		return;
	}

	victim = NULL; obj = NULL;
	if ((victim = get_char_room (ch, arg)) == NULL
	  && (obj = get_obj_here  (ch, arg)) == NULL) {
		ch->SendText ("You can't find that here.\n\r");
		return;
	}

	if (obj) {
		separate_obj (obj);
		act (AT_IMMORT, "$n purges $p!", ch, obj, NULL, TO_ROOM);
		act (AT_IMMORT, "You make $p disappear in a puff of smoke!",
			ch, obj, NULL, TO_CHAR);
		extract_obj (obj);
		return;
	}

	if (! victim->IsNpc ()) {
		ch->SendText ("Not on PC's.\n\r");
		return;
	}

	if (victim == ch) {
		ch->SendText ("You cannot purge yourself!\n\r");
		return;
	}

	act (AT_IMMORT, "$n purges $N.", ch, NULL, victim, TO_NOTVICT);
	act (AT_IMMORT, "You make $N disappear in a puff of smoke!",
		ch, NULL, victim, TO_CHAR);
	extract_char (victim, TRUE);
}


void do_balzhur (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	char		buf [MAX_STRING_LENGTH];
	char		buf2 [MAX_STRING_LENGTH];
	CCharacter	*victim;
	int			sn;

	argument = one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Who is deserving of such a fate?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't playing.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetLevel () >= ch->GetTrustLevel ()) {
		ch->SendText ("I wouldn't even think of that if I were you...\n\r");
		return;
	}

	set_char_color (AT_WHITE, ch);
	ch->SendText ("You summon the demon Balzhur to wreak your wrath!\n\r");
	ch->SendText ("Balzhur sneers at you evilly, then vanishes in a puff of smoke.\n\r");
	set_char_color (AT_IMMORT, victim);
	victim->SendText ("You hear an ungodly sound in the distance that makes your blood run cold!\n\r");
	sprintf (buf, "Balzhur screams, 'You are MINE %s!!!'", victim->GetName ());
	echo_to_all (AT_IMMORT, buf, ECHOTAR_ALL); 
	victim->SetLevel (2);
	victim->SetTrust (0);
	victim->SetExp (2000);
	victim->SetMaxHp (10);
	victim->SetMaxMana (100);
	victim->SetMaxMove (100);
	for (sn = 0; sn < SkillTable.GetCount (); sn++)
		victim->GetPcData ()->learned[sn] = 0;
	victim->SetPractices (0);
	victim->SetHp (victim->GetMaxHp ());
	victim->SetMana (victim->GetMaxMana ());
	victim->SetMove (victim->GetMaxMove ());


	strcpy (buf, FileTable.MakeName (SD_GOD_DIR,
		capitalize (victim->GetName ())));

	if (!remove (buf))
		ch->SendText ("Player's immortal data destroyed.\n\r");
	else if (errno != ENOENT) {
		ch->SendTextf ("Unknown error #%d - %s (immortal data).  Report "
			"to %s.\n\r", errno, strerror (errno), SysData.GetSupremeEntity ());
		sprintf (buf2, "%s balzhuring %s", ch->GetName (), buf);
		perror (buf2);
	}

	strcpy (buf, capitalize (arg));
	CAreaData	*pArea = BuildList.FindByAuthor (buf);

	if (pArea) {
		if (pArea->IsLoaded ())
			fold_area (pArea, FA_BUILD);
		close_area (pArea);

		CString	Fname = FileTable.MakeBuildName (buf);
		CString	Bname = FileTable.MakeBackupName (Fname);
		remove (Bname);
		set_char_color (AT_RED, ch);	// Log message changes colors
		if (! rename (Fname, Bname))
			ch->SendText ("Player's area data destroyed.  Area saved "
				"as backup.\n\r");
		else if (errno != ENOENT) {
			ch->SendTextf ("Unknown error #%d - %s  (area data).  "
				"Report to %s.\n\r", errno, strerror (errno),
				SysData.GetSupremeEntity ());
			sprintf (buf2, "%s destroying %s", ch->GetName (), buf);
			perror (buf2);   
		}
	}


	make_wizlist ();
	advance_level (victim);
	do_help (victim, "M_BALZHUR_");
	set_char_color (AT_WHITE, victim);
	victim->SendText ("You awake after a long period of time...\n\r");
	while (victim->IsCarrying ())
		extract_obj (victim->GetFirstCarrying ());
}


void do_advance (CCharacter *ch, char *argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	CCharacter	*victim;
	int			level;
	int			iLevel;

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

	if (arg1 [0] == '\0' || arg2 [0] == '\0' || !is_number (arg2)) {
		ch->SendText ("Syntax: advance <char> <level>.\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg1)) == NULL) {
		ch->SendText ("That player is not here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (! victim->IsAuthed ()) {
		ch->SendText ("Player is not yet authorized.\r\n");
		return;
	}

	// You can demote yourself but not someone else
	// at your own trust. -- Narn
	if (ch->GetTrustLevel () <= victim->GetTrustLevel () && ch != victim) {
		ch->SendText ("You can't do that.\n\r");
		return;
	}

	if ((level = atoi (arg2)) < 1 || level > MAX_LEVEL) {
		ch->SendTextf ("Level must be 1 to %d.\n\r", MAX_LEVEL);
		return;
	}

	if (level > ch->GetTrustLevel ()) {
		ch->SendText ("Limited to your trust level.\n\r");
		return;
	}

	// Lower level:
	//   Reset to level 1.
	//   Then raise again.
	//   Currently, an imp can lower another imp.
	//  -- Swiftest
	if (level <= victim->GetLevel ()) {
		int		sn;

		ch->SendText ("Lowering a player's level!\n\r");
		set_char_color (AT_IMMORT, victim);
		victim->SendText ("Cursed and forsaken! The gods have lowered your level.\n\r");
		victim->SetLevel (1);
		victim->SetExp (exp_level (victim, 1));
		victim->SetMaxHp (10);
		victim->SetMaxMana (100);
		victim->SetMaxMove (100);

		for (sn = 0; sn < SkillTable.GetCount (); sn++)
			victim->GetPcData ()->learned [sn] = 0;

		victim->SetPractices (0);
		victim->SetHp (victim->GetMaxHp ());
		victim->SetMana (victim->GetMaxMana ());
		victim->SetMove (victim->GetMaxMove ());
		advance_level (victim);

		// Rank fix added by Narn.
		delete victim->GetPcData ()->GetRank ();
		victim->GetPcData ()->SetRank (str_dup (""));

		// Make sure players wizinvis level doesnt stay higher 
		// than their actual level. Take wizinvis away from advance
		// below 50
		if (victim->IsWizInvis ())
			victim->GetPcData ()->wizinvis = victim->GetTrust ();

		if (victim->IsWizInvis () && (victim->GetLevel () <= LEVEL_AVATAR)) {
			victim->ClrWizInvis ();
			victim->GetPcData ()->wizinvis = victim->GetTrust ();
		}   
	} else {
		ch->SendText ("Raising a player's level!\n\r");
		if (victim->GetLevel () >= LEVEL_AVATAR) {
			set_char_color (AT_IMMORT, victim);
			act (AT_IMMORT, "$n makes some arcane gestures with $s hands, "
				"then points $s finger at you!", ch, NULL, victim, TO_VICT);
			act (AT_IMMORT, "$n makes some arcane gestures with $s hands, "
				"then points $s finger at $N!", ch, NULL, victim, TO_NOTVICT);
			set_char_color (AT_WHITE, victim);
			victim->SendText ("You suddenly feel very strange...\n\r\n\r");
			set_char_color (AT_LBLUE, victim);
		}

		switch (level) {
		  default:
			victim->SendText ("The gods feel fit to raise your level!\n\r");
			break;
		  case LEVEL_IMMORTAL:
			do_help (victim, "M_GODLVL1_");
			set_char_color (AT_WHITE, victim);
			victim->SendText ("You awake... all your possessions are gone.\n\r");

			while (victim->IsCarrying ())
				extract_obj (victim->GetFirstCarrying ());
			break;
		  case LEVEL_ACOLYTE:
			do_help (victim, "M_GODLVL2_");
			break;
		  case LEVEL_CREATOR:
			do_help (victim, "M_GODLVL3_");
			break;
		  case LEVEL_SAVIOR:
			do_help (victim, "M_GODLVL4_");
			break;
		  case LEVEL_DEMI:
			do_help (victim, "M_GODLVL5_");
			break;
		  case LEVEL_TRUEIMM:
			do_help (victim, "M_GODLVL6_");
			break;
		  case LEVEL_LESSER:
			do_help (victim, "M_GODLVL7_");
			break;
		  case LEVEL_GOD:
			do_help (victim, "M_GODLVL8_");
			break;
		  case LEVEL_GREATER:
			do_help (victim, "M_GODLVL9_");
			break;
		  case LEVEL_ASCENDANT:
			do_help (victim, "M_GODLVL10_");
			break;
		  case LEVEL_SUB_IMPLEM:
			do_help (victim, "M_GODLVL11_");
			break;
		  case LEVEL_IMPLEMENTOR:
			do_help (victim, "M_GODLVL12_");
			break;
		  case LEVEL_ETERNAL:
			do_help (victim, "M_GODLVL13_");
			break;
		  case LEVEL_INFINITE:
			do_help (victim, "M_GODLVL14_");
			break;
		  case LEVEL_SUPREME:
			do_help (victim, "M_GODLVL15_");
			break;
		}
	}

	for (iLevel = victim->GetLevel () ; iLevel < level; ++iLevel) {
		if (level < LEVEL_IMMORTAL)
			victim->SendText ("You raise a level!!\n\r");
		victim->AddLevel (1);
		advance_level (victim);
	}
	victim->SetExp (exp_level (victim, victim->GetLevel ()));
	victim->SetTrust (0);
}


void do_elevate (CCharacter* ch, char* argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	set_char_color (AT_IMMORT, ch);

	argument = one_argument (argument, arg);
	if (arg [0] == '\0') {
		ch->SendText ("Syntax: elevate <char>\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg)) == NULL) {
		ch->SendText ("That player is not here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetLevel () == LEVEL_IMMORTAL) {
		ch->SendText ("Elevating a player...\n\r");
		set_char_color (AT_IMMORT, victim);
		act (AT_IMMORT,
			"$n begins to chant softly... then makes some arcane gestures...",
			ch, NULL, NULL, TO_ROOM );
		set_char_color (AT_WHITE, victim);
		victim->SendText ("You suddenly feel very strange...\n\r\n\r");
		set_char_color (AT_LBLUE, victim);
		do_help (victim, "M_GODLVL2_");
		victim->SetLevel (LEVEL_ACOLYTE);
		set_char_color (AT_WHITE, victim);
		advance_level (victim);
		victim->SetExp (exp_level (victim, victim->GetLevel ()));
		victim->SetTrust (0);
		return;
	}

	if (victim->GetLevel () == LEVEL_ACOLYTE) {
		ch->SendText ("Elevating a player...\n\r");
		set_char_color (AT_IMMORT, victim);
		act (AT_IMMORT,
			"$n begins to chant softly... then makes some arcane gestures...",
			ch, NULL, NULL, TO_ROOM);
		set_char_color (AT_WHITE, victim);
		victim->SendText ("You suddenly feel very strange...\n\r\n\r");
		set_char_color (AT_LBLUE, victim);
		do_help (victim, "M_GODLVL3_"); 
		victim->SetLevel (LEVEL_CREATOR);  
		set_char_color (AT_WHITE, victim);
		advance_level (victim);
		victim->SetExp (exp_level (victim, victim->GetLevel ()));
		victim->SetTrust (0);
		return;
	}
	else
		ch->SendText ("You cannot elevate this character.\n\r");
}


void do_immortalize (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	argument = one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Syntax: immortalize <char>\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg)) == NULL) {
		ch->SendText ("That player is not here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetLevel () != LEVEL_AVATAR) {
		ch->SendText ("This player is not worthy of immortality yet.\n\r");
		return;
	}

	ch->SendText ("Immortalizing a player...\n\r");
	set_char_color (AT_IMMORT, victim);
	act (AT_IMMORT,
		"$n begins to chant softly... then raises $s arms to the sky...",
		ch, NULL, NULL, TO_ROOM);
	set_char_color (AT_WHITE, victim);
	victim->SendText ("You suddenly feel very strange...\n\r\n\r");
	set_char_color (AT_LBLUE, victim);

	do_help (victim, "M_GODLVL1_");
	set_char_color (AT_WHITE, victim);
	victim->SendText ("You awake... all your possessions are gone.\n\r");

	while (victim->IsCarrying ())
		extract_obj (victim->GetFirstCarrying ());

	victim->SetLevel (LEVEL_IMMORTAL);
	advance_level (victim);

	victim->SetExp (exp_level (victim, victim->GetLevel ()));
	victim->SetTrust (0);
}


void do_trust (CCharacter *ch, char *argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	CCharacter	*victim;
	int			level;

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

	if (arg1 [0] == '\0' || arg2 [0] == '\0' || ! is_number (arg2)) {
		ch->SendText ("Syntax: trust <char> <level>.\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg1)) == NULL) {
		ch->SendText ("That player is not here.\n\r");
		return;
	}

	if ((level = atoi (arg2)) < 0 || level > MAX_LEVEL) {
		ch->SendText ("Level must be 0  (reset) or 1 to 60.\n\r");
		return;
	}

	if (level > ch->GetTrustLevel ()) {
		ch->SendText ("Limited to your own trust.\n\r");
		return;
	}

	if (victim->GetTrustLevel () >= ch->GetTrustLevel ()) {
		ch->SendText ("You can't do that.\n\r");
		return;
	}

	victim->SetTrust (level);
	ch->SendText ("Ok.\n\r");
}


void do_restore (CCharacter *ch, char *argument)
{
	char	arg [MAX_INPUT_LENGTH];

	one_argument (argument, arg);
	if (arg [0] == '\0') {
		ch->SendText ("Restore whom?\n\r");
		return;
	}

	if (! str_cmp (arg, "all")) {
		CCharacter	*vch;
		CCharacter	*vch_next;

		if (! ch->GetPcData ())
			return;

		if (ch->GetTrustLevel () < LEVEL_SUB_IMPLEM) {
			if (ch->IsNpc ()) {
				ch->SendText ("You can't do that.\n\r");
				return;
			}
			// Check if the player did a restore all
			// within the last 18 hours.
			if ((CurrentTime - LastRestoreAllTime).GetTotalSeconds () < 
			  RESTORE_INTERVAL) {
				ch->SendText ("Sorry, you can't do a restore all yet.\n\r"); 
				do_restoretime (ch, "");
				return;
			}
		}
		LastRestoreAllTime = CurrentTime;
		ch->GetPcData ()->restore_time = CurrentTime;
		save_char_obj (ch);
		ch->SendText ("Ok.\n\r");

		for (vch = first_char; vch; vch = vch_next) {
			vch_next = vch->GetNext ();

			if (! vch->IsNpc () && vch->IsMortal ()  
			  && ! vch->CanPkill () && !in_arena (vch)) {
				vch->SetHp (vch->GetMaxHp ());
				vch->SetMana (vch->GetMaxMana ());
				vch->SetMove (vch->GetMaxMove ());
				vch->GetPcData ()->condition[COND_BLOODTHIRST] =
					(10 + vch->GetLevel ());
				update_pos  (vch);
				act (AT_IMMORT, "$n has restored you.", ch, NULL, vch, TO_VICT);
			}
		}
	} else {    
		CCharacter	*victim;

		if ((victim = get_char_world (ch, arg)) == NULL) {
			ch->SendText ("They aren't here.\n\r");
			return;
		}

		if (ch->GetTrustLevel () < LEVEL_LESSER &&  victim != ch
		  && ! (victim->IsNpc () && victim->IsAction (ACT_PROTOTYPE))) { 
			ch->SendText ("You can't do that.\n\r");
			return;
		}

		victim->SetHp (victim->GetMaxHp ());
		victim->SetMana (victim->GetMaxMana ());
		victim->SetMove (victim->GetMaxMove ());
		if (victim->GetPcData ())
			victim->GetPcData ()->condition[COND_BLOODTHIRST] =
				(10 + victim->GetLevel ());
		update_pos (victim);

		if (ch != victim)
			act (AT_IMMORT, "$n has restored you.", ch, NULL, victim, TO_VICT);
		ch->SendText ("Ok.\n\r");
	}
}


void do_restoretime (CCharacter *ch, char *argument)
{
	CTimeSpan	TimePassed;

	if (LastRestoreAllTime.IsZero ())
		ch->SendTextf ("There has been no restore all since reboot\n\r");

	else {
		TimePassed = CurrentTime - LastRestoreAllTime;
		ch->SendTextf (
			"The  last restore all was %d hours and %d minutes ago.\n\r", 
			TimePassed.GetHours (), TimePassed.GetMinutes ());
	}

	if (! ch->GetPcData ())
		return;

	if (ch->GetPcData ()->restore_time.IsZero ()) {
		ch->SendText ("You have never done a restore all.\n\r");
		return;
	}

	TimePassed = CurrentTime - ch->GetPcData ()->restore_time;
	ch->SendTextf (
		"Your last restore all was %d hours and %d minutes ago.\n\r", 
		TimePassed.GetHours (), TimePassed.GetMinutes ()); 
}


void do_freeze (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Freeze whom?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetTrustLevel () >= ch->GetTrustLevel ()) {
		ch->SendText ("You failed.\n\r");
		return;
	}

	if (victim->IsFrozen ()) {
		victim->ClrFrozen ();
		victim->SendText ("You can play again.\n\r");
		ch->SendText ("FREEZE removed.\n\r");
	} else {
		victim->SetFrozen ();
		victim->SendText ("You can't do ANYthing!\n\r");
		ch->SendText ("FREEZE set.\n\r");
	}

	save_char_obj (victim);
}


void do_log (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Log whom?\n\r");
		return;
	}

	if (! str_cmp (arg, "all")) {
		if (fLogAll) {
			fLogAll = FALSE;
			ch->SendText ("Log ALL off.\n\r");
		} else {
			fLogAll = TRUE;
			ch->SendText ("Log ALL on.\n\r");
		}
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	// No level check, gods can log anyone.
	if (victim->IsLogged ()) {
		victim->ClrLogged ();
		ch->SendText ("LOG removed.\n\r");
	} else {
		victim->SetLogged ();
		ch->SendText ("LOG set.\n\r");
	}
}


void do_litterbug (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Set litterbug flag on whom?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetTrustLevel () >= ch->GetTrustLevel ()) {
		ch->SendText ("You failed.\n\r");
		return;
	}

	if (victim->IsAction (PLR_LITTERBUG)) {
		victim->ClrActBit (PLR_LITTERBUG);
		victim->SendText ("You can drop items again.\n\r");
		ch->SendText ("LITTERBUG removed.\n\r");
	} else {
		victim->SetActBit (PLR_LITTERBUG);
		victim->SendText ("A strange force prevents you from dropping "
			"any more items!\n\r");
		ch->SendText ("LITTERBUG set.\n\r");
	}
}


void do_noemote (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Noemote whom?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetTrustLevel () >= ch->GetTrustLevel ()) {
		ch->SendText ("You failed.\n\r");
		return;
	}

	if (victim->IsAction (PLR_NO_EMOTE)) {
		victim->ClrActBit (PLR_NO_EMOTE);
		victim->SendText ("You can emote again.\n\r");
		ch->SendText ("NO_EMOTE removed.\n\r");
	} else {
		victim->SetActBit (PLR_NO_EMOTE);
		victim->SendText ("You can't emote!\n\r");
		ch->SendText ("NO_EMOTE set.\n\r");
	}
}


void do_notell (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Notell whom?");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetTrustLevel () >= ch->GetTrustLevel ()) {
		ch->SendText ("You failed.\n\r");
		return;
	}

	if (victim->IsAction (PLR_NO_TELL)) {
		victim->ClrActBit (PLR_NO_TELL);
		victim->SendText ("You can tell again.\n\r");
		ch->SendText ("NO_TELL removed.\n\r");
	} else {
		victim->SetActBit (PLR_NO_TELL);
		victim->SendText ("You can't tell!\n\r");
		ch->SendText ("NO_TELL set.\n\r");
	}
}


void do_notitle (CCharacter *ch, char *argument)
{
	char		buf [MAX_STRING_LENGTH];
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Notitle whom?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetTrustLevel () >= ch->GetTrustLevel ()) {
		ch->SendText ("You failed.\n\r");
		return;
	}

	if (victim->IsNoTitle ()) {
		victim->ClrNoTitle ();
		victim->SendText ("You can set your own title again.\n\r");
		ch->SendText ("NOTITLE removed.\n\r");
	} else {
		victim->SetNoTitle ();
		sprintf (buf, "the %s", ClassTable.GetTitle (victim->GetClass (),
			victim->GetLevel (), victim->GetSex () == SEX_FEMALE ? 1 : 0));
		set_title (victim, buf);   
		victim->SendText ("You can't set your own title!\n\r");
		ch->SendText ("NOTITLE set.\n\r");
	}
}


void do_silence (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Silence whom?");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetTrustLevel () >= ch->GetTrustLevel ()) {
		ch->SendText ("You failed.\n\r");
		return;
	}

	if (victim->IsAction (PLR_SILENCE)) {
		ch->SendText ("Player already silenced, use unsilence to remove.\n\r");
	} else {
		victim->SetActBit (PLR_SILENCE);
		victim->SendText ("You can't use channels!\n\r");
		ch->SendText ("SILENCE set.\n\r");
	}
}


void do_unsilence (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CCharacter	*victim;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Unsilence whom?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if (victim->GetTrustLevel () >= ch->GetTrustLevel ()) {
		ch->SendText ("You failed.\n\r");
		return;
	}

	if (victim->IsAction (PLR_SILENCE)) {
		victim->ClrActBit (PLR_SILENCE);
		victim->SendText ("You can use channels again.\n\r");
		ch->SendText ("SILENCE removed.\n\r");
	}
	else ch->SendText ("That player is not silenced.\n\r");
}


void do_peace (CCharacter *ch, char *argument)
{
	act (AT_IMMORT, "$n booms, 'PEACE!'", ch, NULL, NULL, TO_ROOM);

	CCharacter	*rch = ch->GetInRoom ()->first_person;

	while (rch) {
		if (rch->GetFightData ()) {
			stop_fighting (rch, TRUE);
			do_sit (rch, "");
		}

		// Added by Narn, Nov 28/95
		stop_hating (rch);
		stop_hunting (rch);
		stop_fearing (rch);

		rch = rch->GetNextInRoom ();
	}

	ch->SendText ("Ok.\n\r");
}



CBanData *		first_ban;
CBanData *		last_ban;

void save_banlist ()
{
	CBanData	*pban;
	FILE		*fp;

	fclose (fpReserve);
	if (! (fp = fopen (FileTable.GetName (SM_BAN_LIST), "w"))) {
		bug ("Save_banlist: Cannot open %s" BAN_LIST, BAN_LIST);
		fpReserve = fopen (FileTable.GetName (SM_NULL_FILE), "r");
		return;
	}
	for (pban = first_ban; pban; pban = pban->GetNext ())
		fprintf (fp, "%d %s~~%s~\n", pban->level, pban->name, pban->ban_time);
	fprintf (fp, "-1\n");
	fclose (fp);
	fpReserve = fopen (FileTable.GetName (SM_NULL_FILE), "r");
}


void do_ban (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	CBanData	*pban;
	int			bnum;

	if (ch->IsNpc ())
		return;

	argument = one_argument (argument, arg);

	set_pager_color (AT_PLAIN, ch);
	if (arg [0] == '\0') {
		send_to_pager ("Banned sites:\n\r", ch);
		send_to_pager ("[ #]  (Lv) Time                     Site\n\r", ch);
		send_to_pager ("---- ---- ------------------------ "
			"---------------\n\r", ch);
		for (pban=first_ban, bnum = 1; pban; pban = pban->GetNext (), bnum++)
			pager_printf (ch, "[%2d]  (%2d) %s %s\n\r", bnum,
				pban->level, pban->ban_time, pban->name);
		return;
	}

	// People are gonna need .# instead of just # to ban by just last
	// number in the site ip.                               -- Altrag
	if (is_number (arg)) {
		for (pban=first_ban, bnum = 1; pban; pban = pban->GetNext (), bnum++)
			if (bnum == atoi (arg))
				break;
		if (! pban) {
			do_ban (ch, "");
			return;
		}
		argument = one_argument (argument, arg);
		if (arg [0] == '\0') {
			do_ban (ch, "help");
			return;
		}
		if (!str_cmp (arg, "level")) {
			argument = one_argument (argument, arg);
			if (arg[0] == '\0' || !is_number (arg)) {
				do_ban (ch, "help");
				return;
			}
			if (atoi (arg) < 1 || atoi (arg) > LEVEL_SUPREME) {
				ch->SendTextf ("Level range: 1 - %d.\n\r", LEVEL_SUPREME);
				return;
			}
			pban->level = atoi (arg);
			ch->SendText ("Ban level set.\n\r");
		}
		else if (!str_cmp (arg, "newban")) {
			pban->level = 1;
			ch->SendText ("New characters banned.\n\r");
		}
		else if (!str_cmp (arg, "mortal")) {
			pban->level = LEVEL_AVATAR;
			ch->SendText ("All mortals banned.\n\r");
		}
		else if (!str_cmp (arg, "total")) {
			pban->level = LEVEL_SUPREME;
			ch->SendText ("Everyone banned.\n\r");
		} else {
			do_ban (ch, "help");
			return;
		}
		save_banlist ();
		return;
	}

	if (!str_cmp (arg, "help")) {
		ch->SendText ("Syntax: ban <site address>\n\r");
		ch->SendText ("Syntax: ban <ban number> <level <lev>|newban|mortal|"
			"total>\n\r");
		return;
	}

	for (pban = first_ban; pban; pban = pban->GetNext ()) {
		if (!str_cmp (arg, pban->name)) {
			ch->SendText ("That site is already banned!\n\r");
			return;
		}
	}

	pban = new CBanData;
	LINK (pban, first_ban, last_ban);
	pban->name = str_dup (arg);
	pban->level = LEVEL_AVATAR;
	pban->ban_time = str_dup (CurrentTime.GetString ());
	save_banlist ();
	ch->SendText ("Ban created.  Mortals banned from site.\n\r");
}


void do_allow (CCharacter *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    CBanData *pban;

    one_argument (argument, arg);

    if (arg[0] == '\0')
    {
	ch->SendText ("Remove which site from the ban list?\n\r");
	return;
    }

    for (pban = first_ban; pban; pban = pban->GetNext ())
    {
	if (!str_cmp (arg, pban->name))
	{
	    UNLINK (pban, first_ban, last_ban);
	    if (pban->ban_time)
	      delete pban->ban_time;
	    delete pban->name;
	    delete pban;
	    save_banlist ();
	    ch->SendText ("Site no longer banned.\n\r");
	    return;
	}
    }

    ch->SendText ("Site is not banned.\n\r");
    return;
}



void do_wizlock (CCharacter *ch, char *argument)
{
    extern BOOL wizlock;
    wizlock = !wizlock;

    if (wizlock)
	ch->SendText ("Game wizlocked.\n\r");
    else
	ch->SendText ("Game un-wizlocked.\n\r");

    return;
}


void do_noresolve (CCharacter *ch, char *argument)
{
	SysData.bNameResolving = !SysData.bNameResolving;

	ch->SendText (SysData.bNameResolving ?
		"Name resolving enabled.\n\r" : "Name resolving disabled.\n\r");
}


void do_users (CCharacter *ch, char *argument)
{
	char buf[MAX_STRING_LENGTH];
	int count;
	char arg[MAX_INPUT_LENGTH];

	one_argument  (argument, arg);
	count	= 0;
	buf[0]	= '\0';

	set_pager_color (AT_PLAIN, ch);
	sprintf (buf, 
	"Desc|Con|Idle| Port | Player@HostIP                 ");
	if (ch->GetTrustLevel () >= LEVEL_GOD)
	strcat (buf, "| Username");
	strcat (buf, "\n\r");
	strcat (buf, "----+---+----+------+-------------------------------");
	if (ch->GetTrustLevel () >= LEVEL_GOD)
	strcat (buf, "+---------");
	strcat (buf, "\n\r");
	send_to_pager (buf, ch);

	POSITION	pos = DList.GetHeadPosition ();
	while (pos) {
		CDescriptor	&Ds = *DList.GetNext (pos);
		if (Ds.IsDisconnecting ())
			continue;

		if (arg [0] == '\0') {     
			if (ch->GetTrustLevel () >= LEVEL_SUPREME
			  || (Ds.m_pCharacter && can_see (ch, Ds.m_pCharacter))) {
				count++;
				sprintf (buf, " %3d| %2d|%4lu|%6d| %-12s%-17s ",
					Ds.m_DescNo, Ds.m_Connected, Ds.m_Idle / 4,
					Ds.port,
					Ds.m_pOriginal ? Ds.m_pOriginal->GetName () :
					Ds.m_pCharacter ? Ds.m_pCharacter->GetName () : "(none)",
					Ds.m_pHost);
				if (ch->GetTrustLevel () >= LEVEL_GOD)
					sprintf (buf + strlen (buf), "| %s", Ds.user);
				strcat (buf, "\n\r");
				send_to_pager (buf, ch);
			}
		} else {
			if ((ch->GetTrustLevel () >= LEVEL_SUPREME
			  || (Ds.m_pCharacter && can_see (ch, Ds.m_pCharacter)))
			  && (Ds.IsHost () && !str_prefix (arg, Ds.m_pHost) 
			  || (Ds.m_pCharacter && !str_prefix (arg, Ds.m_pCharacter->GetName ()))))
			{
				count++;
				pager_printf (ch, " %3d| %2d|%4lu|%6d| %-12s%-17s ",
					Ds.m_DescNo, Ds.m_Connected, Ds.m_Idle / 4, Ds.port,
					Ds.m_pOriginal  ? Ds.m_pOriginal->GetName ()  :
					Ds.m_pCharacter ? Ds.m_pCharacter->GetName () : "(none)",
					Ds.m_pHost);
				buf[0] = '\0';
				if (ch->GetTrustLevel () >= LEVEL_GOD)
					sprintf (buf, "| %s", Ds.user);
				strcat (buf, "\n\r");
				send_to_pager (buf, ch);
			}
		}
    }
	pager_printf (ch, "%d user%s.\n\r", count, count == 1 ? "" : "s");
}



/*
 * Thanks to Grodyn for pointing out bugs in this function.
 */
void do_force (CCharacter *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    BOOL mobsonly; 
    argument = one_argument (argument, arg);

    if (arg[0] == '\0' || argument[0] == '\0')
    {
	ch->SendText ("Force whom to do what?\n\r");
	return;
    }

    mobsonly = ch->GetTrustLevel () < SysData.ForcePcLevel; 

    if (!str_cmp (arg, "all"))
    {
	CCharacter *vch;
	CCharacter *vch_next;

        if (mobsonly)
        {
	  ch->SendText ("Force whom to do what?\n\r");
	  return;
        } 

	for (vch = first_char; vch; vch = vch_next)
	{
	    vch_next = vch->GetNext ();

	    if (!vch->IsNpc () && vch->GetTrustLevel () < ch->GetTrustLevel ())
	    {
		act (AT_IMMORT, "$n forces you to '$t'.", ch, argument, vch, TO_VICT);
		interpret (vch, argument);
	    }
	}
    }
    else
    {
	CCharacter *victim;

	if ((victim = get_char_world (ch, arg)) == NULL)
	{
	    ch->SendText ("They aren't here.\n\r");
	    return;
	}

	if (victim == ch)
	{
	    ch->SendText ("Aye aye, right away!\n\r");
	    return;
	}

	if ((victim->GetTrustLevel () >= ch->GetTrustLevel ()) 
          ||  (mobsonly && !victim->IsNpc ()))
	{
	    ch->SendText ("Do it yourself!\n\r");
	    return;
	}

    act (AT_IMMORT, "$n forces you to '$t'.", ch, argument, victim, TO_VICT);
	interpret (victim, argument);
    }

    ch->SendText ("Ok.\n\r");
    return;
}


void do_invis (CCharacter *ch, char *argument)
{
    char arg[MAX_INPUT_LENGTH];
    short level;
    
    /*
    if (ch->IsNpc ())
	return;
    */

    argument = one_argument (argument, arg);
    if (arg && arg[0] != '\0')
    {
	if (!is_number (arg))
	{
	   ch->SendText ("Usage: invis | invis <level>\n\r");
	   return;
	}
	level = atoi (arg);
	if (level < 2 || level > ch->GetTrustLevel ())
	{
	    ch->SendText ("Invalid level.\n\r");
	    return;
	}

	if (!ch->IsNpc ())
        {
	  ch->GetPcData ()->wizinvis = level;
	  ch->SendTextf ("Wizinvis level set to %d.\n\r", level);
        }
        
        if (ch->IsNpc ())       
        {
          ch->SetMobInvisLevel (level);
          ch->SendTextf ("Mobinvis level set to %d.\n\r", level);
        }
	return;
    }
    
    if (!ch->IsNpc ())
    {
    if (ch->GetPcData ()->wizinvis < 2)
      ch->GetPcData ()->wizinvis = ch->GetLevel ();
    }

    if (ch->IsNpc ())
    {
    if (ch->GetMobInvisLevel () < 2)
      ch->SetMobInvisLevel (ch->GetLevel ());
    }

    if (ch->IsWizInvis ())
    {
	ch->ClrWizInvis ();
	act (AT_IMMORT, "$n slowly fades into existence.", ch, NULL, NULL, TO_ROOM);
	ch->SendText ("You slowly fade back into existence.\n\r");
    }
    else
    {
	ch->SetWizInvis ();
	act (AT_IMMORT, "$n slowly fades into thin air.", ch, NULL, NULL, TO_ROOM);
	ch->SendText ("You slowly vanish into thin air.\n\r");
    }

    return;
}


void do_holylight (CCharacter *ch, char *argument)
{
    if (ch->IsNpc ())
	return;

    if (ch->IsHolyLight ())
    {
	ch->ClrHolyLight ();
	ch->SendText ("Holy light mode off.\n\r");
    }
    else
    {
	ch->SetHolyLight ();
	ch->SendText ("Holy light mode on.\n\r");
    }

    return;
}

void do_rassign (CCharacter *ch, char *argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	char		arg3 [MAX_INPUT_LENGTH];
	int			r_lo, r_hi;
	CCharacter	*victim;

	argument = one_argument (argument, arg1);
	argument = one_argument (argument, arg2);
	argument = one_argument (argument, arg3);
	r_lo = atoi (arg2);
	r_hi = atoi (arg3);

	if (arg1 [0] == '\0' || r_lo < 0 || r_hi < 0) {
		ch->SendText ("Syntax: rassign <who> <low> <high>\n\r");
		return;
	}
	if ((victim = get_char_world (ch, arg1)) == NULL) {
		ch->SendText ("They don't seem to be around.\n\r");
		return;
	}
	if (victim->IsNpc () || victim->GetTrustLevel () < LEVEL_CREATOR) {
		ch->SendText ("They wouldn't know what to do with a room range.\n\r");
		return;
	}
	if (r_lo > r_hi) {
		ch->SendText ("Unacceptable room range.\n\r");
		return;
	}

	if (r_lo == 0)
		r_hi = 0;
	victim->GetPcData ()->r_range_lo = r_lo;
	victim->GetPcData ()->r_range_hi = r_hi;
	assign_area (victim);

	ch->SendText ("Done.\n\r");
	victim->SendTextf (
		"%s has assigned you the room vnum range %d - %d.\n\r",
		ch->GetName (), r_lo, r_hi);
//	assign_area (victim);			// Put back by Thoric on 02/07/96

	CAreaData	&Area = *victim->GetArea ();

	if (! &Area) {
		bug ("rassign: assign_area failed");
		return;
	}

	if (r_lo == 0) {				// Scryn 8/12/95
		Area.ClrLoaded ();
		Area.SetDeleted ();
	} else {
		Area.SetLoaded ();
		Area.ClrDeleted ();
	}
}


void do_oassign (CCharacter *ch, char *argument)
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    char arg3[MAX_INPUT_LENGTH];
    int			o_lo, o_hi;
    CCharacter	*victim;
    
    argument = one_argument (argument, arg1);
    argument = one_argument (argument, arg2);
    argument = one_argument (argument, arg3);
    o_lo = atoi (arg2);  o_hi = atoi (arg3);

    if (arg1[0] == '\0' || o_lo < 0 || o_hi < 0)
    {
	ch->SendText ("Syntax: oassign <who> <low> <high>\n\r");
	return;
    }
    if ((victim = get_char_world (ch, arg1)) == NULL)
    {
	ch->SendText ("They don't seem to be around.\n\r");
	return;
    }
    if (victim->IsNpc () || victim->GetTrustLevel () < LEVEL_SAVIOR)
    {
	ch->SendText ("They wouldn't know what to do with an object range.\n\r");
	return;
    }
    if (o_lo > o_hi)
    {
	ch->SendText ("Unacceptable object range.\n\r");
	return;
    }
    victim->GetPcData ()->o_range_lo = o_lo;
    victim->GetPcData ()->o_range_hi = o_hi;
    assign_area (victim);
    ch->SendText ("Done.\n\r");
    victim->SendTextf ("%s has assigned you the object vnum range %d - %d.\n\r",
		ch->GetName (), o_lo, o_hi);
    return;
}

void do_massign (CCharacter *ch, char *argument)
{
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];
    char arg3[MAX_INPUT_LENGTH];
    int			m_lo, m_hi;
    CCharacter	*victim;
    
    argument = one_argument (argument, arg1);
    argument = one_argument (argument, arg2);
    argument = one_argument (argument, arg3);
    m_lo = atoi (arg2);  m_hi = atoi (arg3);

    if (arg1[0] == '\0' || m_lo < 0 || m_hi < 0)
    {
	ch->SendText ("Syntax: massign <who> <low> <high>\n\r");
	return;
    }
    if ((victim = get_char_world (ch, arg1)) == NULL)
    {
	ch->SendText ("They don't seem to be around.\n\r");
	return;
    }
    if (victim->IsNpc () || victim->GetTrustLevel () < LEVEL_SAVIOR)
    {
	ch->SendText ("They wouldn't know what to do with a monster range.\n\r");
	return;
    }
    if (m_lo > m_hi)
    {
	ch->SendText ("Unacceptable monster range.\n\r");
	return;
    }
    victim->GetPcData ()->m_range_lo = m_lo;
    victim->GetPcData ()->m_range_hi = m_hi;
    assign_area (victim);
    ch->SendText ("Done.\n\r");
    victim->SendTextf ("%s has assigned you the monster vnum range %d - %d.\n\r",
		ch->GetName (), m_lo, m_hi);
    return;
}


void do_cmdtable (CCharacter *ch, char *argument)
{
	int			hash, cnt;
	CCmdType	*cmd;

	set_pager_color (AT_PLAIN, ch);
	send_to_pager ("Commands and Number of Uses This Run\n\r", ch);

	for (cnt = hash = 0; hash < MAX_COMMANDS; ++hash)
		for (cmd = CommandTable.GetCommand (hash); cmd; cmd = cmd->GetNext ()) {
			if ((++cnt) % 4)
				pager_printf (ch,"%-6.6s %4d\t", cmd->GetName (),
					cmd->userec.num_uses);
			else
				pager_printf (ch,"%-6.6s %4d\n\r", cmd->GetName (),
					cmd->userec.num_uses);
		}
}


// Load up a player file
void do_loadup (CCharacter *ch, char *argument)
{
#ifdef XXXX
	char		name [256];
	BOOL		loaded;
	CDescriptor	*d;
	int			old_room_vnum;
	char		buf [MAX_STRING_LENGTH];

	one_argument (argument, name);
	if (name [0] == '\0') {
		ch->SendText ("Usage: loadup <playername>\n\r");
		return;
	}

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

	CString	Fname = FileTable.PlayerName (name);

	if (FileTable.Exists (Fname)) {
		d = new CDescriptor;
		d->m_Connected = CON_GET_NAME;
		d->m_Outsize = 2000;
		d->m_pOutbuf = new char [d->m_Outsize];

		loaded = load_char_obj (d, name, FALSE);
		add_char (d->m_pCharacter);
		old_room_vnum = d->m_pCharacter->GetInRoom ()->vnum;
		d->m_pCharacter->SendToRoom (ch->GetInRoom ());

		if (d->m_pCharacter->GetTrustLevel () >= ch->GetTrustLevel ()) {
			do_say (d->m_pCharacter, "Do *NOT* disturb me again!");
			ch->SendText ("I think you'd better leave that player alone!\n\r");
			d->m_pCharacter->SetDesc (NULL);
			do_quit (d->m_pCharacter, "");
			return;	   
		}
		d->m_pCharacter->SetDesc (NULL);
		d->m_pCharacter->retran = old_room_vnum;
		d->m_pCharacter = NULL;	
		delete [] d->m_pOutbuf;
		delete d;

		ch->SendTextf ("Player %s loaded from room %d.\n\r", capitalize (name),old_room_vnum);
		sprintf (buf, "%s appears from nowhere, eyes glazed over.\n\r", capitalize (name));
		act (AT_IMMORT, buf, ch, NULL, NULL, TO_ROOM);
		ch->SendText ("Done.\n\r");
		return;
	}
	// else no player file
	ch->SendText ("No such player.\n\r");
#endif
}


void do_fixchar (CCharacter *ch, char *argument)
{
    char name[MAX_STRING_LENGTH];
    CCharacter *victim;

    one_argument (argument, name);
    if (name[0] == '\0')
    {
	ch->SendText ("Usage: fixchar <playername>\n\r");
	return;
    }
    victim = get_char_room (ch, name);
    if (!victim)
    {
	ch->SendText ("They're not here.\n\r");
	return;
    }
    fix_char (victim);
/*  victim->armor	= 100;
    victim->mod_str	= 0;
    victim->mod_dex	= 0;
    victim->mod_wis	= 0;
    victim->mod_int	= 0;
    victim->mod_con	= 0;
    victim->mod_cha	= 0;
    victim->mod_lck	= 0;
    victim->damroll	= 0;
    victim->GetHp ()roll	= 0;
    victim->alignment	= URANGE (-1000, victim->alignment, 1000);
    victim->saving_spell_staff = 0; */
    ch->SendText ("Done.\n\r");
}


void do_newbieset (CCharacter *ch, char *argument)
{
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];
	CObjData	*obj;
	CCharacter	*victim;

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

	if (arg1 [0] == '\0') {
		ch->SendText ("Syntax: newbieset <char>.\n\r");
		return;
	}

	if ((victim = get_char_room (ch, arg1)) == NULL) {
		ch->SendText ("That player is not here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("Not on NPC's.\n\r");
		return;
	}

	if ((victim->GetLevel () < 1) || (victim->GetLevel () > 5)) {
		ch->SendText ("Level of victim must be 1 to 5.\n\r");
		return;
	}

	obj = create_object (OIdxTable.Find (SysData.m_ObjVest), 1);
	obj_to_char (obj, victim);

	obj = create_object (OIdxTable.Find (SysData.m_ObjShield), 1);
	obj_to_char (obj, victim);

	obj = create_object (OIdxTable.Find (SysData.m_ObjBanner), 1);
	obj_to_char (obj, victim);

	if ((victim->GetClass () == 0) || (victim->GetClass () == 2)
	  || (victim->GetClass () == 4) || (victim->GetClass () == 7)) {
		obj = create_object (OIdxTable.Find (SysData.m_ObjDagger), 1);
		obj_to_char (obj, victim);
	}
	else if ((victim->GetClass () == 1) || (victim->GetClass () == 5)) {
		obj = create_object (OIdxTable.Find (SysData.m_ObjMace), 1);
		obj_to_char (obj, victim);
	}
	else if ((victim->GetClass () == 3) || (victim->GetClass () == 6)) {
		obj = create_object (OIdxTable.Find (SysData.m_ObjSword), 1);
		obj_to_char (obj, victim);
	}
  
	// Added by Brittany, on Nov. 24, 1996. The object is the adventurer's 
	// guide to the realms of despair, part of academy.are.
	CObjIndexData *obj_ind = OIdxTable.Find (SysData.m_ObjGuide);
	if (obj_ind) {
		obj = create_object (obj_ind, 1);
		obj_to_char (obj, victim);
	}

	// Added the burlap sack to the newbieset. The sack is part of
	// Spectral Gate.are - Brittany
	obj_ind = OIdxTable.GetObj (OBJ_VNUM_SACK);
	if (obj_ind) {
		obj = create_object (obj_ind, 1);
		obj_to_char (obj, victim);
	}

	act (AT_IMMORT, "$n has equipped you with a newbieset.", ch, NULL, victim, TO_VICT);
	ch->SendTextf ("You have re-equipped %s.\n\r", victim->GetName ());
}


/*
 * Extract area names from "input" string and place result in "output" string
 * e.g. "aset joe.are sedit susan.are cset" --> "joe.are susan.are"
 * - Gorog
 */
void extract_area_names  (char *inp, char *out)
{
char buf[MAX_INPUT_LENGTH], *pbuf=buf;
int  len;

*out='\0';
while  (inp && *inp)
   {
   inp = one_argument (inp, buf);
   if ((len=strlen (buf)) >= 5 && !strcmp (".are", pbuf+len-4))
       {
       if (*out) strcat  (out, " ");
       strcat  (out, buf);
       }
   }
}

/*
 * Remove area names from "input" string and place result in "output" string
 * e.g. "aset joe.are sedit susan.are cset" --> "aset sedit cset"
 * - Gorog
 */
void remove_area_names  (char *inp, char *out)
{
char buf[MAX_INPUT_LENGTH], *pbuf=buf;
int  len;

*out='\0';
while  (inp && *inp)
   {
   inp = one_argument (inp, buf);
   if ((len=strlen (buf)) < 5 || strcmp (".are", pbuf+len-4))
       {
       if (*out) strcat  (out, " ");
       strcat  (out, buf);
       }
   }
}


// Allows members of the Area Council to add Area names to the bestow field.
// Area names mus end with ".are" so that no commands can be bestowed.
void do_bestowarea (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	char		buf [MAX_STRING_LENGTH];
	CCharacter	*victim;
	int			arg_len;

	argument = one_argument (argument, arg);

	if (str_cmp (ch->GetPcData ()->GetCouncilName (), "Area Council")
	  && ch->GetTrustLevel () < LEVEL_SUB_IMPLEM) {
		ch->SendText ("Sorry. You are not on the Area Council.\n\r");
		return;
	}

	if (! *arg) {
		ch->SendText ("Syntax:\n\r"
			"bestowarea <victim> <filename>.are\n\r"
			"bestowarea <victim> none             removes bestowed areas\n\r"
			"bestowarea <victim> list             lists bestowed areas\n\r"
			"bestowarea <victim>                  lists bestowed areas\n\r");
		return;
	}

	if (! (victim = get_char_world (ch, arg))) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("You can't give special abilities to a mob!\n\r");
		return;
	}

	if (victim->GetTrustLevel () < LEVEL_IMMORTAL) {
		ch->SendText ("They aren't an immortal.\n\r");
		return;
	}

	pc_data		&vPc = *victim->GetPcData ();

	if (! vPc.HasBestowments ())
		vPc.SetBestowments (str_dup (""));

	if (! *argument || ! str_cmp  (argument, "list")) {
		extract_area_names (vPc.GetBestowments (), buf);
		ch->SendTextf ("Bestowed areas: %s\n\r", buf);
		return;
	}

	if (! str_cmp  (argument, "none")) {
		remove_area_names (vPc.GetBestowments (), buf);
		delete vPc.GetBestowments ();
		vPc.SetBestowments (str_dup (buf));
		ch->SendText ("Done.\n\r");
		return;
	}

	arg_len = strlen (argument);
	if (arg_len < 5 
	  || argument [arg_len-4] != '.' || argument [arg_len-3] != 'a'
	  || argument [arg_len-2] != 'r' || argument [arg_len-1] != 'e') {
		ch->SendText ("You can only bestow an area name\n\r");
		ch->SendText ("E.G. bestow joe sam.are\n\r");
		return;
	}

	sprintf (buf, "%s %s", vPc.GetBestowments (), argument);
	delete vPc.GetBestowments ();
	vPc.SetBestowments (str_dup (buf));
	victim->SendTextf ("%s has bestowed on you the area: %s\n\r", 
		ch->GetName (), argument);
	ch->SendText ("Done.\n\r");
}


void do_bestow (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	char		buf [MAX_STRING_LENGTH];
	CCharacter	*victim;

	argument = one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Bestow whom with what?\n\r");
		return;
	}

	if ((victim = get_char_world (ch, arg)) == NULL) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsNpc ()) 	{
		ch->SendText ("You can't give special abilities to a mob!\n\r");
		return;
	}

	if (victim->GetTrustLevel () > ch->GetTrustLevel ()) {
		ch->SendText ("You aren't powerful enough...\n\r");
		return;
	}

	if (! victim->GetPcData ()->GetBestowments ())
		victim->GetPcData ()->SetBestowments (str_dup (""));

	if (argument [0] == '\0' || ! str_cmp (argument, "list")) {
		ch->SendTextf ("Current bestowed commands on %s: %s.\n\r",
			victim->GetName (), victim->GetPcData ()->GetBestowments ());
		return;
	}

	if (! str_cmp (argument, "none")) {
		delete victim->GetPcData ()->GetBestowments ();
		victim->GetPcData ()->SetBestowments (str_dup (""));
		ch->SendTextf ("Bestowments removed from %s.\n\r",
			victim->GetName ());
		victim->SendTextf ("%s has removed your bestowed commands.\n\r",
			ch->GetName ());
		return;
	}

	sprintf (buf, "%s %s", victim->GetPcData ()->GetBestowments (), argument);
	delete victim->GetPcData ()->GetBestowments ();
	victim->GetPcData ()->SetBestowments (str_dup (buf));
	victim->SendTextf ("%s has bestowed on you the command (s): %s\n\r", 
		ch->GetName (), argument);
	ch->SendText ("Done.\n\r");
}


void do_set_boot_time (CCharacter *ch, char *argument)
{
	char	arg [MAX_INPUT_LENGTH];
	char	arg1 [MAX_INPUT_LENGTH];

	CSwTime	&Bt = gpDoc->m_RebootTime;

	BOOL	check = FALSE;

	argument = one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Syntax: setboot time {hour minute <day> <month> <year>}\n\r");
		ch->SendText ("        setboot manual {0/1}\n\r");
		ch->SendText ("        setboot default\n\r"); 
		ch->SendTextf (
			"Boot time is currently set to %s,\nmanual bit is set to %d\n\r",
			Bt.GetString (), Bt.IsManual ());
		return;
	}

	if (! str_cmp (arg, "time")) {
		argument = one_argument (argument, arg);
		argument = one_argument (argument, arg1);
		if (! *arg || ! *arg1 || ! is_number (arg) || ! is_number (arg1)) {
			ch->SendText ("You must input a value for hour and minute.\n\r");
			return;
		}

		CSwTime	ct;
		ct.SetCurrentTime ();
		int	hour = atoi (arg);
		int	min = atoi (arg1);
		int	day = ct.GetDay ();
		int	month = ct.GetMonth ();
		int	year = ct.GetYear ();

		if (hour < 0 || hour > 23) {
			ch->SendText ("Valid range for hour is 0 to 23.\n\r");
			return;
		}

		if (min < 0 || min > 59) {
			ch->SendText ("Valid range for minute is 0 to 59.\n\r");
			return;
		}

		argument = one_argument (argument, arg);
		if (*arg != '\0' && is_number (arg)) {
			day = atoi (arg);
			if (day < 1 || day > 31) {
				ch->SendText ("Valid range for day is 1 to 31.\n\r");
				return;
			}

			argument = one_argument (argument, arg);
			if (*arg != '\0' && is_number (arg)) {
				month = atoi (arg);
				if (month < 1 || month > 12) {
					ch->SendText ("Valid range for month is 1 to 12.\n\r");
					return;
				}

				argument = one_argument (argument, arg);
				year = atoi (arg);
				if (year < 1900 || year > 2037) {
					ch->SendText ("Valid range for year is 1900 to 2037.\n\r");
					return;
				}
			}
		}

		CTime	nbt (year, month, day, hour, min, 0);

		if (nbt < ct.GetCtime ()) {
			ch->SendText ("You can't set a time previous to today!\n\r");
			return;
		}

		Bt = nbt;
		Bt.SetManual (TRUE);

		ResetBootMessages ();
		ch->SendTextf ("Boot time set to %s\n\r", Bt.GetString ());
		return;
	}  

	if (! str_cmp (arg, "manual")) {
		argument = one_argument (argument, arg1);
		if (arg1 [0] == '\0') {
			ch->SendText ("Please enter a value for manual boot on/off\n\r");
			return;
		}

		int	mv = atoi (arg1);
		if (! is_number (arg1) || mv < 0 || mv > 1) {
			ch->SendText ("Value for manual must be 0  (off) or 1  (on)\n\r");
			return;
		}

		Bt.SetManual (mv);
		ch->SendTextf ("Manual bit set to %d\n\r", mv);
		return;
	}

	if (! str_cmp (arg, "default")) {		// Reinitialize boot time
		Bt.SetCurrentTime ();
		Bt.SetSecond (0);
		Bt.SetMinute (0);
		Bt.SetHour (SysData.GetRebootHour ());
		Bt += SysData.GetRebootInterval ();
		Bt.SetManual (FALSE);

		gpDoc->m_bDenyNewPlayers = FALSE;

		ResetBootMessages ();
		ch->SendTextf ("Reboot time set to normal (%s).\n\r",
			Bt.GetString ());
		return;
	}

	ch->SendText ("Invalid argument for setboot.\n\r");
}


// Online high level immortal command for displaying what the encryption
// of a name/password would be, taking in 2 arguments - the name and the
// password - can still only change the password if you have access to 
// pfiles and the correct password
void do_form_password (CCharacter *ch, char *argument) 
{
	char arg [MAX_STRING_LENGTH];

	argument = one_argument (argument, arg);

	ch->SendTextf ("The encrypted result is: %s\r\n", 
		Crypt (arg, argument)); 
}


/*
 * Purge a player file.  No more player.  -- Altrag
 */
void do_destro (CCharacter *ch, char *argument)
{
  set_char_color (AT_RED, ch);
  ch->SendText ("If you want to destroy a character, spell it out!\n\r");
  return;
}


// This could have other applications too.. move if needed. -- Altrag
void close_area (CAreaData *pArea)
{
	CCharacter		*ech;
	CCharacter		*ech_next;
	CObjData		*eobj;
	int				icnt;
	CRoomIndexData	*rid;
	CRoomIndexData	*rid_next;
	CObjIndexData	*oid;
	CObjIndexData	*oid_next;
	CMobIndexData	*mid;
	CMobIndexData	*mid_next;
	CExitData		*exit;
	CExitData		*exit_next;
	CMobProgActList	*mpact;
	CMobProgActList	*mpact_next;
  
	for (ech = first_char; ech; ech = ech_next) {
		ech_next = ech->GetNext ();

		if (ech->GetFightData ())
			stop_fighting (ech, TRUE);
		if (ech->IsNpc ()) {
			// if mob is in area, or part of this area.
			if (URANGE (pArea->low_m_vnum, ech->GetMobIndex ()->vnum,
				pArea->hi_m_vnum) == ech->GetMobIndex ()->vnum ||
				(ech->GetInRoom () && ech->GetInRoom ()->GetArea () == pArea))
					extract_char (ech, TRUE);
			continue;
		}
		if (ech->GetInRoom () && ech->GetInRoom ()->GetArea () == pArea)
			do_recall (ech, "");
	}

	// This uses the whole-mud object list to find any object that belongs
	// to the area, or which is in the area, and extract it.  I'm not sure
	// why we don't just delete the objects.  Of course we would still have
	// to remove them from the possession of any chars (mobs or PCs).  This
	// routine is only called from do_destroy and do_balzhur, and I'm not
	// sure it works right...  (Rustry)
	CParseinfo	Inf;

	while (eobj = Inf.ParseAreaLists (AllAreasList)) {
		// if obj is in area, or part of area.
		if (URANGE (pArea->low_o_vnum, eobj->pIndexData->vnum,
			pArea->hi_o_vnum) == eobj->pIndexData->vnum ||
			(eobj->in_room && eobj->in_room->GetArea () == pArea))
				extract_obj (eobj);
	}

	for (icnt = 0; icnt < MAX_KEY_HASH; icnt++) {
		for (rid = RoomTable.GetFirstByHash (icnt); rid; rid = rid_next) {
			rid_next = rid->GetNext ();

			for (exit = rid->first_exit; exit; exit = exit_next) {
				exit_next = exit->GetNext ();
				if (rid->GetArea () == pArea
				  || exit->GetToRoom ()->GetArea () == pArea) {
					STRFREE (exit->keyword);
					STRFREE (exit->description);
					UNLINK (exit, rid->first_exit, rid->last_exit);
					delete exit;
				}
			}
			if (rid->GetArea () != pArea)
				continue;

			if (rid->first_person) {
				bug ("close_area: room with people #%d", rid->vnum);
				for (ech = rid->first_person; ech; ech = ech_next) {
					ech_next = ech->GetNextInRoom ();
					if (ech->GetFightData ())
						stop_fighting (ech, TRUE);
					if (ech->IsNpc ())
						extract_char (ech, TRUE);
					else
						do_recall (ech, "");
				}
			}
			if (! rid->IsEmpty ()) {
				bug ("close_area: room with contents #%d", rid->vnum);
				POSITION	pos = rid->GetHeadContentPos ();
				while (pos)
					extract_obj (rid->GetNextContent (pos));
			}

			while (! rid->ExDesList.IsEmpty ())
				delete (CExtraDescrData*) rid->ExDesList.RemoveTail ();
			rid->ExDesList.RemoveAll ();

			for (mpact = rid->mpact; mpact; mpact = mpact_next) {
				mpact_next = mpact->GetNext ();
				STRFREE (mpact->buf);
				delete mpact;
			}

			// Delete room and remove from list
			RoomTable.Remove (rid);
			delete rid;
		}

		for (mid = MobTable.GetFirstByHash (icnt); mid; mid = mid_next) {
			mid_next = mid->GetNext ();

			if (mid->vnum < pArea->low_m_vnum
			  || mid->vnum > pArea->hi_m_vnum)
				continue;

			if (mid->pShop) {
				UNLINK (mid->pShop, first_shop, last_shop);
				delete mid->pShop;
			}
			if (mid->rShop) {
				UNLINK (mid->rShop, first_repair, last_repair);
				delete mid->rShop;
			}
			if (mid == MobTable.GetFirstByHash (icnt))
				MobTable.SetFirst (icnt, mid->GetNext ());
			else {
				CMobIndexData *tmid;

				for (tmid = MobTable.GetFirstByHash (icnt); tmid; tmid = tmid->GetNext ())
					if (tmid->GetNext () == mid)
						break;
				if (!tmid)
					bug ("Close_area: mid not in hash list %s", mid->vnum);
				else
					tmid->SetNext (mid->GetNext ());
			}
			delete mid;
		}

		for (oid = OIdxTable.GetFirstByHash (icnt); oid; oid = oid_next) {
			oid_next = oid->GetNext ();

			if (oid->vnum < pArea->low_o_vnum || oid->vnum > pArea->hi_o_vnum)
				continue;

			while (! oid->ExDesList.IsEmpty ())
				delete (CExtraDescrData*) oid->ExDesList.RemoveTail ();
			oid->ExDesList.RemoveAll ();

			if (oid == OIdxTable.GetFirstByHash (icnt))
				OIdxTable.SetFirst (icnt, oid->GetNext ());
			else {
				CObjIndexData *toid;

				for (toid = OIdxTable.GetFirstByHash (icnt); toid; toid = toid->GetNext ())
					if (toid->GetNext () == oid)
						break;
				if (!toid)
					bug ("Close_area: oid not in hash list %s", oid->vnum);
				else
					toid->SetNext (oid->GetNext ());
			}
			delete oid;
		}
	}

	BuildList.Remove (pArea);
	delete pArea;
}


void do_destroy (CCharacter *ch, char *argument)
{
	CCharacter	*victim;
	CString		Msg;
	char		arg [MAX_INPUT_LENGTH];

	one_argument (argument, arg);
	if (arg [0] == '\0') {
		ch->SendText ("Destroy what player file?\n\r");
		return;
	}

	for (victim = first_char; victim; victim = victim->GetNext ())
		if (!victim->IsNpc () && !stricmp (victim->GetName (), arg))
			break;

	if (! victim) {
		// Make sure they aren't halfway logged in.
		POSITION	pos = DList.GetHeadPosition ();
		while (pos) {
			CDescriptor *d = DList.GetNext (pos);
			if ((victim = d->m_pCharacter) && !victim->IsNpc () &&
				! stricmp (victim->GetName (), arg)) {
					RemoveCharacter (*d);
					break;
			}
		}
	} else {
		int		x, y;

		quitting_char = victim;
		save_char_obj (victim);
		saving_char = NULL;
		extract_char (victim, TRUE);
		for (x = 0; x < MAX_WEAR; x++)
			for (y = 0; y < MAX_LAYERS; y++)
				save_equipment [x][y] = NULL;
	}

	CString	Dname = capitalize (arg);
	CString	Dfile = FileTable.PlayerName (Dname);

	if (! FileTable.Exists (Dfile)) {
		set_char_color (AT_PLAIN, ch);
		ch->SendTextf ("Player %s does not exist.\n\r", Dname);
		return;
	}


	CString	strback;
	
	// Find out if backup player directory exists, and create it if not.
	FileTable.CreatePlayerDirectory (strback, Dname, TRUE);

	if (! CopyFile (Dfile, strback, FALSE)) {
		bug ("do_destroy::Error %d: Unable to copy %s to %s.",
			GetLastError (), Dfile, strback);
	}

	int		rv;
	if (rv = FileTable.Remove (Dfile)) {
		set_char_color (AT_WHITE, ch);
		Msg.Format ("do_destroy::Error %d: Deleting %s.  Report to "
			"%s.\n\r", rv, Dfile, SysData.GetSupremeEntity ());
		ch->SendText (Msg);
		bug (Msg);
		return;
	}


	set_char_color (AT_RED, ch);
	ch->SendText ("Player destroyed.  Pfile saved in backup directory.\n\r");

	CString	Godfile = FileTable.MakeName (SD_GOD_DIR, Dname);
	if (FileTable.Exists (Godfile)) {
		if (rv = FileTable.Remove (Godfile)) {
			Msg.Format ("do_destroy::Error %d Deleting %s Report to %s.\n\r",
				rv, Godfile, SysData.GetSupremeEntity ());
			ch->SendText (Msg);
			bug (Msg);
		}
		else ch->SendTextf ("Player %s's immortal data destroyed.\n\r",
			Dname);
	}

	POSITION	pos = BuildList.GetHeadPosition ();
	while (pos) {
		CAreaData	*pArea = BuildList.GetNext (pos);
		if (pArea->m_Filename == Dname) {
			if (pArea->IsLoaded ())
				fold_area (pArea, FA_BUILD);
			close_area (pArea);

			CString	Fname = FileTable.MakeBuildName (Dname);
			CString	Bname = FileTable.MakeBackupName (Fname);
			if (rv = FileTable.Remove (Bname)) {
				Msg.Format ("do_destroy::Error %d Deleting %s  (area data).  "
					"Report to %s.\n\r", rv, Bname,
					SysData.GetSupremeEntity ());
				bug (Msg);
			} else {
				set_char_color (AT_RED, ch);	// Log message changes colors
				if (! rename (Fname, Bname))
					ch->SendText ("Player's area data destroyed.  Area "
						"saved as backup.\n\r");
			}
		}
	}
}


/* Super-AT command:

FOR ALL <action>
FOR MORTALS <action>
FOR GODS <action>
FOR MOBS <action>
FOR EVERYWHERE <action>


Executes action several times, either on ALL players  (not including yourself),
MORTALS  (including trusted characters), GODS  (characters with level higher than
L_HERO), MOBS  (Not recommended) or every room  (not recommended either!)

If you insert a # in the action, it will be replaced by the name of the target.

If # is a part of the action, the action will be executed for every target
in game. If there is no #, the action will be executed for every room containg
at least one target, but only once per room. # cannot be used with FOR EVERY-
WHERE. # can be anywhere in the action.

Example: 

FOR ALL SMILE -> you will only smile once in a room with 2 players.
FOR ALL TWIDDLE # -> In a room with A and B, you will twiddle A then B.

Destroying the characters this command acts upon MAY cause it to fail. Try to
avoid something like FOR MOBS PURGE  (although it actually works at my MUD).

FOR MOBS TRANS 3054  (transfer ALL the mobs to Midgaard temple) does NOT work
though :)

The command works by transporting the character to each of the rooms with 
target in them. Private rooms are not violated.

*/

/* Expand the name of a character into a string that identifies THAT
   character within a room. E.g. the second 'guard' -> 2. guard
*/   
const char * name_expand  (CCharacter *ch)
{
	int count = 1;
	CCharacter *rch;
	char name[MAX_INPUT_LENGTH]; /*  HOPEFULLY no mob has a name longer than THAT */

	static char outbuf[MAX_INPUT_LENGTH];	
	
	if (!ch->IsNpc ())
		return ch->GetName ();
		
	one_argument  (ch->GetName (), name); /* copy the first word into name */
	
	if (!name[0]) /* weird mob .. no keywords */
	{
		strcpy  (outbuf, ""); /* Do not return NULL, just an empty buffer */
		return outbuf;
	}
	
	/* ->people changed to ->first_person -- TRI */	
	for (rch = ch->GetInRoom ()->first_person; rch &&  (rch != ch);rch = 
	    rch->GetNextInRoom ())
		if (is_name  (name, rch->GetName ()))
			count++;
			

	sprintf  (outbuf, "%d.%s", count, name);
	return outbuf;
}


void do_for (CCharacter *ch, char *argument)
{
	char range[MAX_INPUT_LENGTH];
	char buf[MAX_STRING_LENGTH];
	BOOL fGods = FALSE, fMortals = FALSE, fMobs = FALSE, fEverywhere = FALSE, found;
	CRoomIndexData *room, *old_room;
	CCharacter *p, *p_prev;  /* p_next to p_prev -- TRI */
	int i;
	
	argument = one_argument  (argument, range);
	
	if (!range[0] || !argument[0]) /* invalid usage? */
	{
		do_help  (ch, "for");
		return;
	}
	
	if (!str_prefix ("quit", argument))
	{
		ch->SendText ("Are you trying to crash the MUD or something?\n\r");
		return;
	}
	
	
	if (!str_cmp  (range, "all"))
	{
		fMortals = TRUE;
		fGods = TRUE;
	}
	else if (!str_cmp  (range, "gods"))
		fGods = TRUE;
	else if (!str_cmp  (range, "mortals"))
		fMortals = TRUE;
	else if (!str_cmp  (range, "mobs"))
		fMobs = TRUE;
	else if (!str_cmp  (range, "everywhere"))
		fEverywhere = TRUE;
	else
		do_help  (ch, "for"); /* show syntax */

	/* do not allow # to make it easier */		
	if (fEverywhere && strchr  (argument, '#'))
	{
		ch->SendText ("Cannot use FOR EVERYWHERE with the # thingie.\n\r");
		return;
	}
		
	if (strchr  (argument, '#')) /* replace # ? */
	{ 
		/* char_list - last_char, p_next - gch_prev -- TRI */
		for (p = last_char; p ; p = p_prev)
		{
			p_prev = p->GetPrev ();  /* TRI */
		/*	p_next = p->GetNext (); */ /* In case someone DOES try to AT MOBS SLAY # */
			found = FALSE;
			
			if (! (p->GetInRoom ()) || room_is_private (p->GetInRoom ()) ||  (p == ch))
				continue;
			
			if (p->IsNpc () && fMobs)
				found = TRUE;
			else if (!p->IsNpc () && p->GetLevel () >= LEVEL_IMMORTAL && fGods)
				found = TRUE;
			else if (!p->IsNpc () && p->GetLevel () < LEVEL_IMMORTAL && fMortals)
				found = TRUE;

			/* It looks ugly to me.. but it works :) */				
			if (found) /* p is 'appropriate' */
			{
				char *pSource = argument; /* head of buffer to be parsed */
				char *pDest = buf; /* parse into this */
				
				while  (*pSource)
				{
					if (*pSource == '#') /* Replace # with name of target */
					{
						const char *namebuf = name_expand  (p);
						
						if (namebuf) /* in case there is no mob name ?? */
							while  (*namebuf) /* copy name over */
								* (pDest++) = * (namebuf++);

						pSource++;
					}
					else
						* (pDest++) = * (pSource++);
				} /* while */
				*pDest = '\0'; /* Terminate */
				
				/* Execute */
				old_room = ch->GetInRoom ();
				ch->RemoveFromRoom ();
				ch->SendToRoom (p->GetInRoom ());
				interpret (ch, buf);
				ch->RemoveFromRoom ();
				ch->SendToRoom (old_room);
				
			} /* if found */
		} /* for every char */
	}
	else /* just for every room with the appropriate people in it */
	{
		for (i = 0; i < MAX_KEY_HASH; i++) /* run through all the buckets */
			for (room = RoomTable.GetFirstByHash (i); room; room = room->GetNext ())
			{
				found = FALSE;
				
				/* Anyone in here at all? */
				if (fEverywhere) /* Everywhere executes always */
					found = TRUE;
				else if (!room->first_person) /* Skip it if room is empty */
					continue;
				/* ->people changed to first_person -- TRI */
					
				/* Check if there is anyone here of the requried type */
				/* Stop as soon as a match is found or there are no more ppl in room */
				/* ->people to ->first_person -- TRI */
				for (p = room->first_person; p && !found; p = p->GetNextInRoom ())
				{

					if (p == ch) /* do not execute on oneself */
						continue;
						
					if (p->IsNpc () && fMobs)
						found = TRUE;
					else if (!p->IsNpc () &&  (p->GetLevel () >= LEVEL_IMMORTAL) && fGods)
						found = TRUE;
					else if (!p->IsNpc () &&  (p->GetLevel () <= LEVEL_IMMORTAL) && fMortals)
						found = TRUE;
				} /* for everyone inside the room */
						
				if (found && !room_is_private (room)) /* Any of the required type here AND room not private? */
				{
					/* This may be ineffective. Consider moving character out of old_room
					   once at beginning of command then moving back at the end.
					   This however, is more safe?
					*/
				
					old_room = ch->GetInRoom ();
					ch->RemoveFromRoom ();
					ch->SendToRoom (room);
					interpret  (ch, argument);
					ch->RemoveFromRoom ();
					ch->SendToRoom (old_room);
				} /* if found */
			} /* for every room in a bucket */
	} /* if strchr */
} /* do_for */


void do_cset (CCharacter *ch, char *argument)
{
	char	arg [MAX_STRING_LENGTH];
	short	level;

	set_char_color (AT_IMMORT, ch);

	if (argument [0] == '\0') {
		ch->SendTextf ("Mail:\n\r  Read all mail: %d. Read mail for free: %d."
			" Write mail for free: %d.\n\r", SysData.ReadAllMailLev,
			SysData.ReadMailFreeLev, SysData.WriteMailFreeLev);
		ch->SendTextf ("  Take all mail: %d.\n\r", SysData.TakeOthersMailLev);
		ch->SendTextf ("Channels:\n\r  Muse: %d. Think: %d. Log: %d. "
			"Build: %d.\n\r", SysData.MuseLevel, SysData.ThinkLevel,
			SysData.LogLevel, SysData.BuildLevel);
		ch->SendTextf ("Building:\n\r  Prototype modification: %d.  Player "
			"msetting: %d.\n\r", SysData.ModifyProtoLevel,
			SysData.MsetPlayerLevel);
		ch->SendTextf ("Guilds:\n\r  Overseer: %s.  Advisor: %s.\n\r", 
			SysData.pGuildOverseer, SysData.pGuildAdvisor);
		ch->SendTextf ("Other:\n\r  Force on players: %d.  ",
			SysData.ForcePcLevel);
		ch->SendTextf ("Private room override: %d.\n\r",
			SysData.OverridePrivateLev);
		ch->SendTextf ("  Penalty to regular stun chance: %d.  ",
			SysData.StunRegularLev);
		ch->SendTextf ("Penalty to stun plr vs. plr: %d.\n\r",
			SysData.StunPlayerLev);
		ch->SendTextf ("  Percent damage plr vs. plr: %3d.  ",
			SysData.PlrPlrDamage);
		ch->SendTextf ("Percent damage plr vs. mob: %d.\n\r",
			SysData.PlrMobDamage);
		ch->SendTextf ("  Percent damage mob vs. plr: %3d.  ",
			SysData.MobPlrDamage);
		ch->SendTextf ("Percent damage mob vs. mob: %d.\n\r",
			SysData.MobMobDamage);
		ch->SendTextf ("  Get object without take flag: %d.  ",
			SysData.GetObjNoTakeLevel);
		ch->SendTextf ("Autosave frequency  (minutes): %d.\n\r",
			SysData.SaveFrequency);
		ch->SendTextf ("  Save flags: %s\n\r", SysData.GetFlagString ());
		return;
	}

	argument = one_argument (argument, arg);

	if (! str_cmp (arg, "help")) {
		do_help (ch, "controls");
		return;
	}

	if (! str_cmp (arg, "save")) {
		SysData.Save ();
		return;
	}

	if (! str_cmp (arg, "saveflag")) {
		int x = SysData.GetSaveFlag (argument);

		if (x < 0)
			ch->SendText ("Not a save flag.\n\r");
		else {
			SysData.ToggleSave (1 << x);
			ch->SendText ("Ok.\n\r");
		}
		return;
	}

	if (! str_prefix (arg, "GuildOverseer")) {
		STRFREE (SysData.pGuildOverseer);
		SysData.pGuildOverseer = str_dup (argument);
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_prefix (arg, "GuildAdvisor")) {
		STRFREE (SysData.pGuildAdvisor);
		SysData.pGuildAdvisor = str_dup (argument);
		ch->SendText ("Ok.\n\r");      
		return;
	}

	level = (short) atoi (argument);

	if (! str_prefix (arg, "savefrequency")) {
		SysData.SaveFrequency = level;
		ch->SendText ("Ok.\n\r");
		return;
	}

	if (! str_cmp (arg, "stun")) {
		SysData.StunRegularLev = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "stun_pvp")) {
		SysData.StunPlayerLev = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "dam_pvp")) {
		SysData.PlrPlrDamage = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "get_notake")) {
		SysData.GetObjNoTakeLevel = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "dam_pvm")) {
		SysData.PlrMobDamage = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "dam_mvp")) {
		SysData.MobPlrDamage = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "dam_mvm")) {
		SysData.MobMobDamage = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (level < 0 || level > MAX_LEVEL) {
		ch->SendText ("Invalid value for new control.\n\r");
		return;
	}

	if (! str_cmp (arg, "read_all")) {
		SysData.ReadAllMailLev = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "read_free")) {
		SysData.ReadMailFreeLev = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "write_free")) {
		SysData.WriteMailFreeLev = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "take_all")) {
		SysData.TakeOthersMailLev = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "muse")) {
		SysData.MuseLevel = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (!str_cmp (arg, "think")) {
		SysData.ThinkLevel = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "log")) {
		SysData.LogLevel = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "build")) {
		SysData.BuildLevel = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "proto_modify")) {
		SysData.ModifyProtoLevel = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "override_private")) {
		SysData.OverridePrivateLev = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "forcepc")) {
		SysData.ForcePcLevel = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	if (! str_cmp (arg, "mset_player")) {
		SysData.MsetPlayerLevel = level;
		ch->SendText ("Ok.\n\r");      
		return;
	}

	ch->SendText ("Invalid argument.\n\r");
}


void do_orange (CCharacter *ch, char *argument)
{
	ch->SendText ("Function under construction.\n\r");
}


void do_mrange (CCharacter *ch, char *argument)
{
	ch->SendText ("Function under construction.\n\r");
}


void do_hell (CCharacter *ch, char *argument)
{
	CCharacter	*victim;
	char		arg [MAX_INPUT_LENGTH];

	argument = one_argument (argument, arg);
	if (! *arg) {
		ch->SendText ("Hell who, and for how long?\n\r");
		return;
	}

	if (! (victim = get_char_world (ch, arg)) || victim->IsNpc ()) {
		ch->SendText ("They aren't here.\n\r");
		return;
	}

	if (victim->IsImmortal ()) {
		ch->SendText ("There is no point in helling an immortal.\n\r");
		return;
	}

	if (! victim->GetPcData ()->release_date.IsZero ()) {
		ch->SendTextf ("They are already in hell until %s, by %s.\n\r",
			victim->GetPcData ()->release_date.GetString (),
			victim->GetPcData ()->helled_by);
		return;
	}

	argument = one_argument (argument, arg);
	if (! *arg || ! is_number (arg)) {
		ch->SendText ("Hell them for how long?\n\r");
		return;
	}

	int	time = atoi (arg);
	if (time <= 0) {
		ch->SendText ("You cannot hell for zero or negative time.\n\r");
		return;
	}

	int		Hours = 0, Days = 0;
	argument = one_argument (argument, arg);

	if (! *arg || ! str_prefix (arg, "hours"))
		Hours = time;
	else if (str_prefix (arg, "days")) {
		ch->SendText ("Is that value in hours or days?\n\r");
		return;
	}
	else if (time > 30) {
		ch->SendText ("You may not hell a person for more than 30 days "
			"at a time.\n\r");
		return;
	}
	else Days = time;

	CTimeSpan	HellTime (Days, Hours, 0, 0);

	CSwTime	&Rd = victim->GetPcData ()->release_date;

	Rd.SetCurrentTime ();
	Rd += HellTime;

	victim->GetPcData ()->helled_by = STRALLOC (ch->GetName ());
	ch->SendTextf ("%s will be released from hell at %s.\n\r",
		victim->GetName (), Rd.GetString ());

	act (AT_MAGIC, "$n disappears in a cloud of hellish light.",
		victim, NULL, ch, TO_NOTVICT);
	victim->RemoveFromRoom ();
	victim->SendToRoom (RoomTable.GetRoom (SysData.m_RoomHell));

	act (AT_MAGIC, "$n appears in a could of hellish light.",
		victim, NULL, ch, TO_NOTVICT);

	do_look (victim, "auto");
	victim->SendTextf ("The immortals are not pleased with your actions.\n\r"
		"You shall remain in hell for %d Hours.\n\r", Days + 24 * Hours);

	save_char_obj (victim);		// used to save ch, fixed by Thoric 09/17/96
}


void do_unhell (CCharacter *ch, char *argument)
{
	CCharacter		*victim;
	char			arg [MAX_INPUT_LENGTH];
	CRoomIndexData	*location;

	argument = one_argument (argument, arg);
	if (!*arg) {
		ch->SendText ("Unhell whom..?\n\r");
		return;
	}
	location = ch->GetInRoom ();
	ch->SetInRoom (RoomTable.GetRoom (SysData.m_RoomHell));
	victim = get_char_room (ch, arg);
	ch->SetInRoom (location);            /* The case of unhell self, etc. */

	if (!victim || victim->IsNpc ()
	  || victim->GetInRoom ()->vnum != SysData.m_RoomHell) {
		ch->SendText ("No one like that is in hell.\n\r");
		return;
	}
	if (victim->GetPcData ()->GetClan ())
		location = RoomTable.GetRoom (victim->GetPcData ()->GetClan ()->recall);
	else
		location = RoomTable.GetRoom (SysData.m_RoomTemple);
	if (!location)
		location = ch->GetInRoom ();

	MOBtrigger = FALSE;
	act (AT_MAGIC, "$n disappears in a cloud of godly light.",
		victim, NULL, ch, TO_NOTVICT);
	victim->RemoveFromRoom ();
	victim->SendToRoom (location);
	victim->SendText ("The gods have smiled on you and released you from hell "
		"early!\n\r");
	do_look (victim, "auto");
	ch->SendText ("They have been released.\n\r");

	if (victim->GetPcData ()->helled_by) {
		if (str_cmp (ch->GetName (), victim->GetPcData ()->helled_by))
		ch->SendTextf ("(You should probably write a note to %s, "
			"explaining the early release.)\n\r",
			victim->GetPcData ()->helled_by);
		STRFREE (victim->GetPcData ()->helled_by);
		victim->GetPcData ()->helled_by = NULL;
	}

	MOBtrigger = FALSE;
	act (AT_MAGIC, "$n appears in a cloud of godly light.",
		victim, NULL, ch, TO_NOTVICT);
	victim->GetPcData ()->release_date = CTime (0);
	save_char_obj (victim);
}


// Vnum search command by Swordbearer
void do_vsearch (CCharacter *ch, char *argument)
{
	char		arg [MAX_INPUT_LENGTH];
	BOOL		found = FALSE;
	CObjData	*obj;
	CObjData	*in_obj;
	int			obj_counter = 1;
	int			argi;

	one_argument (argument, arg);

	if (arg [0] == '\0') {
		ch->SendText ("Syntax:  vsearch <vnum>.\n\r");
		return;
	}

	set_pager_color (AT_PLAIN, ch);
	argi = atoi (arg);
	if (argi < 0 && argi > 20000) {
		ch->SendText ("Vnum out of range.\n\r");
		return;
	}

	CParseinfo	Inf;

	while (obj = Inf.ParseAreaLists (AllAreasList)) {
		if (! can_see_obj (ch, *obj) || ! (argi == obj->pIndexData->vnum))
			continue;

		found = TRUE;
		for (in_obj = obj; in_obj->in_obj != NULL;
			in_obj = in_obj->in_obj);

		if (in_obj->carried_by != NULL)
			pager_printf (ch, "[%2d] Level %d %s carried by %s.\n\r", 
				obj_counter, obj->level, obj_short (obj),
				PERS (in_obj->carried_by, ch));
		else           
			pager_printf (ch, "[%2d] [%-5d] %s in %s.\n\r", obj_counter,
				((in_obj->in_room) ? in_obj->in_room->vnum : 0),
				obj_short (obj),  (in_obj->in_room == NULL) ?
				"somewhere" : in_obj->in_room->GetName ());

		++obj_counter;
	}

	if (!found)
		ch->SendText ("Nothing like that in heaven, earth, or hell.\n\r");
}


/* 
 * Simple function to let any imm make any player instantly sober.
 * Saw no need for level restrictions on this.
 * Written by Narn, Apr/96 
 */
void do_sober (CCharacter *ch, char *argument)
{
  CCharacter *victim;
  char arg1 [MAX_INPUT_LENGTH];

  smash_tilde (argument);
  argument = one_argument (argument, arg1);
  if ((victim = get_char_room (ch, arg1)) == NULL)
  {
    ch->SendText ("They aren't here.\n\r");
    return;
  }

  if (victim->IsNpc ())
  {
    ch->SendText ("Not on mobs.\n\r");
    return;    
  }

  if (victim->GetPcData ()) 
    victim->GetPcData ()->condition[COND_DRUNK] = 0;
  ch->SendText ("Ok.\n\r");
  victim->SendText ("You feel sober again.\n\r");
  return;    
}


/*
 * Social editor/displayer/save/delete				-Thoric
 */
void do_sedit (CCharacter *ch, char *argument)
{
    CSocialType *social;
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];

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

    set_char_color (AT_SOCIAL, ch);

    if (arg1[0] == '\0')
    {
	ch->SendText ("Syntax: sedit <social> [field]\n\r");
	ch->SendText ("Syntax: sedit <social> create\n\r");
	if (ch->GetTrustLevel () > LEVEL_GOD)
	    ch->SendText ("Syntax: sedit <social> delete\n\r");
	if (ch->GetTrustLevel () > LEVEL_LESSER)
	    ch->SendText ("Syntax: sedit <save>\n\r");
	ch->SendText ("\n\rField being one of:\n\r");
	ch->SendText ("  cnoarg onoarg cfound ofound vfound cauto oauto\n\r");
	return;
    }

	if (ch->GetTrustLevel () > LEVEL_LESSER && !str_cmp (arg1, "save")) {
		SocialTable.Write ();
		ch->SendText ("Saved.\n\r");
		return;
	}

    social = SocialTable.Find (arg1);

    if (!str_cmp (arg2, "create"))
    {
	if (social)
	{
	    ch->SendText ("That social already exists!\n\r");
	    return;
	}
	social = new CSocialType;
	social->SetName (str_dup (arg1));
	sprintf (arg2, "You %s.", arg1);
	social->char_no_arg = str_dup (arg2);
	SocialTable.Add (social);
	ch->SendText ("Social added.\n\r");
	return;
    }

    if (!social)
    {
	ch->SendText ("Social not found.\n\r");
	return;
    }

    if (arg2[0] == '\0' || !str_cmp (arg2, "show"))
    {
	ch->SendTextf ("Social: %s\n\r\n\rCNoArg: %s\n\r",
	    social->GetName (),	social->char_no_arg);
	ch->SendTextf ("ONoArg: %s\n\rCFound: %s\n\rOFound: %s\n\r",
	    social->others_no_arg	? social->others_no_arg	: "(not set)",
	    social->char_found		? social->char_found	: "(not set)",
	    social->others_found	? social->others_found	: "(not set)");
	ch->SendTextf ("VFound: %s\n\rCAuto : %s\n\rOAuto : %s\n\r",
	    social->vict_found	? social->vict_found	: "(not set)",
	    social->char_auto	? social->char_auto	: "(not set)",
	    social->others_auto	? social->others_auto	: "(not set)");
	return;
    }

	if (ch->GetTrustLevel () > LEVEL_GOD && !str_cmp (arg2, "delete")) {
		SocialTable.Unlink (social);
		delete social;
		ch->SendText ("Deleted.\n\r");
		return;
	}

    if (!str_cmp (arg2, "cnoarg"))
    {
	if (argument[0] == '\0' || !str_cmp (argument, "clear"))
	{
	    ch->SendText ("You cannot clear this field.  It must have a message.\n\r");
	    return;
	}
	if (social->char_no_arg)
	    delete social->char_no_arg;
	social->char_no_arg = str_dup (argument);
	ch->SendText ("Done.\n\r");
	return;
    }

    if (!str_cmp (arg2, "onoarg"))
    {
	if (social->others_no_arg)
	    delete social->others_no_arg;
	if (argument[0] != '\0' && str_cmp (argument, "clear"))
	    social->others_no_arg = str_dup (argument);
	ch->SendText ("Done.\n\r");
	return;
    }

    if (!str_cmp (arg2, "cfound"))
    {
	if (social->char_found)
	    delete social->char_found;
	if (argument[0] != '\0' && str_cmp (argument, "clear"))
	    social->char_found = str_dup (argument);
	ch->SendText ("Done.\n\r");
	return;
    }

    if (!str_cmp (arg2, "ofound"))
    {
	if (social->others_found)
	    delete social->others_found;
	if (argument[0] != '\0' && str_cmp (argument, "clear"))
	    social->others_found = str_dup (argument);
	ch->SendText ("Done.\n\r");
	return;
    }

    if (!str_cmp (arg2, "vfound"))
    {
	if (social->vict_found)
	    delete social->vict_found;
	if (argument[0] != '\0' && str_cmp (argument, "clear"))
	    social->vict_found = str_dup (argument);
	ch->SendText ("Done.\n\r");
	return;
    }

    if (!str_cmp (arg2, "cauto"))
    {
	if (social->char_auto)
	    delete social->char_auto;
	if (argument[0] != '\0' && str_cmp (argument, "clear"))
	    social->char_auto = str_dup (argument);
	ch->SendText ("Done.\n\r");
	return;
    }

    if (!str_cmp (arg2, "oauto"))
    {
	if (social->others_auto)
	    delete social->others_auto;
	if (argument[0] != '\0' && str_cmp (argument, "clear"))
	    social->others_auto = str_dup (argument);
	ch->SendText ("Done.\n\r");
	return;
    }

    if (ch->GetTrustLevel () > LEVEL_GREATER && !str_cmp (arg2, "name")) {
		BOOL relocate;

		one_argument (argument, arg1);
		if (arg1 [0] == '\0') {
			ch->SendText ("Cannot clear name field!\n\r");
			return;
		}
		if (arg1 [0] != social->GetName ()[0]) {
			SocialTable.Unlink (social);
			relocate = TRUE;
		}
		else relocate = FALSE;

		if (social->GetName ())
			delete social->GetName ();
		social->SetName (str_dup (arg1));

		if (relocate)
			SocialTable.Add (social);
		ch->SendText ("Done.\n\r");
		return;
    }

    /* display usage message */
    do_sedit (ch, "");
}


/*
 * Command editor/displayer/save/delete				-Thoric
 */
void do_cedit (CCharacter *ch, char *argument)
{
    CCmdType *command;
    char arg1[MAX_INPUT_LENGTH];
    char arg2[MAX_INPUT_LENGTH];

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

    set_char_color (AT_IMMORT, ch);

    if (arg1[0] == '\0')
    {
	ch->SendText ("Syntax: cedit save\n\r");
	if (ch->GetTrustLevel () > LEVEL_SUB_IMPLEM)
	{
	    ch->SendText ("Syntax: cedit <command> create [code]\n\r");
	    ch->SendText ("Syntax: cedit <command> delete\n\r");
	    ch->SendText ("Syntax: cedit <command> show\n\r");
	    ch->SendText ("Syntax: cedit <command> [field]\n\r");
	    ch->SendText ("\n\rField being one of:\n\r");
	    ch->SendText ("  level position log code\n\r");
	}
	return;
    }

    if (ch->GetTrustLevel () > LEVEL_GREATER && !str_cmp (arg1, "save")) {
		CommandTable.Save ();
		ch->SendText ("Saved.\n\r");
		return;
    }

    command = CommandTable.Find (arg1);

    if (ch->GetTrustLevel () > LEVEL_SUB_IMPLEM && !str_cmp (arg2, "create"))
    {
	if (command)
	{
	    ch->SendText ("That command already exists!\n\r");
	    return;
	}
	command = new CCmdType;
	command->SetName (str_dup (arg1));
	command->level = ch->GetTrustLevel ();
	if (*argument)
	  one_argument (argument, arg2);
	else
	  sprintf (arg2, "do_%s", arg1);
	command->do_fun = skill_function (arg2);
	CommandTable.Add (command);
	ch->SendText ("Command added.\n\r");
	if (command->do_fun == skill_notfound)
	  ch->SendTextf ("Code %s not found.  Set to no code.\n\r", arg2);
	return;
    }

    if (!command)
    {
	ch->SendText ("Command not found.\n\r");
	return;
    }
    else
    if (command->level > ch->GetTrustLevel ())
    {
	ch->SendText ("You cannot touch this command.\n\r");
	return;
    }

    if (arg2[0] == '\0' || !str_cmp (arg2, "show"))
    {
	ch->SendTextf ("Command:  %s\n\rLevel:    %d\n\rPosition: %d\n\rLog:      %d\n\rCode:     %s\n\r",
	    command->GetName (), command->level, command->position, command->log,
	    skill_name (command->do_fun));
	if (command->userec.num_uses)
	  send_timer (&command->userec, ch);
	return;
    }

    if (ch->GetTrustLevel () <= LEVEL_SUB_IMPLEM)
    {
	do_cedit (ch, "");
	return;
    }

    if (!str_cmp (arg2, "delete"))
    {
	CommandTable.Unlink (command);
	delete command;
	ch->SendText ("Deleted.\n\r");
	return;
    }

    if (!str_cmp (arg2, "code"))
    {
	DO_FUN *fun = skill_function (argument);
	
	if (fun == skill_notfound)
	{
	    ch->SendText ("Code not found.\n\r");
	    return;
	}
	command->do_fun = fun;
	ch->SendText ("Done.\n\r");
	return;
    }

    if (!str_cmp (arg2, "level"))
    {
	int level = atoi (argument);

	if (level < 0 || level > ch->GetTrustLevel ())
	{
	    ch->SendText ("Level out of range.\n\r");
	    return;
	}
	command->level = level;
	ch->SendText ("Done.\n\r");
	return;
    }

    if (!str_cmp (arg2, "log"))
    {
	int log = atoi (argument);

	if (log < 0 || log > LOG_COMM)
	{
	    ch->SendText ("Log out of range.\n\r");
	    return;
	}
	command->log = log;
	ch->SendText ("Done.\n\r");
	return;
    }

    if (!str_cmp (arg2, "position"))
    {
	int position = atoi (argument);

	if (position < 0 || position > POS_DRAG)
	{
	    ch->SendText ("Position out of range.\n\r");
	    return;
	}
	command->position = position;
	ch->SendText ("Done.\n\r");
	return;
    }

    if (!str_cmp (arg2, "name"))
    {
	BOOL relocate;

	one_argument (argument, arg1);
	if (arg1[0] == '\0')
	{
	    ch->SendText ("Cannot clear name field!\n\r");
	    return;
	}
	if (arg1[0] != command->GetName ()[0])
	{
	    CommandTable.Unlink (command);
	    relocate = TRUE;
	}
	else
	    relocate = FALSE;
	delete command->GetName ();
	command->SetName (str_dup (arg1));
	if (relocate)
	    CommandTable.Add (command);
	ch->SendText ("Done.\n\r");
	return;
    }

    /* display usage message */
    do_cedit (ch, "");
}


// Display class information					-Thoric
void do_showclass (CCharacter *ch, char *argument)
{
	char	arg1 [MAX_INPUT_LENGTH];
	char	arg2 [MAX_INPUT_LENGTH];
	int		low, hi;

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

	set_char_color (AT_IMMORT, ch);
	if (arg1 [0] == '\0') {
		ch->SendText ("Syntax: showclass <class> [level range]\n\r");
		ch->SendText ("Syntax: showclass list\r\n");
		return;
	}

	if (! str_cmp (arg1, "list")) {
		ClassTable.ListClasses (ch);
		return;
	}

	int			nClass = ClassTable.GetCount ();
	int			cl = atoi (arg1);
	CClassData	*pClass = NULL;

	if (is_number (arg1) &&  (cl >= 0 && cl < nClass))
		pClass = ClassTable.GetClassData (cl);
	else {
		for (cl = 0; cl < nClass; ++cl)
			if (! str_cmp (ClassTable.GetName (cl), arg1)) {
				pClass = ClassTable.GetClassData (cl);
				break;
			}
	}

	if (! pClass) {
		ch->SendText ("No such class.\n\r");
		return;
	}

	set_pager_color (AT_IMMORT, ch);
	pager_printf (ch, "Class: %s\n\rPrime Attribute: %-14s Weapon: %-5d  Guild:   %d\n\r"
		"Max Skill Adept: %-3d            Thac0:  %-5d  Thac32:  %d\n\r"
		"Hp Min / Hp Max: %d/%-2d           Mana:   %s    ExpBase: %d\n\r",
		pClass->GetName (), affect_loc_name (pClass->GetAttrPrime ()),
		pClass->GetWeapon (), pClass->GetGuild (),
		pClass->GetSkillAdept (), pClass->GetThac0 (),
		pClass->GetThac32 (), pClass->GetMinHp (),
		pClass->GetMaxHp (), pClass->HasManaGain () ? "yes" : "no ",
		pClass->GetExpBase ());

	if (arg2 [0] != '\0') {
		int		x, y, cnt;

		low = UMIN (0, atoi (arg2));
		hi  = URANGE (low, atoi (argument), MAX_LEVEL);
		for (x = low; x <= hi; x++) {
			set_pager_color (AT_LBLUE, ch);
			pager_printf (ch, "Male: %-30s Female: %s\n\r",
				ClassTable.GetTitle (cl,x,0), ClassTable.GetTitle (cl,x,1));
			cnt = 0;
			set_pager_color (AT_BLUE, ch);
			for (y = gsn_first_spell; y < gsn_top_sn; y++)
				if (SkillTable.GetClassLevel (y, cl) == x) {
					pager_printf (ch, "  %-7s %-19s%3d     ",
						skill_tname [SkillTable.GetType (y)],
						SkillTable.GetName (y),
							SkillTable.GetClassAdept (y, cl));
					if (++cnt % 2 == 0)
						send_to_pager ("\n\r", ch);
				}
			if (cnt % 2 != 0)
				send_to_pager ("\n\r", ch);
			send_to_pager ("\n\r", ch);
		}
	}
}


// Edit class information					-Thoric
void do_setclass (CCharacter *ch, char *argument)
{
	char	arg1 [MAX_INPUT_LENGTH];
	char	arg2 [MAX_INPUT_LENGTH];

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

	set_char_color (AT_IMMORT, ch);
	if (arg1 [0] == '\0') {
		ch->SendText ("Syntax: setclass <class> <field> <value>\n\r");
		ch->SendText ("\n\rField being one of:\n\r");
		ch->SendText ("  name prime weapon guild thac0 thac32\n\r");
		ch->SendText ("  hpmin hpmax mana expbase mtitle ftitle\n\r");
		return;
	}

	int			nClass = ClassTable.GetCount ();
	int			cl = atoi (arg1);
	CClassData	*pClass = NULL;

	if (is_number (arg1) && cl >= 0 && cl < nClass)
		pClass = ClassTable.GetClassData (cl);
	else {
		for (cl = 0; cl < nClass; ++cl)
			if (! str_cmp (ClassTable.GetName (cl), arg1)) {
				pClass = ClassTable.GetClassData (cl);
				break;
			}
	}

	if (! pClass) {
		ch->SendText ("No such class.\n\r");
		return;
	}

	if (! str_cmp (arg2, "save")) {
		pClass->Write ();
		ch->SendText ("Saved.\n\r");
		return;
	}

	if (! str_cmp (arg2, "name")) {
		STRFREE (pClass->GetName ());
		pClass->SetName (argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "prime")) {
		int		x = get_atype (argument);

		if (x < APPLY_STR || (x > APPLY_CON && x != APPLY_LCK))
			ch->SendText ("Invalid prime attribute!\n\r");
		else {
			pClass->SetAttrPrime (x);
			ch->SendText ("Done.\n\r");
		}
		return;
	}

	if (! str_cmp (arg2, "weapon")) {
		pClass->SetWeapon (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "guild")) {
		pClass->SetGuild (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "thac0")) {
		pClass->SetThac0 (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "thac32")) {
		pClass->SetThac32 (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "hpmin")) {
		pClass->SetMinHp (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "hpmax")) {
		pClass->SetMaxHp (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "mana")) {
		pClass->SetManaGain (argument [0] == 'Y');
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "expbase")) {
		pClass->SetExpBase (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "mtitle")) {
		char	arg3 [MAX_INPUT_LENGTH];

		argument = one_argument (argument, arg3);
		if (arg3 [0] == '\0' || argument [0] == '\0') {
			ch->SendText ("Syntax: setclass <class> mtitle <level> <title>\n\r");
			return;
		}
		int	lev = atoi (arg3);
		if (! is_number (arg3) || lev <= 0 || lev > MAX_LEVEL) {
			ch->SendText ("Invalid level.\n\r");
			return;
		}
		pClass->SetTitle (lev, 0, argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "ftitle")) {
		char	arg3 [MAX_INPUT_LENGTH];

		argument = one_argument (argument, arg3);
		if (arg3 [0] == '\0' || argument [0] == '\0') {
			ch->SendText ("Syntax: setclass <class> ftitle <level> <title>\n\r");
			return;
		}
		int	lev = atoi (arg3);
		if (! is_number (arg3) || lev <= 0 || lev > MAX_LEVEL) {
			ch->SendText ("Invalid level.\n\r");
			return;
		}
		pClass->SetTitle (lev, 1, argument);
		ch->SendText ("Done.\n\r");
		return;
	}
	do_setclass (ch, "");
}


/*
 * quest point set - TRI
 * syntax is: qpset char give/take amount
 */

void do_qpset (CCharacter *ch, char *argument)
{
  char arg[MAX_INPUT_LENGTH];
  char arg2[MAX_INPUT_LENGTH];
  char arg3[MAX_INPUT_LENGTH];
  CCharacter *victim;
  int amount;
  BOOL give = TRUE;

  if (ch->IsNpc ())
  {
    ch->SendText ("Cannot qpset as an NPC.\n\r");
    return;
  }

  if (ch->GetTrustLevel () < LEVEL_IMMORTAL) 
  {
    ch->SendText ("Huh?\n\r");
    return;
  }
 else if (str_cmp (ch->GetPcData ()->GetCouncilName (), "Quest Council") 
	&&  (ch->GetTrustLevel () < LEVEL_DEMI))
  {
    ch->SendText ("You must be a member of Quest Council to give or remove qp from players.\n\r");
    return;
  }

  set_char_color (AT_LOG, ch);  
  argument = one_argument (argument, arg);
  argument = one_argument (argument, arg2);
  argument = one_argument (argument, arg3);
  amount = atoi (arg3);

  if (arg[0] == '\0' || arg2[0] == '\0' || amount <= 0)
  {
    ch->SendText ("Syntax: qpset <character> <give/take> <amount>\n\r");
    ch->SendText ("Amount must be a positive number greater than 0.\n\r");
    return;
  }

  if ((victim = get_char_world (ch, arg)) == NULL)
  {
    ch->SendText ("There is no such player currently playing.\n\r");
    return;
  }

  if (victim->IsNpc ())
  {
    ch->SendText ("Glory cannot be given to or taken from a mob.\n\r");
    return;
  }

  if (nifty_is_name_prefix (arg2, "give"))
    give = TRUE;
   else if (nifty_is_name_prefix (arg2, "take"))
    give = FALSE;
   else
    {
      do_qpset (ch, "");
      return;
    }

  if (give)
  {
    victim->GetPcData ()->quest_curr += amount;
    victim->GetPcData ()->quest_accum += amount;
    victim->SendTextf ("Your glory has been increased by %d.\n\r", amount);
  }
 else
  {
    victim->GetPcData ()->quest_curr -= amount;
    victim->SendTextf ("Your glory has been decreased by %d.\n\r", amount);
  }

  ch->SendText ("Ok.\n\r");
  return;
}


void do_showrace (CCharacter* ch, char* argument)
{
	char	arg1 [MAX_INPUT_LENGTH];
	char	arg2 [MAX_INPUT_LENGTH];

	set_pager_color (AT_PLAIN, ch);

	argument = one_argument (argument, arg1);
	if (arg1 [0] == '\0') {
		ch->SendText ("Syntax: showrace <race name> [wearnames]\n\r");
		ch->SendText ("Syntax: showrace list\r\n");
		return;
	}

	if (! str_cmp (arg1, "list")) {
		RaceTable.ListRaces (ch);
		return;
	}

	CRaceData &Ra = *RaceTable.Find (arg1);

	if (! &Ra) {
		ch->SendText ("No such race.\n\r");
		return;
	}

	argument = one_argument (argument, arg2);
	if (! str_cmp (arg2, "wearnames")) {
		Ra.ShowRacialWearNames (ch);
		return;
	}	
	
	ch->SendTextf ("RACE: %s\n\r", Ra.GetName ());
	ch->SendText ("Disallowed Classes: ");

	int	ct = 0;
	int cl;
	for (cl=0; cl < ClassTable.GetCount (); ++cl) {
		if (Ra.IsClassRestricted (cl)) {
			++ct; 
			ch->SendTextf ("%s ", ClassTable.GetName (cl));
			if (ct % 6 == 0)
				ch->SendText ("\n\r                    ");
		} 
	}
	if (ct % 6 || ct == 0)
		ch->SendText ("\n\r");

	ch->SendText ("Allowed Classes:    ");
	ct = 0;
	for (cl=0; cl < ClassTable.GetCount (); ++cl) {
		if (! Ra.IsClassRestricted (cl)) {
			++ct;
			ch->SendTextf ("%s ", ClassTable.GetName (cl));
			if (ct % 6 == 0)
				ch->SendText ("\n\r                    ");
		} 
	}
	if (ct % 6 || ct == 0)
		ch->SendText ("\n\r");

	ch->SendTextf ("Str Plus: %-3d\tDex Plus: %-3d\tWis Plus: %-3d\tInt Plus: %-3d\t\n\r",
		Ra.str_plus, Ra.dex_plus, Ra.wis_plus, Ra.int_plus);
	ch->SendTextf ("Con Plus: %-3d\tCha Plus: %-3d\tLck Plus: %-3d\n\r",
		Ra.con_plus, Ra.cha_plus, Ra.lck_plus);
	ch->SendTextf ("Hit Pts:  %-3d\tMana: %-3d\tAlign: %-4d\tAC: %-d\n\r",
		Ra.hit, Ra.mana, Ra.GetAlignment (), Ra.GetAcPlus ());
	ch->SendTextf ("Min Align: %d\tMax Align: %-d\t\tXP Mult: %-d%%\n\r",
		Ra.GetMinAlign (), Ra.GetMaxAlign (), Ra.GetExpMultiplier ());
	ch->SendTextf ("Height: %3d in.\t\tWeight: %4d lbs.\tHungerMod: %d\tThirstMod: %d\n\r",
		Ra.GetHeight (), Ra.GetWeight (), Ra.GetHungerMod (), Ra.GetThirstMod ());
	ch->SendTextf ("Recall Room: %d\t\tManaRegen: %d\t\tHpRegen %d\tShoveDrag %d\n\r",
		Ra.GetRaceRecall (), Ra.GetManaRegen (), Ra.GetHpRegen (),
			Ra.GetShoveDragModifier ());
	ch->SendTextf ("Racial Languages: %s\n\r",
		LanguageTable.PrintAssigned (Ra.GetLanguages ()));

	ch->SendTextf ("Affected by: %s\n\r",
		Ra.GetAffectFlags ().PrintString ());

	ch->SendTextf ("Resistant to: %s\n\r",
		flag_string (Ra.resist, ris_flags));

	ch->SendTextf ("Susceptible to: %s\n\r",
		flag_string (Ra.suscept, ris_flags));

	ch->SendTextf ("Saves: (P/D) %d (W) %d (P/P) %d (B) %d (S/S) %d\n\r",
		Ra.GetSavingPoisonDeath (), Ra.GetSavingWand (),
		Ra.GetSavingParaPetri (), Ra.GetSavingBreath (),
		Ra.GetSavingSpellstaff ());

	ch->SendTextf ("Innate Attacks: %s\n\r",
		Ra.GetAttackFlags ().PrintString ());

	ch->SendTextf ("Innate Defenses: %s\n\r",
		Ra.GetDefenseFlags ().PrintString ());
}


void do_setrace (CCharacter* ch, char* argument)
{
	char	arg1 [MAX_INPUT_LENGTH];
	char	arg2 [MAX_INPUT_LENGTH];
	char	arg3 [MAX_INPUT_LENGTH];
	int		value;

	set_char_color (AT_PLAIN, ch);

	smash_tilde (argument);
	argument = one_argument (argument, arg1);
	argument = one_argument (argument, arg2);
	if (arg1 [0] == '\0') {
		ch->SendText ("Syntax: setrace <race> <field> <value>\n\r");
		ch->SendText ("\n\rField being one of:\n\r");
		ch->SendText ("  create save writelist\n\r");
		ch->SendText ("  class strplus dexplus wisplus\n\r");
		ch->SendText ("  intplus conplus chaplus lckplus hit\n\r");
		ch->SendText ("  mana affected resist suscept language\n\r");
		ch->SendText ("  attack defense alignment acplus\n\r");
		ch->SendText ("  minalign maxalign height weight\n\r");
		ch->SendText ("  hungermod thirstmod expmultiplier\n\r");
		ch->SendText ("  saving_poison_death saving_wand\n\r");
		ch->SendText ("  saving_para_petri saving_breath\n\r");
		ch->SendText ("  saving_spell_staff  race_recall\n\r");
		ch->SendText ("  mana_regen hp_regen shove_drag\n\r");
		ch->SendText ("  wearname\n\r");
		return;
	}

	if (! str_cmp (arg1, "writelist")) {
		if (RaceTable.WriteList ())
			ch->SendText ("Race List Written\r\n");
		else
			ch->SendText ("Unable to write race list. See bug file for details.\r\n");
		return;
	}

	CRaceData &Ra = *RaceTable.Find (arg1);

	if (! str_cmp (arg2, "create")) {
		if (&Ra) {
			ch->SendTextf ("The %s race already exists.\r\n", Ra.GetName ());
			return;
		}
		CreateRace (ch, arg1, argument);
		return;
	}

	if (! &Ra) {
		ch->SendText ("No such race.\n\r");
		return;
	}

	if (! str_cmp (arg2, "save")) {
		Ra.Write ();
		ch->SendText ("Saved.\n\r");
		return;
	}

	if (! argument) {
		ch->SendText ("You must specify an argument.\n\r");
		return;
	}

	if (! str_cmp (arg2, "strplus")) {
		Ra.str_plus = atoi (argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "dexplus")) {
		Ra.dex_plus = atoi (argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "wisplus")) {
		Ra.wis_plus = atoi (argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "intplus")) {
		Ra.int_plus = atoi (argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "conplus")) {
		Ra.con_plus = atoi (argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "chaplus")) {
		Ra.cha_plus = atoi (argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "lckplus")) {
		Ra.lck_plus = atoi (argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "hit")) {
		Ra.hit = atoi (argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "mana")) {
		Ra.mana = atoi (argument);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "affected")) {
		if (! argument || argument [0] == '\0') {
			ch->SendText ("Usage: setrace <race> affected <flag> [flag]...\n\r");
			return;
		}
		CAffectFlags	Af = Ra.GetAffectFlags ();
		while (argument [0] != '\0') {
			argument = one_argument (argument, arg3);
			int	bit = CAffectFlags::GetVector (arg3);
			if (bit < 0)
				ch->SendTextf ("Unknown flag: %s\n\r", arg3);
			else
				Af.ToggleBit (bit);
		}
		Ra.SetAffectFlags (Af);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "resist")) {
		if (! argument || argument [0] == '\0') {
			ch->SendText ("Usage: setrace <race> resist <flag> [flag]...\n\r");
			return;
		}
		while (argument [0] != '\0') {
			argument = one_argument (argument, arg3);
			value = get_risflag (arg3);
			if (value < 0)
				ch->SendTextf ("Unknown flag: %s\n\r", arg3);
			else
				TOGGLE_BIT (Ra.resist, 1 << value);
		}
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "suscept")) {
		if (! argument || argument [0] == '\0') {
			ch->SendText ("Usage: setrace <race> suscept <flag> [flag]...\n\r");
			return;
		}
		while (argument [0] != '\0') {
			argument = one_argument (argument, arg3);
			value = get_risflag (arg3);
			if (value < 0)
				ch->SendTextf ("Unknown flag: %s\n\r", arg3);
			else
				TOGGLE_BIT (Ra.suscept, 1 << value);
		}
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "language")) {
		CLanguage	&La = *LanguageTable.Find (argument);
		if (! &La)
			ch->SendText ("No such Language.\n\r");
		else {
			int	lang = La.GetLanguage ();
			Ra.ToggleSpeaks (lang);
			ch->SendTextf ("Race can no%c speak %s.\n\r",
				Ra.CanSpeak (lang) ? 'w' : 't', argument);
		}
		return;
	}

	if (! str_cmp (arg2, "class")) {
		CClassData	&Cl = *ClassTable.Find (argument);
		if (! &Cl)
			ch->SendText ("No such class.\n\r");
		else {
			Ra.ToggleClassRestrict (Cl.GetClass ());
			ch->SendText ("Done.\n\r");
		}
		return;
	}


	if (! str_cmp (arg2, "acplus")) {
		Ra.SetAcPlus (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "alignment")) {
		Ra.SetAlignment (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	// not implemented
	if (! str_cmp (arg2, "defense")) {
		if (! argument || argument [0] == '\0') {
			ch->SendText ("Usage: setrace <race> defense <flag> [flag]...\n\r");
			return;
		}
		CDefenseFlags	Df = Ra.GetDefenseFlags ();
		while (argument [0] != '\0') {
			argument = one_argument (argument, arg3);
			value = get_defenseflag (arg3);
			if (value < 0)
				ch->SendTextf ("Unknown flag: %s\n\r", arg3);
			else
				Df.ToggleBit (value);
		}
		Ra.SetDefenseFlags (Df);
		ch->SendText ("Done.\n\r");
		return;
	}

	// not implemented
	if (! str_cmp (arg2, "attack")) {
		if (! argument || argument [0] == '\0') {
			ch->SendText ("Usage: setrace <race> attack <flag> [flag]...\n\r");
			return;
		}
		CAttackFlags	At = Ra.GetAttackFlags ();
		while (argument [0] != '\0') {
			argument = one_argument (argument, arg3);
			value = get_attackflag (arg3);
			if (value < 0)
				ch->SendTextf ("Unknown flag: %s\n\r", arg3);
			else
				At.ToggleBit (value);
		}
		Ra.SetAttackFlags (At);
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "minalign")) {
		Ra.SetMinAlign (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "maxalign")) {
		Ra.SetMaxAlign (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "height")) {
		Ra.SetHeight (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "weight")) {
		Ra.SetWeight (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "thirstmod")) {
		Ra.SetThirstMod (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "hungermod")) {
		Ra.SetHungerMod (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "expmultiplier")) {
		Ra.SetExpMultiplier (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "saving_poison_death")) {
		Ra.SetSavingPoisonDeath (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "saving_wand")) {
		Ra.SetSavingWand (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "saving_para_petri")) {
		Ra.SetSavingParaPetri (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "saving_breath")) {
		Ra.SetSavingBreath (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "saving_spell_staff")) {
		Ra.SetSavingSpellstaff (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "wearname")) {
		argument = one_argument (argument, arg3);
		CString	Arg = argument;
		Arg.TrimRight ();

		if (! isdigit (arg3 [0]) || Arg.IsEmpty ()) {
			ch->SendText ("Usage: setrace <race> wearname <position#> <name>\n\r");
			return;
		}
		WORD	pos = atoi (arg3);
		if (pos < 1 || pos > MAX_WEAR) {
			ch->SendTextf ("Use position values from 1 to %d.\r\n", MAX_WEAR);
			return;
		}

		int len = Arg.GetLength ();
		if (len > 18) {
			ch->SendText ("Max length of wear names is 18 (do not include angle brackets).\r\n");
			return;
		}

		if (Arg.GetAt (0) != '<') {
			Arg = '<' + Arg;
			++len;
		}
		if (Arg.GetAt (Arg.GetLength () - 1) != '>') {
			Arg += '>';
			++len;
		}
		if (len < 20) {
			CString	spc = "                    ";
			Arg += spc.Left (20 - len);
		}
		Ra.SetWhereName (pos-1, Arg);
		ch->SendText ("Done.\n\r");
		return;
	}

	// unimplemented stuff follows
	if (! str_cmp (arg2, "mana_regen")) {
		Ra.SetManaRegen (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "hp_regen")) {
		Ra.SetHpRegen (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "race_recall")) {
		Ra.SetRaceRecall (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	if (! str_cmp (arg2, "shove_drag")) {
		Ra.SetShoveDragModifier (atoi (argument));
		ch->SendText ("Done.\n\r");
		return;
	}

	do_setrace (ch,"");
}


void do_pcrename (CCharacter* ch, char* argument)
{
	CCharacter	*victim;
	char		arg1 [MAX_INPUT_LENGTH];
	char		arg2 [MAX_INPUT_LENGTH];

	if (ch->IsNpc ())
		return;

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

	if (arg1 [0] == '\0' || arg2 [0] == '\0') {
		ch->SendText ("Syntax: rename <victim> <new name>\n\r");
		return;
	}

	// Just a security precaution so you don't rename someone you don't mean 
	// to --Shaddai
	if ((victim = get_char_room (ch, arg1)) == NULL) {
		ch->SendText ("That person is not in the room.\n\r");
		return;
	}

	CString	NewName = capitalize (arg2);
	if (! check_parse_name (NewName)) {
		ch->SendText ("Illegal name.\n\r");
		return;
	}

	CString	Npass = Crypt ("pass", NewName);
	if (Npass.Find ('~') >= 0) {
		ch->SendText ("Illegal name.\n\r");
		return;
	}

	if (victim->IsNpc ()) {
		ch->SendText ("You can't rename NPC's.\n\r");
		return;
	}

	if (ch->GetTrustLevel () < victim->GetTrustLevel ()) {
		ch->SendText ("I don't think they would like that!\n\r");
		return;
	}

	CString	NFname = FileTable.PlayerName (NewName);

	if (FileTable.Exists (NFname)) {
		ch->SendText ("That name already exists.\n\r");
		return;
	}

	// Have to remove the old god entry in the directories
	if (victim->IsImmortal ()) {
		CString	GodName = FileTable.MakeName (SD_GOD_DIR, victim->GetName ());
		remove (GodName);	
	}

	// Remember to change the names of the areas
	if (victim->GetArea ()) {
		CString	Aname = FileTable.MakeBuildName (victim->GetName ());
		CString	NAname = FileTable.MakeBuildName (arg2);

		rename (Aname, NAname);
		rename (FileTable.MakeBackupName (Aname),
				FileTable.MakeBackupName (NAname));
	}

	CString	OldName = FileTable.PlayerName (victim->GetName ());
	CString	BakName = FileTable.BackupPlayerName (victim->GetName ());

	remove (BakName);
	if (remove (OldName))
		ch->SendTextf ("Couldn't delete the old file: %s\n\r", OldName);

	// Time to save to force the affects to take place
	victim->SetName (NewName);    
	delete victim->GetPcData ()->GetPassWord ();
	victim->GetPcData ()->SetPassWord (str_dup (Npass));
	save_char_obj (victim);

	// Now lets update the wizlist
	if (victim->IsImmortal ())
		make_wizlist ();

	ch->SendText ("Character was renamed.\n\r");
	victim->SendTextf ("%s has changed your character's name to %s.\r\n",
		ch->GetName (), NewName);
	victim->SendText ("You have been assigned a temporary password: pass.\r\n");
	victim->SendText ("Be sure to change your password right "
		"away (See Help password).\r\n");
}


void save_reserved ()
{
	FILE	*fp = NULL;

	CString	Fname = FileTable.MakeName (SD_SYSTEM_DIR, "reserved.lst"); 

	fclose (fpReserve);
	if (fp = fopen (Fname, "w")) {
		POSITION	pos = ReservedNamesList.GetHeadPosition ();
		while (pos)
			fprintf (fp, "%s~\n", ReservedNamesList.GetNext (pos));

		fprintf (fp, "$~\n");
		fclose (fp);
	}
	else
		bug ("Save_reserved: cannot open %s", Fname);

	fpReserve = fopen (FileTable.GetName (SM_NULL_FILE), "r");
}


void do_reserve (CCharacter* ch, char* argument)
{
	char	arg [MAX_INPUT_LENGTH];

	set_char_color (AT_PLAIN, ch);

	argument = one_argument (argument, arg);
	if (! *arg) {
		int		wid = 0;

		ch->SendText ("-- Reserved Names --\n\r");
		POSITION	pos = ReservedNamesList.GetHeadPosition ();
		while (pos) {
			CString	Rname = ReservedNamesList.GetNext (pos);
			if (! Rname.IsEmpty ()) {
				if (Rname [0] != '*')
					ch->SendTextf (" %-17s ", Rname);
				else
					ch->SendTextf ("%-18s ", Rname);
				if (++wid % 4 == 0)
					ch->SendText ("\n\r");
			}
		}
		if (wid % 4 != 0)
			ch->SendText ("\n\r");
		return;
	}

	POSITION	CurPos, pos = ReservedNamesList.GetHeadPosition ();
	while (pos) {
		CurPos = pos;
		CString	Rname = ReservedNamesList.GetNext (pos);
		if (! Rname.CompareNoCase (arg)) {
			ReservedNamesList.RemoveAt (CurPos);
			save_reserved ();
			ch->SendText ("Name no longer reserved.\n\r");
			return;
		}
	}

	ReservedNamesList.AddTail (arg);
	save_reserved ();
	ch->SendText ("Name reserved.\n\r");
}