1stMUD4.0/bin/
1stMUD4.0/doc/MPDocs/
1stMUD4.0/player/
1stMUD4.0/win32/
1stMUD4.0/win32/rom/
/**************************************************************************
*  Original Diku Mud copyright (C) 1990, 1991 by Sebastian Hammer,        *
*  Michael Seifert, Hans Henrik St{rfeldt, Tom Madsen, and Katja Nyboe.   *
*                                                                         *
*  Merc Diku Mud improvements copyright (C) 1992, 1993 by Michael         *
*  Chastain, Michael Quan, and Mitchell Tse.                              *
*                                                                         *
*  In order to use any part of this Merc Diku Mud, you must comply with   *
*  both the original Diku license in 'license.doc' as well the Merc       *
*  license in 'license.txt'.  In particular, you may not remove either of *
*  these copyright notices.                                               *
*                                                                         *
*  Much time and thought has gone into this software and you are          *
*  benefiting.  We hope that you share your changes too.  What goes       *
*  around, comes around.                                                  *
***************************************************************************
*       ROM 2.4 is copyright 1993-1998 Russ Taylor                        *
*       ROM has been brought to you by the ROM consortium                 *
*           Russ Taylor (rtaylor@hypercube.org)                           *
*           Gabrielle Taylor (gtaylor@hypercube.org)                      *
*           Brian Moore (zump@rom.org)                                    *
*       By using this code, you have agreed to follow the terms of the    *
*       ROM license, in the file Rom24/doc/rom.license                    *
***************************************************************************
*       1stMUD ROM Derivative (c) 2001-2003 by Ryan Jennings              *
*            http://1stmud.dlmud.com/  <r-jenn@shaw.ca>                   *
***************************************************************************/

#include "merc.h"
#include "interp.h"
#include "magic.h"
#include "recycle.h"
#include "tables.h"
#include "lookup.h"

char *const where_name[] = {
	"{g<{Wused as light{g>{x     ",
	"{g<{Wworn on finger{g>{x    ",
	"{g<{Wworn on finger{g>{x    ",
	"{g<{Wworn around neck{g>{x  ",
	"{g<{Wworn around neck{g>{x  ",
	"{g<{Wworn on torso{g>{x     ",
	"{g<{Wworn on head{g>{x      ",
	"{g<{Wworn on legs{g>{x      ",
	"{g<{Wworn on feet{g>{x      ",
	"{g<{Wworn on hands{g>{x     ",
	"{g<{Wworn on arms{g>{x      ",
	"{g<{Wworn as shield{g>{x    ",
	"{g<{Wworn about body{g>{x   ",
	"{g<{Wworn about waist{g>{x  ",
	"{g<{Wworn around wrist{g>{x ",
	"{g<{Wworn around wrist{g>{x ",
	"{g<{Wwielded{g>{x           ",
	"{g<{Wheld{g>{x              ",
	"{g<{Wfloating nearby{g>{x   ",
	"{g<{Wsecondary weapon{g>{x  "
};

/*
 * Local functions.
 */
PROTOTYPE(char *format_obj_to_char, (OBJ_DATA *, CHAR_DATA *, bool));
PROTOTYPE(void show_list_to_char, (OBJ_DATA *, CHAR_DATA *, bool, bool));
PROTOTYPE(void show_char_to_char_0, (CHAR_DATA *, CHAR_DATA *));
PROTOTYPE(void show_char_to_char_1, (CHAR_DATA *, CHAR_DATA *));
PROTOTYPE(void show_char_to_char, (CHAR_DATA *, CHAR_DATA *));
PROTOTYPE(bool check_blind, (CHAR_DATA *));

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

	buf[0] = '\0';

	if ((fShort &&
		 IS_NULLSTR(obj->short_descr)) || IS_NULLSTR(obj->description))
		return buf;

	if (IS_OBJ_STAT(obj, ITEM_INVIS))
		strcat(buf, "({cInvis{x) ");
	if (IS_AFFECTED(ch, AFF_DETECT_EVIL) && IS_OBJ_STAT(obj, ITEM_EVIL))
		strcat(buf, "({RRed Aura{x) ");
	if (IS_AFFECTED(ch, AFF_DETECT_GOOD) && IS_OBJ_STAT(obj, ITEM_BLESS))
		strcat(buf, "({BBlue Aura{x) ");
	if (IS_AFFECTED(ch, AFF_DETECT_MAGIC) && IS_OBJ_STAT(obj, ITEM_MAGIC))
		strcat(buf, "({MMagical{x) ");
	if (IS_OBJ_STAT(obj, ITEM_GLOW))
		strcat(buf, "({YGlowing{x) ");
	if (IS_OBJ_STAT(obj, ITEM_HUM))
		strcat(buf, "({CHumming{x) ");

	if (IS_QUESTOR(ch) && (obj->pIndexData->vnum == ch->pcdata->questobj))
		strcat(buf, "{r[{RTARGET{r]{x ");

	if (fShort)
	{
		if (obj->short_descr != NULL)
			strcat(buf, obj->short_descr);
	}
	else
	{
		if (obj->description != NULL)
			strcat(buf, obj->description);
	}

	return buf;
}

/*
 * Show a list to a character.
 * Can coalesce duplicated items.
 */
void show_list_to_char(OBJ_DATA * list, CHAR_DATA * ch, bool fShort,
					   bool fShowNothing)
{
	BUFFER *output;
	const char **prgpstrShow;
	int *prgnShow;
	char *pstrShow;
	OBJ_DATA *obj;
	int nShow;
	int iShow;
	int count;
	bool fCombine;

	if (ch->desc == NULL)
		return;

	/*
	 * Alloc space for output lines.
	 */
	output = new_buf();

	count = 0;
	for (obj = list; obj != NULL; obj = obj->next_content)
		count++;
	alloc_mem(prgpstrShow, const char *, count);
	alloc_mem(prgnShow, int, count);
	nShow = 0;

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

			fCombine = FALSE;

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

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

	/*
	 * Output the formatted list.
	 */
	for (iShow = 0; iShow < nShow; iShow++)
	{
		if (prgpstrShow[iShow][0] == '\0')
		{
			free_string(prgpstrShow[iShow]);
			continue;
		}

		if (IS_NPC(ch) || IS_SET(ch->comm, COMM_COMBINE))
		{
			if (prgnShow[iShow] != 1)
			{
				bprintf(output, "(%2d) ", prgnShow[iShow]);
			}
			else
			{
				bprint(output, "     ");
			}
		}
		bprintln(output, prgpstrShow[iShow]);
		free_string(prgpstrShow[iShow]);
	}

	if (fShowNothing && nShow == 0)
	{
		if (IS_NPC(ch) || IS_SET(ch->comm, COMM_COMBINE))
			chprint(ch, "     ");
		chprintln(ch, "Nothing.");
	}
	sendpage(ch, buf_string(output));

	/*
	 * Clean up.
	 */
	free_buf(output);
	free_mem(prgpstrShow);
	free_mem(prgnShow);

	return;
}

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

	buf[0] = '\0';

	if (IS_SET(victim->comm, COMM_AFK))
		strcat(buf, "{Y[{RAFK{Y]{x ");
	if (IS_AFFECTED(victim, AFF_INVISIBLE))
		strcat(buf, "({cInvis{x) ");
	if (victim->invis_level >= LEVEL_HERO)
		strcat(buf, "{c({WWizi{c){x ");
	if (IS_AFFECTED(victim, AFF_HIDE))
		strcat(buf, "({DHide{x) ");
	if (IS_AFFECTED(victim, AFF_CHARM))
		strcat(buf, "({MCharmed{x) ");
	if (IS_AFFECTED(victim, AFF_PASS_DOOR))
		strcat(buf, "({cTranslucent{x) ");
	if (IS_AFFECTED(victim, AFF_FAERIE_FIRE))
		strcat(buf, "({MPink Aura{x) ");
	if (IS_EVIL(victim) && IS_AFFECTED(ch, AFF_DETECT_EVIL))
		strcat(buf, "({RRed Aura{x) ");
	if (IS_GOOD(victim) && IS_AFFECTED(ch, AFF_DETECT_GOOD))
		strcat(buf, "({YGolden Aura{x) ");
	if (IS_AFFECTED(victim, AFF_SANCTUARY))
		strcat(buf, "({WWhite Aura{x) ");
	if (IS_IN_WAR(victim))
		strcat(buf, "({RWAR{x) ");
	if (!IS_NPC(victim) && IS_SET(victim->act, PLR_KILLER))
		strcat(buf, "({rKILLER{x) ");
	if (!IS_NPC(victim) && IS_SET(victim->act, PLR_THIEF))
		strcat(buf, "({rTHIEF{x) ");
	if (IS_QUESTOR(ch) && IS_NPC(victim)
		&& (victim->pIndexData->vnum == ch->pcdata->questmob))
		strcat(buf, "{r[{RTARGET{r]{x ");

	if (ON_GQUEST(ch) && IS_NPC(victim)
		&& is_gqmob(ch->gquest, victim->pIndexData->vnum) != -1)
	{
		strcat(buf, "{Y({RGquest{Y){x ");
	}

	if (victim->position == victim->start_pos
		&& !IS_NULLSTR(victim->long_descr))
	{
		strcat(buf, victim->long_descr);
		chprint(ch, buf);
		return;
	}

	strcat(buf, PERS(victim, ch));
	if (!IS_NPC(victim) && !IS_SET(ch->comm, COMM_BRIEF) &&
		victim->position == POS_STANDING && ch->on == NULL)
		strcat(buf, victim->pcdata->title);

	switch (victim->position)
	{
	case POS_DEAD:
		strcat(buf, " is DEAD!!");
		break;
	case POS_MORTAL:
		strcat(buf, " is mortally wounded.");
		break;
	case POS_INCAP:
		strcat(buf, " is incapacitated.");
		break;
	case POS_STUNNED:
		strcat(buf, " is lying here stunned.");
		break;
	case POS_SLEEPING:
		if (victim->on != NULL)
		{
			if (IS_SET(victim->on->value[2], SLEEP_AT))
			{
				sprintf(message, " is sleeping at %s.",
						victim->on->short_descr);
				strcat(buf, message);
			}
			else if (IS_SET(victim->on->value[2], SLEEP_ON))
			{
				sprintf(message, " is sleeping on %s.",
						victim->on->short_descr);
				strcat(buf, message);
			}
			else
			{
				sprintf(message, " is sleeping in %s.",
						victim->on->short_descr);
				strcat(buf, message);
			}
		}
		else
			strcat(buf, " is sleeping here.");
		break;
	case POS_RESTING:
		if (victim->on != NULL)
		{
			if (IS_SET(victim->on->value[2], REST_AT))
			{
				sprintf(message, " is resting at %s.", victim->on->short_descr);
				strcat(buf, message);
			}
			else if (IS_SET(victim->on->value[2], REST_ON))
			{
				sprintf(message, " is resting on %s.", victim->on->short_descr);
				strcat(buf, message);
			}
			else
			{
				sprintf(message, " is resting in %s.", victim->on->short_descr);
				strcat(buf, message);
			}
		}
		else
			strcat(buf, " is resting here.");
		break;
	case POS_SITTING:
		if (victim->on != NULL)
		{
			if (IS_SET(victim->on->value[2], SIT_AT))
			{
				sprintf(message, " is sitting at %s.", victim->on->short_descr);
				strcat(buf, message);
			}
			else if (IS_SET(victim->on->value[2], SIT_ON))
			{
				sprintf(message, " is sitting on %s.", victim->on->short_descr);
				strcat(buf, message);
			}
			else
			{
				sprintf(message, " is sitting in %s.", victim->on->short_descr);
				strcat(buf, message);
			}
		}
		else
			strcat(buf, " is sitting here.");
		break;
	case POS_STANDING:
		if (victim->on != NULL)
		{
			if (IS_SET(victim->on->value[2], STAND_AT))
			{
				sprintf(message, " is standing at %s.",
						victim->on->short_descr);
				strcat(buf, message);
			}
			else if (IS_SET(victim->on->value[2], STAND_ON))
			{
				sprintf(message, " is standing on %s.",
						victim->on->short_descr);
				strcat(buf, message);
			}
			else
			{
				sprintf(message, " is standing in %s.",
						victim->on->short_descr);
				strcat(buf, message);
			}
		}
		else
			strcat(buf, " is here.");
		break;
	case POS_FIGHTING:
		strcat(buf, " is here, fighting ");
		if (victim->fighting == NULL)
			strcat(buf, "thin air??");
		else if (victim->fighting == ch)
			strcat(buf, "YOU!");
		else if (victim->in_room == victim->fighting->in_room)
		{
			strcat(buf, PERS(victim->fighting, ch));
			strcat(buf, ".");
		}
		else
			strcat(buf, "someone who left??");
		break;
	default:
		break;
	}

	buf[0] = UPPER(buf[0]);
	chprintln(ch, buf);
	return;
}

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

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

	if (!IS_NULLSTR(victim->description))
	{
		chprint(ch, victim->description);
	}
	else
	{
		act("You see nothing special about $M.", ch, NULL, victim, TO_CHAR);
	}

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

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

	if (percent >= 100)
		strcat(buf, " is in excellent condition.\n\r");
	else if (percent >= 90)
		strcat(buf, " has a few scratches.\n\r");
	else if (percent >= 75)
		strcat(buf, " has some small wounds and bruises.\n\r");
	else if (percent >= 50)
		strcat(buf, " has quite a few wounds.\n\r");
	else if (percent >= 30)
		strcat(buf, " has some big nasty wounds and scratches.\n\r");
	else if (percent >= 15)
		strcat(buf, " looks pretty hurt.\n\r");
	else if (percent >= 0)
		strcat(buf, " is in awful condition.\n\r");
	else
		strcat(buf, " is bleeding to death.\n\r");

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

	found = FALSE;
	for (iWear = 0; iWear < MAX_WEAR; iWear++)
	{
		if ((obj = get_eq_char(victim, (wloc_t) iWear)) != NULL
			&& can_see_obj(ch, obj))
		{
			if (!found)
			{
				chprintln(ch, "");
				act("$N is using:", ch, NULL, victim, TO_CHAR);
				found = TRUE;
			}
			chprint(ch, where_name[iWear]);
			chprintln(ch, format_obj_to_char(obj, ch, TRUE));
		}
	}

	if (victim != ch && !IS_NPC(ch) &&
		number_percent() < get_skill(ch, gsn_peek))
	{
		chprintln(ch, "\n\rYou peek at the inventory:");
		check_improve(ch, gsn_peek, TRUE, 4);
		show_list_to_char(victim->first_carrying, ch, TRUE, TRUE);
	}

	return;
}

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

	for (rch = list; rch != NULL; rch = rch->next_in_room)
	{
		if (rch == ch)
			continue;

		if (get_trust(ch) < rch->invis_level)
			continue;

		if (can_see(ch, rch))
		{
			show_char_to_char_0(rch, ch);
		}
		else if (room_is_dark(ch->in_room) && IS_AFFECTED(rch, AFF_INFRARED))
		{
			chprintln(ch, "You see glowing red eyes watching YOU!");
		}
	}

	return;
}

bool check_blind(CHAR_DATA * ch)
{

	if (!IS_NPC(ch) && IS_SET(ch->act, PLR_HOLYLIGHT))
		return TRUE;

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

	return TRUE;
}

int get_scr_cols(CHAR_DATA * ch)
{
	unsigned int len;

	if (!ch)
		len = DEFAULT_SCR_WIDTH;
	else if (ch->columns <= 10)
		len = SCR_WIDTH(ch->desc);
	else
		len = ch->columns;

	return len - 2;
}

int get_scr_lines(CHAR_DATA * ch)
{
	unsigned int len;

	if (!ch)
		len = DEFAULT_SCR_HEIGHT;
	else if (!ch->lines)
		len = SCR_HEIGHT(ch->desc);
	else
		len = ch->lines;

	return len - 2;
}

CH_CMD(do_screen)
{
	char arg1[MIL], arg2[MIL];
	unsigned int lines;
	int *plines;
	char *func;
	unsigned int def_lines;

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

	if (IS_NULLSTR(arg1) || IS_NULLSTR(arg2))
	{
		if (get_scr_lines(ch) < 0)
			chprintln(ch, "You do not page long messages.");
		else
		{
			chprintlnf(ch, "You currently display %d lines per page.",
					   get_scr_lines(ch));
		}
		chprintlnf(ch, "\n\rYou currently display %d columns per line.",
				   get_scr_cols(ch));
		chprintln(ch, "\n\rSyntax: screen lines|columns <#val|default>");
		chprintlnf(ch,
				   "        (type 'screen lines none' to disable scrolling)");
		return;
	}
	if (!str_prefix(arg1, "lines"))
	{
		if (!str_cmp(arg2, "none") || atoi(arg2) < 0)
		{
			ch->lines = -1;
			chprintln
				(ch,
				 "Scrolling disabled.  This may cause you to disconnect on long outputs.");
			return;
		}
		plines = &ch->lines;
		func = "lines";
		def_lines = SCR_HEIGHT(ch->desc);
	}
	else if (!str_prefix(arg1, "columns"))
	{
		plines = &ch->columns;
		func = "columns";
		def_lines = SCR_WIDTH(ch->desc);
	}
	else
	{
		do_screen(ch, "");
		return;
	}

	if (!str_cmp(arg2, "default"))
	{
		*plines = def_lines;
		chprintlnf(ch, "You're screen now displays %d %s.", def_lines, func);
		return;
	}
	else if (!is_number(arg2))
	{
		chprintln(ch, "You must provide a number.");
		return;
	}

	lines = atoi(arg2);

	if (lines < 10 || lines > 250)
	{
		chprintln(ch, "You must provide a reasonable number.");
		return;
	}

	chprintlnf(ch, "Your screen now displays %d %s.", lines, func);
	if (ch->desc && IS_SET(ch->desc->d_flags, DESC_TELOPT_NAWS)
		&& lines != def_lines)
		chprintlnf
			(ch, "The MUD has detected that you have %d screen %s.",
			 def_lines, func);
	*plines = lines;
}

/* RT does socials */
CH_CMD(do_socials)
{
	SOCIAL_DATA *iSocial;
	int col;

	col = 0;

	for (iSocial = social_first; iSocial != NULL; iSocial = iSocial->next)
	{
		chprintf(ch, "%-12s", iSocial->name);
		if (++col % 6 == 0)
			chprintln(ch, "");
	}

	if (col % 6 != 0)
		chprintln(ch, "");
	return;
}

/* RT Commands to replace news, motd, imotd, etc from ROM */

CH_CMD(do_motd)
{
	do_function(ch, &do_oldhelp, "motd");
}

CH_CMD(do_imotd)
{
	do_function(ch, &do_oldhelp, "imotd");
}

CH_CMD(do_rules)
{
	do_function(ch, &do_oldhelp, "rules");
}

CH_CMD(do_story)
{
	do_function(ch, &do_oldhelp, "story");
}

CH_CMD(do_wizlist)
{
	do_function(ch, &do_oldhelp, "wizlist");
}

/* RT this following section holds all the auto commands from ROM, as well as
   replacements for config */

CH_CMD(do_autolist)
{
	/* lists most player flags */
	if (IS_NPC(ch))
		return;

	chprintlnf(ch, " %-9s %-6s{w %s", "Command", "Status", "Description");
	chprintln(ch, draw_line(ch, NULL, 0));

	print_on_off(ch, IS_SET(ch->act, PLR_AUTOMAP), "automap",
				 "Map in Room Descriptions");
	print_on_off(ch, IS_SET(ch->act, PLR_AUTODAMAGE), "autodamage",
				 "Displays damage amounts in combat.");
	print_on_off(ch, IS_SET(ch->act, PLR_AUTOASSIST), "autoassist",
				 "Automatically assists group members.");
	print_on_off(ch, IS_SET(ch->act, PLR_AUTOEXIT), "autoexit",
				 "Displays exits in room descriptions.");
	print_on_off(ch, IS_SET(ch->act, PLR_AUTOGOLD), "autogold",
				 "Automatically loots gold from corpses.");
	print_on_off(ch, IS_SET(ch->act, PLR_AUTOLOOT), "autoloot",
				 "Automatically loots objects from corpses.");
	print_on_off(ch, IS_SET(ch->act, PLR_AUTOSAC), "autosac",
				 "Automatically sacrifices corpses.");
	print_on_off(ch, IS_SET(ch->act, PLR_AUTOSPLIT), "autosplit",
				 "Automatically splits gold between group members.");
	print_on_off(ch, IS_SET(ch->comm, COMM_COMPACT), "compact",
				 "Compacts mud output.");
	print_on_off(ch, IS_SET(ch->comm, COMM_PROMPT), "prompt",
				 "Displays prompt information.");
	print_on_off(ch, IS_SET(ch->comm, COMM_COMBINE), "combine",
				 "Combines duplicate objects in display.");
	print_on_off(ch, !IS_SET(ch->act, PLR_CANLOOT), "noloot",
				 "Sets players unable to loot your corpse.");
	print_on_off(ch, IS_SET(ch->act, PLR_NOSUMMON), "nosummon",
				 "Sets you unable to be summoned.");
	print_on_off(ch, IS_SET(ch->act, PLR_NOFOLLOW), "nofollow",
				 "Stops others from following you.");

	chprintln(ch, draw_line(ch, NULL, 0));
}

CH_CMD(do_autoassist)
{
	if (IS_NPC(ch))
		return;

	set_on_off(ch, &ch->act, PLR_AUTOASSIST,
			   "You now assist group members in combat.",
			   "You no longer assist group members in combat.");
}

CH_CMD(do_autodamage)
{
	if (IS_NPC(ch))
		return;

	set_on_off(ch, &ch->act, PLR_AUTODAMAGE,
			   "You now see damage amounts in combat.",
			   "You no longer see damage amounts in combat.");
}

CH_CMD(do_autoexit)
{
	if (IS_NPC(ch))
		return;

	set_on_off(ch, &ch->act, PLR_AUTOEXIT, "Exits will now be displayed.",
			   "Exits will no longer be displayed.");
}

CH_CMD(do_autogold)
{
	if (IS_NPC(ch))
		return;

	set_on_off(ch, &ch->act, PLR_AUTOGOLD,
			   "You now loot gold from corpses automatically.",
			   "You no longer loot gold from corpses automatically.");
}

CH_CMD(do_autoloot)
{
	if (IS_NPC(ch))
		return;

	set_on_off(ch, &ch->act, PLR_AUTOLOOT,
			   "You now loot objects from corpses automatically.",
			   "You no longer loot objects from corpses automatically.");
}

CH_CMD(do_autosac)
{
	if (IS_NPC(ch))
		return;

	set_on_off(ch, &ch->act, PLR_AUTOSAC,
			   "You now sacrifice corpses automatically.",
			   "You no longer automatically sacrifice corpses.");
}

CH_CMD(do_autosplit)
{
	if (IS_NPC(ch))
		return;

	set_on_off(ch, &ch->act, PLR_AUTOSPLIT,
			   "You now split gold with group members.",
			   "You no longer split gold with group members.");
}

CH_CMD(do_brief)
{
	set_on_off(ch, &ch->comm, COMM_BRIEF,
			   "You no longer see room descriptions.",
			   "You now see room descriptions.");
}

CH_CMD(do_compact)
{
	set_on_off(ch, &ch->comm, COMM_COMPACT, "Compact mode set.",
			   "Compact mode removed.");
}

CH_CMD(do_show)
{
	set_on_off(ch, &ch->comm, COMM_SHOW_AFFECTS,
			   "Affects will now be shown in score.",
			   "Affects will no longer be shown in score.");
}

CH_CMD(do_prompt)
{
	char buf[MAX_STRING_LENGTH];

	if (IS_NULLSTR(argument))
	{
		set_on_off(ch, &ch->comm, COMM_PROMPT, "You will now see prompts.",
				   "You will no longer see prompts.");
		return;
	}

	else if (!str_prefix(argument, "autoprompt"))
	{
		set_on_off(ch, &ch->act, PLR_AUTOPROMPT,
				   "Prompts will now always show.",
				   "Prompts are now selectivly shown.");
		return;
	}
	else if (!str_cmp(argument, "all"))
		strcpy(buf, "<%hhp %mm %vmv> ");
	else
	{
		strcpy(buf, argument);
		if (strlen(buf) > 50)
			buf[50] = '\0';
		smash_tilde(buf);
		if (str_suffix("%c", buf))
			strcat(buf, " ");

	}

	replace_string(ch->prompt, buf);
	chprintlnf(ch, "Prompt set to %s", ch->prompt);
	return;
}

CH_CMD(do_combine)
{
	set_on_off(ch, &ch->comm, COMM_COMBINE, "Combined inventory selected.",
			   "Long inventory selected.");
}

CH_CMD(do_noloot)
{
	if (IS_NPC(ch))
		return;

	set_on_off(ch, &ch->act, PLR_CANLOOT,
			   "Other players can now loot your corpse.",
			   "Other players can no longer loot your corpse.");
}

CH_CMD(do_nofollow)
{
	if (IS_NPC(ch))
		return;

	set_on_off(ch, &ch->act, PLR_NOFOLLOW, "You no longer accept followers.",
			   "You accept followers once again.");

	if (IS_SET(ch->act, PLR_NOFOLLOW))
		die_follower(ch);
}

CH_CMD(do_nosummon)
{
	if (IS_NPC(ch))
	{
		set_on_off(ch, &ch->imm_flags, IMM_SUMMON,
				   "You are now immune to summoning.",
				   "You can be summoned once again.");
	}
	else
	{
		set_on_off(ch, &ch->act, PLR_NOSUMMON,
				   "You are now immune to summoning.",
				   "You can be summoned once again.");
	}
}

bool is_last_run(CHAR_DATA * ch)
{
	if (IS_NPC(ch))
		return TRUE;

	if (!ch->desc)
		return TRUE;

	if (!ch->desc->run_buf)
		return TRUE;

	if (IS_NULLSTR(ch->desc->run_head))
		return TRUE;

	if (tolower(ch->desc->run_head[0]) == 'o'
		&& strlen(ch->desc->run_head) <= 2)
		return TRUE;

	if (ch->desc->run_head[0] == '0' && strlen(ch->desc->run_head) <= 2)
		return TRUE;

	return FALSE;
}

CH_CMD(do_look)
{
	char buf[MAX_STRING_LENGTH];
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char arg3[MAX_INPUT_LENGTH];
	EXIT_DATA *pexit;
	CHAR_DATA *victim;
	OBJ_DATA *obj;
	const char *pdesc;
	int door;
	int number, count;

	if (ch->desc == NULL)
		return;

	if (ch->position < POS_SLEEPING)
	{
		chprintln(ch, "You can't see anything but stars!");
		return;
	}

	if (ch->position == POS_SLEEPING)
	{
		chprintln(ch, "You can't see anything, you're sleeping!");
		return;
	}

	if (!check_blind(ch))
		return;

	if (!IS_NPC(ch) && !IS_SET(ch->act, PLR_HOLYLIGHT) &&
		room_is_dark(ch->in_room))
	{
		chprintln(ch, "It is pitch black ... ");
		show_char_to_char(ch->in_room->first_person, ch);
		return;
	}

	argument = one_argument(argument, arg1);
	argument = one_argument(argument, arg2);
	number = number_argument(arg1, arg3);
	count = 0;

	if (IS_NULLSTR(arg1) || !str_cmp(arg1, "auto"))
	{
		/* 'look' or 'look auto' */
		chprint(ch, MXPTAG("RName"));
		chprintf(ch, "" CTAG(_RTITLE) "%s", ch->in_room->name);
		chprint(ch, MXPTAG("/RName"));

		if ((IS_IMMORTAL(ch) &&
			 (IS_NPC(ch) || IS_SET(ch->act, PLR_HOLYLIGHT))) ||
			IS_BUILDER(ch, ch->in_room->area))
		{
			chprintf(ch, " {w[{WRoom {R%ld{w]", ch->in_room->vnum);
		}

		chprintln(ch, "{x");

		if (IS_NULLSTR(arg1) || (!IS_NPC(ch) && !IS_SET(ch->comm, COMM_BRIEF)))
		{
			if (is_last_run(ch))
			{
				chprint(ch, MXPTAG("RDesc"));
				if (!IS_SET(ch->in_room->room_flags, ROOM_NOAUTOMAP)
					&& !IS_NPC(ch) && IS_SET(ch->act, PLR_AUTOMAP))
				{
					sprintf(buf, "%s%s{x",
							get_sector_color(ch->in_room->sector_type),
							IS_NULLSTR(ch->in_room->description) ?
							"No room description!" : ch->in_room->description);
					draw_map(ch, buf);
				}
				else
				{
					dwraplnf(ch->desc, "%s%s{x",
							 get_sector_color(ch->in_room->sector_type),
							 IS_NULLSTR(ch->in_room->description) ?
							 "No room description!" : ch->in_room->description);
				}
				chprint(ch, MXPTAG("/RDesc"));
			}
		}

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

		show_list_to_char(ch->in_room->first_content, ch, FALSE, FALSE);
		show_char_to_char(ch->in_room->first_person, ch);
		return;
	}

	if (!str_cmp(arg1, "i") || !str_cmp(arg1, "in") || !str_cmp(arg1, "on"))
	{
		/* 'look in' */
		if (IS_NULLSTR(arg2))
		{
			chprintln(ch, "Look in what?");
			return;
		}

		if ((obj = get_obj_here(ch, NULL, arg2)) == NULL)
		{
			chprintln(ch, "You do not see that here.");
			return;
		}

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

		case ITEM_DRINK_CON:
			if (obj->value[1] <= 0)
			{
				chprintln(ch, "It is empty.");
				break;
			}

			chprintlnf(ch, "It's %sfilled with  a %s liquid.",
					   obj->value[1] <
					   obj->value[0] /
					   4 ? "less than half-" : obj->value[1] <
					   3 * obj->value[0] /
					   4 ? "about half-" : "more than half-",
					   liq_table[obj->value[2]].liq_color);

			break;

		case ITEM_CONTAINER:
		case ITEM_CORPSE_NPC:
		case ITEM_CORPSE_PC:
			if (IS_SET(obj->value[1], CONT_CLOSED))
			{
				chprintln(ch, "It is closed.");
				break;
			}

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

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

	for (obj = ch->first_carrying; obj != NULL; obj = obj->next_content)
	{
		if (can_see_obj(ch, obj))
		{						/* player can see object */
			pdesc = get_extra_descr(arg3, obj->first_extra_descr);
			if (pdesc != NULL)
			{
				if (++count == number)
				{
					chprint(ch, pdesc);
					return;
				}
				else
					continue;
			}
			pdesc = get_extra_descr(arg3, obj->pIndexData->first_extra_descr);
			if (pdesc != NULL)
			{
				if (++count == number)
				{
					chprint(ch, pdesc);
					return;
				}
				else
					continue;
			}
			if (is_name(arg3, obj->name))
				if (++count == number)
				{
					chprint(ch, obj->description);
					chprintln(ch, "");
					return;
				}
		}
	}

	for (obj = ch->in_room->first_content; obj != NULL; obj = obj->next_content)
	{
		if (can_see_obj(ch, obj))
		{
			pdesc = get_extra_descr(arg3, obj->first_extra_descr);
			if (pdesc != NULL)
				if (++count == number)
				{
					chprint(ch, pdesc);
					return;
				}

			pdesc = get_extra_descr(arg3, obj->pIndexData->first_extra_descr);
			if (pdesc != NULL)
				if (++count == number)
				{
					chprint(ch, pdesc);
					return;
				}

			if (is_name(arg3, obj->name))
				if (++count == number)
				{
					chprint(ch, obj->description);
					chprintln(ch, "");
					return;
				}
		}
	}

	pdesc = get_extra_descr(arg3, ch->in_room->first_extra_descr);
	if (pdesc != NULL)
	{
		if (++count == number)
		{
			chprint(ch, pdesc);
			return;
		}
	}

	if (count > 0 && count != number)
	{
		if (count == 1)
			sprintf(buf, "You only see one %s here.", arg3);
		else
			sprintf(buf, "You only see %d of those here.", count);

		chprintln(ch, buf);
		return;
	}

	if (!str_cmp(arg1, "n") || !str_cmp(arg1, "north"))
		door = 0;
	else if (!str_cmp(arg1, "e") || !str_cmp(arg1, "east"))
		door = 1;
	else if (!str_cmp(arg1, "s") || !str_cmp(arg1, "south"))
		door = 2;
	else if (!str_cmp(arg1, "w") || !str_cmp(arg1, "west"))
		door = 3;
	else if (!str_cmp(arg1, "u") || !str_cmp(arg1, "up"))
		door = 4;
	else if (!str_cmp(arg1, "d") || !str_cmp(arg1, "down"))
		door = 5;
	else
	{
		chprintln(ch, "You do not see that here.");
		return;
	}

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

	if (!IS_NULLSTR(pexit->description))
		chprint(ch, pexit->description);
	else
		chprintln(ch, "Nothing special there.");

	if (!IS_NULLSTR(pexit->keyword) && pexit->keyword[0] != ' ')
	{
		if (IS_SET(pexit->exit_info, EX_CLOSED))
		{
			act("The $d is closed.", ch, NULL, pexit->keyword, TO_CHAR);
		}
		else if (IS_SET(pexit->exit_info, EX_ISDOOR))
		{
			act("The $d is open.", ch, NULL, pexit->keyword, TO_CHAR);
		}
	}

	return;
}

/* RT added back for the hell of it */
CH_CMD(do_read)
{
	do_function(ch, &do_look, argument);
}

CH_CMD(do_examine)
{
	char buf[MAX_STRING_LENGTH];
	char arg[MAX_INPUT_LENGTH];
	OBJ_DATA *obj;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
	{
		chprintln(ch, "Examine what?");
		return;
	}

	do_function(ch, &do_look, arg);

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

		case ITEM_JUKEBOX:
			do_function(ch, &do_play, "list");
			break;

		case ITEM_MONEY:
			if (obj->value[0] == 0)
			{
				if (obj->value[1] == 0)
					sprintf(buf, "Odd...there's no coins in the pile.\n\r");
				else if (obj->value[1] == 1)
					sprintf(buf, "Wow. One gold coin.\n\r");
				else
					sprintf(buf,
							"There are %ld gold coins in the pile.\n\r",
							obj->value[1]);
			}
			else if (obj->value[1] == 0)
			{
				if (obj->value[0] == 1)
					sprintf(buf, "Wow. One silver coin.\n\r");
				else
					sprintf(buf,
							"There are %ld silver coins in the pile.\n\r",
							obj->value[0]);
			}
			else
				chprintlnf(ch,
						   "There are %ld gold and %ld silver coins in the pile.",
						   obj->value[1], obj->value[0]);
			break;

		case ITEM_DRINK_CON:
		case ITEM_CONTAINER:
		case ITEM_CORPSE_NPC:
		case ITEM_CORPSE_PC:
			sprintf(buf, "in %s", argument);
			do_function(ch, &do_look, buf);
		}
	}

	return;
}

/*
 * Thanks to Zrin for auto-exit part.
 */
CH_CMD(do_exits)
{
	char buf[MAX_STRING_LENGTH];
	EXIT_DATA *pexit;
	bool found;
	bool fAuto;
	int door;

	fAuto = !str_cmp(argument, "auto");

	if (!check_blind(ch))
		return;

	if (fAuto)
		sprintf(buf, "[Exits:" MXPTAG("RExits"));
	else if (IS_IMMORTAL(ch))
		sprintf(buf, "Obvious exits from room %ld:\n\r", ch->in_room->vnum);
	else
		sprintf(buf, "Obvious exits:\n\r");

	found = FALSE;
	for (door = 0; door <= 5; door++)
	{
		if ((pexit = ch->in_room->exit[door]) != NULL &&
			pexit->u1.to_room != NULL &&
			can_see_room(ch, pexit->u1.to_room) &&
			!IS_SET(pexit->exit_info, EX_CLOSED))
		{
			found = TRUE;
			if (fAuto)
			{
				strcat(buf, " " MXPTAG("Ex"));
				strcat(buf, dir_name[door]);
				strcat(buf, MXPTAG("/Ex"));
			}
			else
			{
				sprintf(buf + strlen(buf), "%-5s - %s",
						capitalize(dir_name[door]),
						room_is_dark(pexit->u1.to_room) ?
						"Too dark to tell" : pexit->u1.to_room->name);
				if (IS_IMMORTAL(ch))
					sprintf(buf + strlen(buf),
							" (room %ld)\n\r", pexit->u1.to_room->vnum);
				else
					sprintf(buf + strlen(buf), "\n\r");
			}
		}
	}

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

	if (fAuto)
		strcat(buf, MXPTAG("/RExits") "]");

	chprintln(ch, buf);
	return;
}

CH_CMD(do_worth)
{

	if (IS_NPC(ch))
	{
		chprintlnf(ch, "You have %ld gold and %ld silver.", ch->gold,
				   ch->silver);
		return;
	}

	chprintlnf(ch,
			   "You have %ld gold, %ld silver, and %d experience (%d exp to level).",
			   ch->gold, ch->silver, ch->exp,
			   (ch->level + 1) * exp_per_level(ch,
											   ch->pcdata->points) - ch->exp);

	chprintlnf(ch, "You have earned %d questpoints and %d trivia points.",
			   ch->pcdata->questpoints, ch->pcdata->trivia);

	return;
}

CH_CMD(do_score)
{
	int i;

	chprintlnf(ch,
			   "" CTAG(_SCORE1) "You are " CTAG(_SCORE2) "%s%s"
			   CTAG(_SCORE1) ", level " CTAG(_SCORE2) "%d"
			   CTAG(_SCORE1) ", " CTAG(_SCORE2) "%d" CTAG(_SCORE1)
			   " years old (%d hours).{x", ch->name,
			   IS_NPC(ch) ? "" : ch->pcdata->title, ch->level,
			   get_age(ch),
			   (ch->played + (int) (current_time - ch->logon)) / 3600);

	if (get_trust(ch) != ch->level)
	{
		chprintlnf(ch,
				   "" CTAG(_SCORE1) "You are trusted at level "
				   CTAG(_SCORE2) "%d" CTAG(_SCORE1) ".{x", get_trust(ch));
	}

	chprintlnf(ch,
			   "" CTAG(_SCORE1) "Race: " CTAG(_SCORE2) "%s"
			   CTAG(_SCORE1) "  Sex: " CTAG(_SCORE2) "%s"
			   CTAG(_SCORE1) "  Class: " CTAG(_SCORE2) "%s{x",
			   ch->race->name,
			   ch->sex == 0 ? "sexless" : ch->sex == 1 ? "male" : "female",
			   IS_NPC(ch) ? "mobile" : class_long(ch));

	chprintlnf(ch,
			   "" CTAG(_SCORE1) "You have %ld/%ld" CTAG(_SCORE1)
			   " hit, %ld/%ld" CTAG(_SCORE1) " mana, %ld/%ld" CTAG(_SCORE1)
			   " movement.{x", ch->hit, ch->max_hit, ch->mana,
			   ch->max_mana, ch->move, ch->max_move);

	chprintlnf(ch,
			   "" CTAG(_SCORE1) "You have " CTAG(_SCORE2) "%d"
			   CTAG(_SCORE1) " practices and " CTAG(_SCORE2) "%d"
			   CTAG(_SCORE1) " training sessions.{x", ch->practice, ch->train);

	chprintlnf(ch,
			   "" CTAG(_SCORE1) "You are carrying " CTAG(_SCORE2) "%d/%d"
			   CTAG(_SCORE1) " items with weight " CTAG(_SCORE2) "%ld/%d"
			   CTAG(_SCORE1) " pounds.{x", ch->carry_number,
			   can_carry_n(ch), get_carry_weight(ch) / 10,
			   can_carry_w(ch) / 10);

	chprintlnf(ch,
			   "" CTAG(_SCORE1) "Str: " CTAG(_SCORE2) "%d"
			   CTAG(_SCORE3) "(%d)" CTAG(_SCORE1) "  Int: "
			   CTAG(_SCORE2) "%d" CTAG(_SCORE3) "(%d)" CTAG(_SCORE1)
			   "  Wis: " CTAG(_SCORE2) "%d" CTAG(_SCORE3) "(%d)"
			   CTAG(_SCORE1) "  Dex: " CTAG(_SCORE2) "%d"
			   CTAG(_SCORE3) "(%d)" CTAG(_SCORE1) "  Con: "
			   CTAG(_SCORE2) "%d" CTAG(_SCORE3) "(%d){x",
			   ch->perm_stat[STAT_STR], get_curr_stat(ch, STAT_STR),
			   ch->perm_stat[STAT_INT], get_curr_stat(ch, STAT_INT),
			   ch->perm_stat[STAT_WIS], get_curr_stat(ch, STAT_WIS),
			   ch->perm_stat[STAT_DEX], get_curr_stat(ch, STAT_DEX),
			   ch->perm_stat[STAT_CON], get_curr_stat(ch, STAT_CON));

	chprintlnf(ch,
			   "" CTAG(_SCORE1) "You have scored " CTAG(_SCORE2) "%d"
			   CTAG(_SCORE1) " exp, and have " CTAG(_SCORE2) "%ld"
			   CTAG(_SCORE1) " gold and " CTAG(_SCORE2) "%ld"
			   CTAG(_SCORE1) " silver coins.{x", ch->exp, ch->gold, ch->silver);

	if (!IS_NPC(ch))
	{
		chprintlnf(ch,
				   "" CTAG(_SCORE1) "You have " CTAG(_SCORE2) "%ld"
				   CTAG(_SCORE1) " gold and " CTAG(_SCORE2) "%ld"
				   CTAG(_SCORE1) " silver in you bank account.{x",
				   ch->pcdata->gold_bank, ch->pcdata->silver_bank);

		chprintlnf(ch,
				   "" CTAG(_SCORE1) "You have earned " CTAG(_SCORE2) "%d"
				   CTAG(_SCORE1) " questpoints and " CTAG(_SCORE2) "%d"
				   CTAG(_SCORE1) " trivia points.{x", ch->pcdata->questpoints,
				   ch->pcdata->trivia);
	}
	chprintlnf(ch,
			   "" CTAG(_SCORE2) "You worship " CTAG(_SCORE2) "%s, %s"
			   CTAG(_SCORE1) ".{x",
			   ch->deity != NULL ? ch->deity->name : "Mota",
			   ch->deity != NULL ? ch->deity->desc : "the God of Thera");

	{
		int rcnt = roomcount(ch);
		double rooms = top_explored, percent = (double) rcnt / (rooms / 100);

		chprintlnf(ch,
				   "" CTAG(_SCORE1) "Explored : " CTAG(_SCORE2) "%d"
				   CTAG(_SCORE1) " of " CTAG(_SCORE2) "%d" CTAG(_SCORE1)
				   " rooms (" CTAG(_SCORE2) "%5.2f%%" CTAG(_SCORE1)
				   " of the world){x", rcnt, top_explored, percent);
	}

	/* RT shows exp to level */
	if (!IS_NPC(ch) && ch->level < calc_max_level(ch))
	{
		chprintlnf(ch,
				   "" CTAG(_SCORE1) "You need " CTAG(_SCORE2) "%d"
				   CTAG(_SCORE1) " exp to level.{x",
				   ((ch->level + 1) * exp_per_level(ch,
													ch->pcdata->points) -
					ch->exp));
	}

	chprintlnf(ch,
			   "" CTAG(_SCORE1) "Wimpy set to " CTAG(_SCORE2) "%d"
			   CTAG(_SCORE1) " hit points.{x", ch->wimpy);

	if (!IS_NPC(ch) && ch->pcdata->condition[COND_DRUNK] > 10)
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3) "drunk.{x");
	if (!IS_NPC(ch) && ch->pcdata->condition[COND_THIRST] == 0)
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3) "thirsty.{x");
	if (!IS_NPC(ch) && ch->pcdata->condition[COND_HUNGER] == 0)
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3) "hungry.{x");

	switch (ch->position)
	{
	case POS_DEAD:
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3) "DEAD!!{x");
		break;
	case POS_MORTAL:
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3)
				  "mortally wounded.{x");
		break;
	case POS_INCAP:
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3)
				  "incapacitated.{x");
		break;
	case POS_STUNNED:
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3) "stunned.{x");
		break;
	case POS_SLEEPING:
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3) "sleeping.{x");
		break;
	case POS_RESTING:
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3) "resting.{x");
		break;
	case POS_SITTING:
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3) "sitting.{x");
		break;
	case POS_STANDING:
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3) "standing.{x");
		break;
	case POS_FIGHTING:
		chprintln(ch, "" CTAG(_SCORE1) "You are " CTAG(_SCORE3) "fighting.{x");
		break;
	default:
		break;
	}

	if (IS_VALID_STANCE(GET_STANCE(ch, STANCE_AUTODROP)))
		chprintlnf(ch,
				   CTAG(_SCORE1) "You auto-drop into the " CTAG(_SCORE3) "%s"
				   CTAG(_SCORE1) " stance. (" CTAG(_SCORE3) "%d%%" CTAG(_SCORE1)
				   "){x", get_stance_name(GET_STANCE(ch, STANCE_AUTODROP)),
				   GET_STANCE(ch, GET_STANCE(ch, STANCE_AUTODROP)));

	/* print AC values */
	if (ch->level >= 25)
	{
		chprintlnf(ch,
				   "" CTAG(_SCORE1) "Armor: " CTAG(_SCORE2) "pierce: "
				   CTAG(_SCORE3) "%d  " CTAG(_SCORE2) "bash: "
				   CTAG(_SCORE3) "%d  " CTAG(_SCORE2) "slash: "
				   CTAG(_SCORE3) "%d  " CTAG(_SCORE2) "magic: "
				   CTAG(_SCORE3) "%d{x", GET_AC(ch, AC_PIERCE),
				   GET_AC(ch, AC_BASH), GET_AC(ch, AC_SLASH),
				   GET_AC(ch, AC_EXOTIC));
	}

	for (i = 0; i < 4; i++)
	{
		char *temp;

		switch (i)
		{
		case (AC_PIERCE):
			temp = "" CTAG(_SCORE2) "piercing";
			break;
		case (AC_BASH):
			temp = "" CTAG(_SCORE2) "bashing";
			break;
		case (AC_SLASH):
			temp = "" CTAG(_SCORE2) "slashing";
			break;
		case (AC_EXOTIC):
			temp = "" CTAG(_SCORE2) "magic";
			break;
		default:
			temp = "" CTAG(_SCORE2) "error";
			break;
		}

		chprint(ch, "" CTAG(_SCORE1) "You are ");

		if (GET_AC(ch, i) >= 101)
			chprintlnf(ch, "hopelessly vulnerable to %s.{x", temp);
		else if (GET_AC(ch, i) >= 80)
			chprintlnf(ch, "defenseless against %s.{x", temp);
		else if (GET_AC(ch, i) >= 60)
			chprintlnf(ch, "barely protected from %s.{x", temp);
		else if (GET_AC(ch, i) >= 40)
			chprintlnf(ch, "slightly armored against %s.{x", temp);
		else if (GET_AC(ch, i) >= 20)
			chprintlnf(ch, "somewhat armored against %s.{x", temp);
		else if (GET_AC(ch, i) >= 0)
			chprintlnf(ch, "armored against %s.{x", temp);
		else if (GET_AC(ch, i) >= -20)
			chprintlnf(ch, "well-armored against %s.{x", temp);
		else if (GET_AC(ch, i) >= -40)
			chprintlnf(ch, "very well-armored against %s.{x", temp);
		else if (GET_AC(ch, i) >= -60)
			chprintlnf(ch, "heavily armored against %s.{x", temp);
		else if (GET_AC(ch, i) >= -80)
			chprintlnf(ch, "superbly armored against %s.{x", temp);
		else if (GET_AC(ch, i) >= -100)
			chprintlnf(ch, "almost invulnerable to %s.{x", temp);
		else
			chprintlnf(ch, "divinely armored against %s.{x", temp);
	}

	/* RT wizinvis and holy light */
	if (IS_IMMORTAL(ch))
	{
		chprint(ch, "" CTAG(_SCORE1) "Holy Light: ");
		if (IS_SET(ch->act, PLR_HOLYLIGHT))
			chprint(ch, "" CTAG(_SCORE2) "on");
		else
			chprint(ch, "" CTAG(_SCORE2) "off");

		if (ch->invis_level)
		{
			chprintf(ch,
					 "" CTAG(_SCORE1) "  Invisible: " CTAG(_SCORE2)
					 "level " CTAG(_SCORE3) "%d", ch->invis_level);
		}

		if (ch->incog_level)
		{
			chprintf(ch,
					 "" CTAG(_SCORE1) "  Incognito: " CTAG(_SCORE2)
					 "level " CTAG(_SCORE3) "%d", ch->incog_level);
		}
		chprintln(ch, "{x");
	}

	if (ch->level >= 15)
	{
		chprintlnf(ch,
				   "" CTAG(_SCORE1) "Hitroll: " CTAG(_SCORE2) "%d"
				   CTAG(_SCORE1) "  Damroll: " CTAG(_SCORE2) "%d.{x",
				   GET_HITROLL(ch), GET_DAMROLL(ch));
	}

	if (ch->level >= 10)
	{
		chprintf(ch,
				 "" CTAG(_SCORE1) "Alignment: " CTAG(_SCORE2) "%d.  ",
				 ch->alignment);
	}

	chprint(ch, "" CTAG(_SCORE1) "You are ");
	if (ch->alignment > 900)
		chprintln(ch, "" CTAG(_SCORE2) "angelic.{x");
	else if (ch->alignment > 700)
		chprintln(ch, "" CTAG(_SCORE2) "saintly.{x");
	else if (ch->alignment > 350)
		chprintln(ch, "" CTAG(_SCORE2) "good.{x");
	else if (ch->alignment > 100)
		chprintln(ch, "" CTAG(_SCORE2) "kind.{x");
	else if (ch->alignment > -100)
		chprintln(ch, "" CTAG(_SCORE2) "neutral.{x");
	else if (ch->alignment > -350)
		chprintln(ch, "" CTAG(_SCORE2) "mean.{x");
	else if (ch->alignment > -700)
		chprintln(ch, "" CTAG(_SCORE2) "evil.{x");
	else if (ch->alignment > -900)
		chprintln(ch, "" CTAG(_SCORE2) "demonic.{x");
	else
		chprintln(ch, "" CTAG(_SCORE2) "satanic.{x");

	if (IS_SET(ch->comm, COMM_SHOW_AFFECTS))
		do_function(ch, &do_affects, "");
}

CH_CMD(do_affects)
{
	AFFECT_DATA *paf, *paf_last = NULL;
	const char *buf4;
	char buf3[MSL];
	char buf2[MSL];
	bool found = FALSE;
	flag_t filter;
	flag_t printme;
	BUFFER *buffer;
	OBJ_DATA *obj;
	int iWear;

	buffer = new_buf();

	if (ch->first_affect != NULL)
	{
		bprintln(buffer, "You are affected by the following spells:{x");

		for (paf = ch->first_affect; paf != NULL; paf = paf->next)
		{
			if (paf_last != NULL && paf->type == paf_last->type)
			{
				if (get_trust(ch) >= 20)
					bprint(buffer, "                          ");
				else
					continue;
			}
			else
				bprintf(buffer, "{xSpell: {c%-19s{x",
						(paf->type != -1
						 && !IS_NULLSTR(skill_table[paf->type].name))
						? skill_table[paf->type].name : "unknown");

			if (get_trust(ch) >= 20)
			{
				bprintf(buffer, ": {xmodifies %s by %d{x ",
						flag_string(apply_flags, paf->location), paf->modifier);
				if (paf->duration == -1)
					bprint(buffer, "{xpermanently{x");
				else
					bprintf(buffer, "{xfor %d hours{x", paf->duration);
			}

			bprintln(buffer, "");
			paf_last = paf;
		}
		found = TRUE;
		bprintln(buffer, "");
	}
	if (ch->race->aff != 0 && IS_AFFECTED(ch, ch->race->aff))
	{
		bprintln(buffer,
				 "You are affected by the following racial abilities:{x");

		strcpy(buf3, flag_string(affect_flags, ch->race->aff));
		buf4 = buf3;
		buf4 = one_argument(buf4, buf2);
		while (buf2[0])
		{
			bprintlnf(buffer, "{xSpell: {c%-19s{x", buf2);
			buf4 = one_argument(buf4, buf2);
		}
		found = TRUE;
		bprintln(buffer, "");
	}
	if (ch->affected_by != 0 && (ch->affected_by != ch->race->aff))
	{
		bool print = FALSE;

		for (iWear = 0; iWear < MAX_WEAR; iWear++)
		{
			if ((obj = get_eq_char(ch, (wloc_t) iWear)) != NULL)
			{
				for (paf = obj->first_affect; paf != NULL; paf = paf->next)
				{
					if (!IS_SET(ch->affected_by, paf->bitvector))
						continue;

					if (paf->where != TO_AFFECTS)
						continue;

					filter = paf->bitvector;
					filter &= ch->affected_by;
					printme = filter;
					if (!print)
					{
						bprintln(buffer,
								 "You are affected by the following equipment spells:{x");
						print = TRUE;
					}

					strcpy(buf3, flag_string(affect_flags, printme));
					buf4 = buf3;
					buf4 = one_argument(buf4, buf2);
					while (buf2[0])
					{
						bprintlnf(buffer, "{xSpell: {c%-19s:{x %s", buf2,
								  obj->short_descr);
						buf4 = one_argument(buf4, buf2);
					}
				}
				if (!obj->enchanted)
				{
					for (paf = obj->pIndexData->first_affect; paf != NULL;
						 paf = paf->next)
					{
						if (!IS_SET(ch->affected_by, paf->bitvector))
							continue;
						if (paf->where != TO_AFFECTS)
							continue;
						filter = paf->bitvector;
						filter &= ch->affected_by;
						printme = filter;
						if (!print)
						{
							bprintln(buffer,
									 "You are affected by the following equipment spells:{x");
							print = TRUE;
						}

						strcpy(buf3, flag_string(affect_flags, printme));

						buf4 = buf3;
						buf4 = one_argument(buf4, buf2);
						while (buf2[0])
						{
							bprintlnf(buffer, "{xSpell: {c%-19s:{x %s", buf2,
									  obj->short_descr);
							buf4 = one_argument(buf4, buf2);
						}
					}
				}
			}
		}
		found = TRUE;
		if (print)
			bprintln(buffer, "");
	}
	if (!found)
	{
		bprintln(buffer, "You are not affected by any spells.{x");
	}

	sendpage(ch, buf_string(buffer));
	free_buf(buffer);
	return;
}

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

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

CH_CMD(do_time)
{
	char *suf;
	int day;

	if (!IS_NULLSTR(argument))
	{
		CHAR_DATA *victim;

		if ((victim = get_char_world(ch, argument)) == NULL || IS_NPC(victim))
		{
			chprintln(ch, "There is no such player.");
			return;
		}
		if (GET_TZONE(victim) == -1)
		{
			act("$N doesn't have a time zone set.", ch, NULL, victim, TO_CHAR);
			return;
		}
		act("{W$N's local time is $t.{x", ch,
			str_time(current_time, GET_TZONE(victim), NULL), victim, TO_CHAR);
		return;
	}
	day = time_info.day + 1;

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

	chprintlnf(ch,
			   "It is %d o'clock %s, Day of %s, %d%s the Month of %s.",
			   (time_info.hour % 12 == 0) ? 12 : time_info.hour % 12,
			   time_info.hour >= 12 ? "pm" : "am", day_name[day % 7], day,
			   suf, month_name[time_info.month]);
	chprintlnf(ch,
			   MUD_NAME
			   " started up at %s\n\rWhich was %s ago.\n\rThe system time is %s.",
			   str_time(boot_time, -1, NULL), timestr(current_time - boot_time,
													  FALSE), str_time(-1, -1,
																	   NULL));

	if (!IS_NPC(ch))
	{
		if (GET_TZONE(ch) != -1)
			chprintlnf(ch, "Your local time is %s",
					   str_time(-1, GET_TZONE(ch), NULL));
		else
			chprintln
				(ch,
				 "Your local time is not set! Use the 'timezone' command to set your time zone.");

		// online time
		chprintlnf(ch, "You connected at %s\n\rWhich was %s ago.",
				   str_time(ch->logon, GET_TZONE(ch), NULL),
				   timestr(current_time - ch->logon, FALSE));
		// creation time
		chprintlnf(ch, "You first created at %s\n\r"
				   "Which was %s ago.",
				   str_time(ch->id, GET_TZONE(ch), NULL),
				   timestr(current_time - ch->id, FALSE));

		chprintlnf(ch, "You have played approximately %d.%02d hours.",
				   (ch->played + (int) (current_time - ch->logon)) / HOUR,
				   ((ch->played + (int) (current_time - ch->logon)) / 36) %
				   100);

		chprintlnf
			(ch, "Which is %0.03f%% of the time since you created.",
			 ((double) (ch->played + (int) (current_time - ch->logon)) /
			  (double) (current_time - ch->id)) * 100.0);
	}
	if (crs_info.timer > -1 && crs_info.status != CRS_NONE)
	{
		chprintln(ch, crs_sprintf(TRUE, FALSE));
	}

	return;
}

CH_CMD(do_timezone)
{
	int i;

	if (IS_NPC(ch))
		return;

	if (IS_NULLSTR(argument))
	{
		chprintlnf(ch, "%-6s %-29s (%s)", "Name", "City/Zone Crosses", "Time");
		chprintln(ch, draw_line(ch, NULL, 0));
		for (i = 0; i < MAX_TZONE; i++)
		{
			chprintlnf(ch, "%-6s %-29s (%s)", tzone_table[i].name,
					   tzone_table[i].zone, str_time(current_time, i, NULL));
		}
		chprintln(ch, draw_line(ch, NULL, 0));
		return;
	}

	i = tzone_lookup(argument);

	if (i == -1)
	{
		chprintln
			(ch,
			 "That time zone does not exists. Make sure to use the exact name.");
		return;
	}

	ch->pcdata->timezone = i;
	chprintlnf(ch, "Your time zone is now %s %s (%s)", tzone_table[i].name,
			   tzone_table[i].zone, str_time(current_time, i, NULL));
}

CH_CMD(do_weather)
{
	char *combo = "", *single = "";
	int temp, precip, wind;

	if (!IS_OUTSIDE(ch))
	{
		chprintln(ch, "You can't see the sky from here.");
		return;
	}

	temp = (ch->in_room->area->weather.temp + 3 * mud_info.weath_unit - 1) /
		mud_info.weath_unit;
	precip = (ch->in_room->area->weather.precip + 3 * mud_info.weath_unit - 1) /
		mud_info.weath_unit;
	wind = (ch->in_room->area->weather.wind + 3 * mud_info.weath_unit - 1) /
		mud_info.weath_unit;

	if (precip >= 3)
	{
		combo = preciptemp_msg[precip][temp];
		single = wind_msg[wind];
	}
	else
	{
		combo = windtemp_msg[wind][temp];
		single = precip_msg[precip];
	}

	chprintlnf(ch, "{B%s and %s.{x", combo, single);
	return;
}

/* 
    Syntax(s):
                help <letter>       - list help files that start with <letter>
                help 2.<keyword>    - find second occurance of <keyword>
                help <keyword>      - find first occurance of <keyword>, put the rest
                                      into 'related helps'.
*/
CH_CMD(do_help)
{
	HELP_DATA *pHelp;
	bool found = FALSE;
	bool list = FALSE;
	char argall[MIL], argone[MIL], argall2[MIL];
	char nohelp[MIL];
	BUFFER *buffer;
	BUFFER *related;
	int counter = 0, number, count = 0;

	if (IS_NULLSTR(argument))
		argument = "summary";

	argall[0] = '\0';
	while (!IS_NULLSTR(argument))
	{
		argument = one_argument(argument, argone);
		if (!IS_NULLSTR(argall))
			strcat(argall, " ");
		strcat(argall, argone);
	}

	buffer = new_buf();
	related = new_buf();
	/* allows for help 2.keyword */
	number = number_argument(argall, argall2);
	strcpy(nohelp, argall2);

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

		if (!is_name(argall2, pHelp->keyword))
			continue;

		if (list || (strlen(argall2) == 1))
		{
			counter++;

			bprintlnf(buffer, "%3d) "
					  MXPTAG("Help '%s'") "%s" MXPTAG("/Help"), counter,
					  pHelp->keyword, pHelp->keyword);
			list = TRUE;
			found = TRUE;
			continue;
		}
		if (found)
		{
			bprintf(buffer, "%s, ", pHelp->keyword);
			continue;
		}
		if (++count == number)
		{
			bprintln(buffer, draw_line(ch, "{m-{M-", 0));
			bprintlnf(buffer, "Help Keywords : %s", pHelp->keyword);
			bprintln(buffer, draw_line(ch, "{m-{M-", 0));
			if (pHelp->text[0] == '.')
				bprint(buffer, pHelp->text + 1);
			else
				bprint(buffer, pHelp->text);
			bprintln(buffer, draw_line(ch, "{m-{M-", 0));
			found = TRUE;
		}
		else
		{
			bprintf(related, MXPTAG("Help '%s'") "%s" MXPTAG("/Help") ", ",
					pHelp->keyword, pHelp->keyword);
		}
	}
	if (list)
	{
		const char *text = str_dup(buf_string(buffer));
		clear_buf(buffer);
		bprintlnf(buffer, "Help files that start with the letter '%s'.",
				  argall2);
		bprintln(buffer, draw_line(ch, "{m-{M-", 0));
		bprint(buffer, text);
		bprintln(buffer, draw_line(ch, "{m-{M-", 0));
		bprintlnf(buffer, "%d total help files.", counter);
		free_string(text);
	}

	else if (!found)
	{
		bprintlnf(buffer,
				  "No help found for %s. Try using just the first letter.\n\r",
				  nohelp);
		sprintf(log_buf, "Missing Help: %s", nohelp);
		wiznet(log_buf, ch, NULL, 0, 0, 0);
	}
	else if (!IS_NULLSTR(related->string))
	{
		related->string[strlen(related->string) - 2] = '.';
		related->string[strlen(related->string) - 1] = '\0';
		bprintlnf(buffer, "See Also : %s\n\r%s", buf_string(related),
				  draw_line(ch, "{m-{M-", 0));
	}
	sendpage(ch, buf_string(buffer));
	free_buf(buffer);
	free_buf(related);
}

CH_CMD(do_oldhelp)
{
	HELP_DATA *pHelp;
	BUFFER *output;
	bool found = FALSE;
	char argall[MAX_INPUT_LENGTH], argone[MAX_INPUT_LENGTH];
	int level;

	output = new_buf();

	if (IS_NULLSTR(argument))
		argument = "summary";

	/* this parts handles help a b so that it returns help 'a b' */
	argall[0] = '\0';
	while (!IS_NULLSTR(argument))
	{
		argument = one_argument(argument, argone);
		if (!IS_NULLSTR(argall))
			strcat(argall, " ");
		strcat(argall, argone);
	}

	for (pHelp = help_first; pHelp != NULL; pHelp = pHelp->next)
	{
		level = (pHelp->level < 0) ? -1 * pHelp->level - 1 : pHelp->level;

		if (level > get_trust(ch))
			continue;

		if (is_name(argall, pHelp->keyword))
		{
			/* add seperator if found */
			if (found)
				bprintln(output,
						 "\n\r============================================================\n\r");
			if (pHelp->level >= 0 && str_cmp(argall, "imotd"))
			{
				bprintln(output, pHelp->keyword);
			}

			/*
			 * Strip leading '.' to allow initial blanks.
			 */
			if (pHelp->text[0] == '.')
				bprint(output, pHelp->text + 1);
			else
				bprint(output, pHelp->text);
			found = TRUE;
			/* small hack :) */
			if (ch->desc != NULL && ch->desc->connected != CON_PLAYING
				&& ch->desc->connected != CON_GEN_GROUPS)
				break;
		}
	}

	if (!found)
		chprintln(ch, "No help on that word.");
	else
		sendpage(ch, buf_string(output));
	free_buf(output);
}

char *format_clan(CHAR_DATA * ch)
{
	static char buf[MSL];

	if (!is_clan(ch))
		return "";

	sprintf(buf, " %s", ch->clan->who_name);
	return buf;
}

char *format_who(CHAR_DATA * ch, CHAR_DATA * wch)
{
	char block[MIL];
	static char buf[MSL];

	if (!wch)
		return "ERROR";

	/*
	 * Format it up.
	 */
	if (!IS_NULLSTR(wch->pcdata->who_descr))
		sprintf(block, "[%s] ",
				stringf(ch, 12, ALIGN_CENTER, NULL, wch->pcdata->who_descr));
	else
		sprintf(block,
				"[" CTAG(_WLEVEL) "%3.3s " CTAG(_WRACE) "%4.4s " CTAG(_WCLASS)
				"%3.3s{x] ", high_level_name(wch->level, FALSE),
				wch->race->name, class_who(wch));

	sprintf(buf, "%s%s%s%s%s%s%s%s%s"
			MXPTAG("Fwho '%s'") "%s" MXPTAG("/Fwho") "%s%s\n\r", block,
			wch->incog_level >= LEVEL_HERO ? "(Incog) " : "",
			wch->invis_level >= LEVEL_HERO ? "(Wizi) " : "",
			IS_SET(wch->comm, COMM_AFK) ? "[AFK] " : "",
			IS_QUESTOR(wch) ? "[Q] " : "",
			ON_GQUEST(wch) ? "(GQuest) " : "", wch->war ? "(WAR) " :
			"", IS_SET(wch->act, PLR_KILLER) ? "(KILLER) " : "",
			IS_SET(wch->act, PLR_THIEF) ? "(THIEF) " : "", wch->name, wch->name,
			IS_NPC(wch) ? "" : wch->pcdata->title, format_clan(wch));
	return (buf);
}

/* whois command */
CH_CMD(do_whois)
{
	char arg[MAX_INPUT_LENGTH];
	BUFFER *output;
	DESCRIPTOR_DATA *d;
	bool found = FALSE;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
	{
		chprintln(ch, "You must provide a name.");
		return;
	}

	output = new_buf();

	for (d = descriptor_first; d != NULL; d = d->next)
	{
		CHAR_DATA *wch;

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

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

		if (!can_see(ch, wch))
			continue;

		if (!str_prefix(arg, wch->name))
		{
			found = TRUE;

			bprint(output, format_who(ch, wch));
		}
	}

	if (!found)
	{
		chprintln(ch, "No one of that name is playing.");
		return;
	}

	sendpage(ch, buf_string(output));
	free_buf(output);
}

CH_CMD(do_whowas)
{
	char arg[MIL];
	CHAR_DATA *victim;
	bool fOld;
	READ_DATA *fp;

	one_argument(argument, arg);
	if (IS_NULLSTR(arg))
	{
		chprintln(ch, "Whowas who?");
		return;
	}

	if ((victim = get_char_world(ch, arg)) != NULL && can_see(ch, victim))
	{
		if (!IS_NPC(victim))
		{
			act("$N is on right now! Use Whois.", ch, NULL, victim, TO_CHAR);
			return;
		}
	}

	victim = new_char();
	victim->pcdata = new_pcdata();
	pload_default(victim);
	fOld = FALSE;
	if ((fp = open_read("%s%s", PLAYER_DIR, capitalize(arg))) != NULL)
	{
		fOld = TRUE;

		for (;;)
		{
			char letter;
			char *word;

			letter = read_letter(fp);
			if (letter == '*')
			{
				read_to_eol(fp);
				continue;
			}

			if (letter != '#')
			{
				bug("do_whowas: # not found.");
				break;
			}

			word = read_word(fp);
			if (!str_cmp(word, "PLAYER"))
				read_char(victim, fp);
			else if (!str_cmp(word, "PET"))
				break;
			else if (!str_cmp(word, "O"))
				break;
			else if (!str_cmp(word, "END"))
				break;
			else
				break;
		}
		close_read(fp);
	}

	if (!fOld)
	{
		chprintln(ch, "No player by that name exists.");
		free_char(victim);
		return;
	}

	if (IS_NPC(victim) || victim->pcdata == NULL)
	{
		chprintln(ch, "Error loading pcdata.  Stop.");
		free_char(victim);
		return;
	}

	chprint(ch, format_who(ch, victim));
	free_char(victim);
	return;
}

struct s_charitem
{
	CHAR_DATA *pch;
	long levelkey;
};

/*
 * New 'who' command originally by Alander of Rivers of Mud.
 */
CH_CMD(do_who)
{
	char buf[MAX_STRING_LENGTH];
	BUFFER *output;
	DESCRIPTOR_DATA *d;
	int iClass;
	RACE_DATA *iRace = NULL;
	CLAN_DATA *iClan = NULL;
	int iLevelLower;
	int iLevelUpper;
	int nNumber;
	int nMatch, count = 0, immcount = 0;
	int ndesc, totalcount = 0, imminvis = 0;
	bool *rgfClass;
	bool fClassRestrict = FALSE;
	bool fClanRestrict = FALSE;
	bool fClan = FALSE;
	bool fRaceRestrict = FALSE;
	bool fImmortalOnly = FALSE;
	struct s_charitem *charitems, tmp_charitem;
	bool searched = FALSE;
	int j1, j2;
	CHAR_DATA *wch;

	/*
	 * Set default arguments.
	 */
	iLevelLower = 0;
	iLevelUpper = MAX_LEVEL;
	alloc_mem(rgfClass, bool, maxClass);
	for (iClass = 0; iClass < maxClass; iClass++)
		rgfClass[iClass] = FALSE;

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

		argument = one_argument(argument, arg);
		if (IS_NULLSTR(arg))
			break;
		else
			searched = TRUE;

		if (is_number(arg))
		{
			switch (++nNumber)
			{
			case 1:
				iLevelLower = atoi(arg);
				break;
			case 2:
				iLevelUpper = atoi(arg);
				break;
			default:
				chprintln(ch, "Only two level numbers allowed.");
				free_mem(rgfClass);
				return;
			}
		}
		else
		{

			/*
			 * Look for classes to turn on.
			 */
			if (!str_prefix(arg, "immortals"))
			{
				fImmortalOnly = TRUE;
			}
			else
			{
				iClass = class_lookup(arg);
				if (iClass == -1 || iClass >= maxClass)
				{
					iRace = race_lookup(arg);

					if (iRace == NULL || !iRace->pc_race)
					{
						if (!str_prefix(arg, "clan"))
							fClan = TRUE;
						else
						{
							iClan = clan_lookup(arg);
							if (iClan != NULL)
							{
								fClanRestrict = TRUE;
							}
							else
							{
								chprintln
									(ch,
									 "That's not a valid race, class, or clan.");
								free_mem(rgfClass);
								return;
							}
						}
					}
					else
					{
						fRaceRestrict = TRUE;
					}
				}
				else
				{
					fClassRestrict = TRUE;
					rgfClass[iClass] = TRUE;
				}
			}
		}
	}

	ndesc = 0;
	for (d = descriptor_first; d != NULL; d = d->next)
		ndesc++;

	alloc_mem(charitems, struct s_charitem, ndesc);

	if (ndesc > mud_info.max_online)
		mud_info.max_online = ndesc;

	/*
	 * Now show matching chars.
	 */
	nMatch = 0;
	buf[0] = '\0';
	output = new_buf();
	bprintln(output, draw_line(ch, "{r-{R-", 0));
	for (d = descriptor_first; d != NULL; d = d->next)
	{
		/*
		 * Check for match against restrictions.
		 * Don't use trust as that exposes trusted mortals.
		 */
		if (d->connected != CON_PLAYING)
			continue;

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

		if (get_trust(wch) >= LEVEL_IMMORTAL && wch->level >= LEVEL_IMMORTAL)
			immcount++;
		else
			count++;

		if (!can_see(ch, wch))
		{
			if (IS_IMMORTAL(wch))
				imminvis++;
			continue;
		}

		if (wch->level < iLevelLower || wch->level > iLevelUpper ||
			(fImmortalOnly && wch->level < LEVEL_IMMORTAL) ||
			(fClassRestrict && !rgfClass[wch->Class[0]]) || (fRaceRestrict
															 &&
															 iRace != wch->race)
			|| (fClan && !is_clan(wch)) || (fClanRestrict
											&& wch->clan != iClan))
			continue;

		charitems[nMatch].pch = wch;
		charitems[nMatch].levelkey = wch->level + 1;
		nMatch++;
	}

	totalcount = (count + immcount);

	for (j1 = 0; j1 < nMatch - 1; j1++)
	{
		for (j2 = j1 + 1; j2 < nMatch; j2++)
		{
			if (charitems[j2].levelkey > charitems[j1].levelkey)
			{
				tmp_charitem = charitems[j1];
				charitems[j1] = charitems[j2];
				charitems[j2] = tmp_charitem;
			}
		}
	}

	for (j1 = 0; j1 < nMatch; j1++)
	{
		wch = charitems[j1].pch;
		bprint(output, format_who(ch, wch));
		if (j1 == (immcount - imminvis - 1) && j1 != (nMatch - 1)
			&& IS_IMMORTAL(wch))
		{
			bprintln(output, draw_line(ch, "{r-{R-", 0));
		}
	}

	free_mem(charitems);

	bprintln(output, draw_line(ch, "{r-{R-", 0));

	if (searched)
	{
		bprintlnf(output, "{WMatches found: {R%d{x", nMatch);
	}
	else if (nMatch < (totalcount - imminvis))
	{
		bprintlnf(output,
				  "{WPlayers found: {R%d{W  Most on ever: {R%d{W  Invisible: {R%d{x",
				  nMatch, mud_info.max_online,
				  (totalcount - nMatch - imminvis));
	}
	else
	{
		bprintlnf(output, "{WPlayers found: {R%d{W  Most on ever: {R%d{x",
				  totalcount - imminvis, mud_info.max_online);
	}

	if (!ON_GQUEST(ch) && gquest_info.minlevel < ch->level &&
		gquest_info.maxlevel > ch->level)
		bprintln(output, "{WThere is a Global Quest running you can join.{x");
	if (crs_info.timer > -1 && crs_info.status != CRS_NONE)
	{
		bprintlnf(output, "{W%s{x", crs_sprintf(TRUE, FALSE));
	}

	sendpage(ch, buf_string(output));
	free_buf(output);
	free_mem(rgfClass);
	return;
}

CH_CMD(do_count)
{
	int count;
	DESCRIPTOR_DATA *d;

	count = 0;

	for (d = descriptor_first; d != NULL; d = d->next)
		if (d->connected == CON_PLAYING && can_see(ch, d->character))
			count++;

	mud_info.max_online = UMAX(count, mud_info.max_online);

	if (mud_info.max_online == count)
		chprintlnf(ch, "There are %d characters on, the most ever.", count);
	else
		chprintlnf(ch,
				   "There are %d characters on, the most on ever was %d.",
				   count, mud_info.max_online);
}

CH_CMD(do_inventory)
{
	chprintlnf(ch,
			   "{YYou are carrying {W%d/%d{Y items with {W%ld/%d{Y weight:{x",
			   ch->carry_number, can_carry_n(ch), get_carry_weight(ch) / 10,
			   can_carry_w(ch) / 10);
	show_list_to_char(ch->first_carrying, ch, TRUE, TRUE);
	return;
}

CH_CMD(do_equipment)
{
	OBJ_DATA *obj;
	int iWear;

	chprintln(ch, "You are using:");
	for (iWear = 0; iWear < MAX_WEAR; iWear++)
	{
		chprint(ch, where_name[iWear]);
		if ((obj = get_eq_char(ch, (wloc_t) iWear)) == NULL)
		{
			chprintln(ch, "nothing.");
		}
		else if (can_see_obj(ch, obj))
		{
			chprintln(ch, format_obj_to_char(obj, ch, TRUE));
		}
		else
		{
			chprintln(ch, "something.");
		}
	}
	return;
}

CH_CMD(do_compare)
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	OBJ_DATA *obj1;
	OBJ_DATA *obj2;
	long value1;
	long value2;
	char *msg;

	argument = one_argument(argument, arg1);
	argument = one_argument(argument, arg2);
	if (IS_NULLSTR(arg1))
	{
		chprintln(ch, "Compare what to what?");
		return;
	}

	if ((obj1 = get_obj_carry(ch, arg1, ch)) == NULL)
	{
		chprintln(ch, "You do not have that item.");
		return;
	}

	if (IS_NULLSTR(arg2))
	{
		for (obj2 = ch->first_carrying; obj2 != NULL; obj2 = obj2->next_content)
		{
			if (obj2->wear_loc != WEAR_NONE && can_see_obj(ch, obj2)
				&& obj1->item_type == obj2->item_type
				&& (obj1->wear_flags & obj2->wear_flags & ~ITEM_TAKE) != 0)
				break;
		}

		if (obj2 == NULL)
		{
			chprintln(ch, "You aren't wearing anything comparable.");
			return;
		}
	}

	else if ((obj2 = get_obj_carry(ch, arg2, ch)) == NULL)
	{
		chprintln(ch, "You do not have that item.");
		return;
	}

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

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

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

		case ITEM_WEAPON:
			if (obj1->pIndexData->new_format)
				value1 = (1 + obj1->value[2]) * obj1->value[1];
			else
				value1 = obj1->value[1] + obj1->value[2];

			if (obj2->pIndexData->new_format)
				value2 = (1 + obj2->value[2]) * obj2->value[1];
			else
				value2 = obj2->value[1] + obj2->value[2];
			break;
		}
	}

	if (msg == NULL)
	{
		if (value1 == value2)
			msg = "$p and $P look about the same.";
		else if (value1 > value2)
			msg = "$p looks better than $P.";
		else
			msg = "$p looks worse than $P.";
	}

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

CH_CMD(do_credits)
{
	do_function(ch, &do_oldhelp, "diku");
	do_function(ch, &do_oldhelp, "ROM");
	do_function(ch, &do_oldhelp, "1stMUD");
	return;
}

CH_CMD(do_where)
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	DESCRIPTOR_DATA *d;
	bool found;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
	{
		chprintlnf(ch, "You are in zone  : %s", ch->in_room->area->name);
		if (!IS_NULLSTR(ch->in_room->area->lvl_comment))
			chprintlnf(ch, "Recomended Levels: [%-7s]",
					   ch->in_room->area->lvl_comment);
		else
			chprintlnf(ch, "Recomended Levels: [%03d %03d]",
					   ch->in_room->area->min_level,
					   ch->in_room->area->max_level);

		chprintlnf(ch, "Author           : [%-7s]", ch->in_room->area->credits);
		if (IS_IMMORTAL(ch))
		{
			chprintlnf(ch, "Vnum Range       : %ld to %ld",
					   ch->in_room->area->min_vnum,
					   ch->in_room->area->max_vnum);
		}
		chprintln(ch, "Players near you:");
		found = FALSE;
		for (d = descriptor_first; d; d = d->next)
		{
			if (d->connected == CON_PLAYING &&
				(victim = d->character) != NULL && !IS_NPC(victim) &&
				victim->in_room != NULL &&
				!IS_SET(victim->in_room->room_flags, ROOM_NOWHERE) &&
				(is_room_owner(ch, victim->in_room) ||
				 !room_is_private(victim->in_room)) &&
				victim->in_room->area == ch->in_room->area &&
				can_see(ch, victim))
			{
				found = TRUE;
				chprintlnf(ch, "%-28s %s", victim->name, victim->in_room->name);
			}
		}
		if (!found)
			chprintln(ch, "None");
	}
	else
	{
		found = FALSE;
		for (victim = char_first; victim != NULL; victim = victim->next)
		{
			if (victim->in_room != NULL &&
				victim->in_room->area == ch->in_room->area &&
				!IS_AFFECTED(victim, AFF_HIDE) &&
				!IS_AFFECTED(victim, AFF_SNEAK)
				&& can_see(ch, victim) && is_name(arg, victim->name))
			{
				found = TRUE;
				chprintlnf(ch, "%-28s %s", PERS(victim, ch),
						   victim->in_room->name);
				break;
			}
		}
		if (!found)
			act("You didn't find any $T.", ch, NULL, arg, TO_CHAR);
	}

	return;
}

CH_CMD(do_consider)
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	char *msg;
	int diff;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
	{
		chprintln(ch, "Consider killing whom?");
		return;
	}

	if ((victim = get_char_room(ch, NULL, arg)) == NULL)
	{
		chprintln(ch, "They're not here.");
		return;
	}

	if (is_safe(ch, victim))
	{
		chprintln(ch, "Don't even think about it.");
		return;
	}

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

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

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

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

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

	if (title[0] != '.' && title[0] != ',' && title[0] != '!' &&
		title[0] != '?')
	{
		buf[0] = ' ';
		strcpy(buf + 1, title);
	}
	else
	{
		strcpy(buf, title);
	}

	replace_string(ch->pcdata->title, buf);
	return;
}

CH_CMD(do_title)
{
	char buf[MAX_STRING_LENGTH];

	if (IS_NPC(ch))
		return;

	if (IS_NULLSTR(argument))
	{
		chprintln(ch, "Change your title to what?");
		return;
	}

	strcpy(buf, argument);

	if (strlen(buf) > 45)
		buf[45] = '\0';

	smash_tilde(buf);
	set_title(ch, buf);
	chprintln(ch, "Ok.");
}

CH_CMD(do_description)
{
	char buf[MAX_STRING_LENGTH];

	if (!IS_NULLSTR(argument))
	{
		buf[0] = '\0';
		smash_tilde(argument);

		if (argument[0] == '-')
		{
			int len;
			bool found = FALSE;

			if (IS_NULLSTR(ch->description))
			{
				chprintln(ch, "No lines left to remove.");
				return;
			}

			strcpy(buf, ch->description);

			for (len = strlen(buf); len > 0; len--)
			{
				if (buf[len] == '\r')
				{
					if (!found)	/* back it up */
					{
						if (len > 0)
							len--;
						found = TRUE;
					}
					else		/* found the second one */
					{
						buf[len + 1] = '\0';
						replace_string(ch->description, buf);
						chprintln(ch, "Your description is:");
						chprint(ch, ch->description ?
								ch->description : "(None).\n\r");
						return;
					}
				}
			}
			buf[0] = '\0';
			replace_string(ch->description, buf);
			chprintln(ch, "Description cleared.");
			return;
		}
		if (argument[0] == '+')
		{
			if (ch->description != NULL)
				strcat(buf, ch->description);
			argument++;
			while (isspace(*argument))
				argument++;
		}

		if (strlen(buf) >= 1024)
		{
			chprintln(ch, "Description too long.");
			return;
		}

		strcat(buf, argument);
		strcat(buf, "\n\r");
		replace_string(ch->description, buf);
	}

	chprintln(ch, "Your description is:");
	chprint(ch, ch->description ? ch->description : "(None).\n\r");
	return;
}

CH_CMD(do_report)
{
	char buf[MAX_INPUT_LENGTH];

	chprintlnf(ch,
			   "You say 'I have %ld/%ld hp %ld/%ld mana %ld/%ld mv %d xp.'",
			   ch->hit, ch->max_hit, ch->mana, ch->max_mana, ch->move,
			   ch->max_move, ch->exp);

	sprintf(buf,
			"$n says 'I have %ld/%ld hp %ld/%ld mana %ld/%ld mv %d xp.'",
			ch->hit, ch->max_hit, ch->mana, ch->max_mana, ch->move,
			ch->max_move, ch->exp);

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

	return;
}

CH_CMD(do_practice)
{
	int sn;

	if (IS_NPC(ch))
		return;

	if (IS_NULLSTR(argument))
	{
		int col;

		col = 0;
		for (sn = 0; sn < maxSkill; sn++)
		{
			if (skill_table[sn].name == NULL)
				break;
			if (!can_use_skpell(ch, sn) || ch->pcdata->learned[sn] < 1	/* skill is not known */
				)
				continue;

			chprintf(ch, "%-18s %3d%%  ", skill_table[sn].name,
					 ch->pcdata->learned[sn]);
			if (++col % 3 == 0)
				chprintln(ch, "");
		}

		if (col % 3 != 0)
			chprintln(ch, "");

		chprintlnf(ch, "You have %d practice sessions left.", ch->practice);
	}
	else
	{
		CHAR_DATA *mob;
		int adept;

		if (!IS_AWAKE(ch))
		{
			chprintln(ch, "In your dreams, or what?");
			return;
		}

		for (mob = ch->in_room->first_person; mob != NULL;
			 mob = mob->next_in_room)
		{
			if (IS_NPC(mob) && IS_SET(mob->act, ACT_PRACTICE))
				break;
		}

		if (mob == NULL)
		{
			chprintln(ch, "You can't do that here.");
			return;
		}

		if (ch->practice <= 0)
		{
			chprintln(ch, "You have no practice sessions left.");
			return;
		}

		if ((sn = find_spell(ch, argument)) < 0
			|| (!IS_NPC(ch)
				&& (!can_use_skpell(ch, sn) || ch->pcdata->learned[sn] < 1	/* skill is not known */
					|| skill_rating(ch, sn) == 0)))
		{
			chprintln(ch, "You can't practice that.");
			return;
		}

		adept = IS_NPC(ch) ? 100 : class_table[ch->Class[0]].skill_adept;

		if (ch->pcdata->learned[sn] >= adept)
		{
			chprintlnf(ch, "You are already learned at %s.",
					   skill_table[sn].name);
		}
		else
		{
			ch->practice--;
			ch->pcdata->learned[sn] +=
				int_app[get_curr_stat(ch, STAT_INT)].learn /
				skill_rating(ch, sn);
			if (ch->pcdata->learned[sn] < adept)
			{
				act("You practice $T.", ch, NULL,
					skill_table[sn].name, TO_CHAR);
				act("$n practices $T.", ch, NULL,
					skill_table[sn].name, TO_ROOM);
			}
			else
			{
				ch->pcdata->learned[sn] = adept;
				act("You are now learned at $T.", ch, NULL,
					skill_table[sn].name, TO_CHAR);
				act("$n is now learned at $T.", ch, NULL,
					skill_table[sn].name, TO_ROOM);
			}
		}
	}
	return;
}

/*
 * 'Wimpy' originally by Dionysos.
 */
CH_CMD(do_wimpy)
{
	char arg[MAX_INPUT_LENGTH];
	int wimpy;

	one_argument(argument, arg);

	if (IS_NULLSTR(arg))
		wimpy = ch->max_hit / 5;
	else
		wimpy = atoi(arg);

	if (wimpy < 0)
	{
		chprintln(ch, "Your courage exceeds your wisdom.");
		return;
	}

	if (wimpy > ch->max_hit / 2)
	{
		chprintln(ch, "Such cowardice ill becomes you.");
		return;
	}

	ch->wimpy = wimpy;
	chprintlnf(ch, "Wimpy set to %d hit points.", wimpy);
	return;
}

CH_CMD(do_password)
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char *pArg;
	char *pwdnew;
	char *p;
	char cEnd;

	if (IS_NPC(ch))
		return;

	/*
	 * Can't use one_argument here because it smashes case.
	 * So we just steal all its code.  Bleagh.
	 */
	pArg = arg1;
	while (isspace(*argument))
		argument++;

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

	while (*argument != '\0')
	{
		if (*argument == cEnd)
		{
			argument++;
			break;
		}
		*pArg++ = *argument++;
	}
	*pArg = '\0';

	pArg = arg2;
	while (isspace(*argument))
		argument++;

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

	while (*argument != '\0')
	{
		if (*argument == cEnd)
		{
			argument++;
			break;
		}
		*pArg++ = *argument++;
	}
	*pArg = '\0';

	if (IS_NULLSTR(arg1) || IS_NULLSTR(arg2))
	{
		chprintln(ch, "Syntax: password <old> <new>.");
		return;
	}

	if (str_casecmp(crypt(arg1, ch->pcdata->pwd), ch->pcdata->pwd))
	{
		WAIT_STATE(ch, 40);
		chprintln(ch, "Wrong password.  Wait 10 seconds.");
		return;
	}

	if (strlen(arg2) < 5)
	{
		chprintln(ch, "New password must be at least five characters long.");
		return;
	}

	/*
	 * No tilde allowed because of player file format.
	 */
	pwdnew = crypt(arg2, ch->name);
	for (p = pwdnew; *p != '\0'; p++)
	{
		if (*p == '~')
		{
			chprintln(ch, "New password not acceptable, try again.");
			return;
		}
	}

	replace_string(ch->pcdata->pwd, pwdnew);
	save_char_obj(ch);
	chprintln(ch, "Ok.");
	return;
}

void print_on_off(CHAR_DATA * ch, bool is_set, const char *cmd,
				  const char *desc)
{
	const char *on = "{WON";
	const char *off = "{DOFF";

	if (!IS_NULLSTR(desc))
	{
		chprintlnf(ch, " {G%-11s %-6s{w %s{x", cmd, is_set ? on : off, desc);
	}
	else
	{
		chprintf(ch, " {G%-11s %-6s{x ", cmd, is_set ? on : off);
	}
	return;
}

void set_on_off(CHAR_DATA * ch, flag_t * flags, flag_t flag, const char *on,
				const char *off)
{
	if (IS_SET(*flags, flag))
	{
		REMOVE_BIT(*flags, flag);
		chprintln(ch, off);
	}
	else
	{
		SET_BIT(*flags, flag);
		chprintln(ch, on);
	}
}