Mud20/accounts/
Mud20/accounts/c/
Mud20/accounts/f/
Mud20/accounts/k/
Mud20/accounts/s/
Mud20/accounts/t/
Mud20/area_current/
Mud20/area_current/newareas/
Mud20/bin/
Mud20/clans/
Mud20/gods/
Mud20/old-sources/
Mud20/player/
Mud20/player/a/del/
Mud20/player/b/
Mud20/player/b/bak/
Mud20/player/b/del/
Mud20/player/f/
Mud20/player/f/bak/
Mud20/player/f/del/
Mud20/player/k/
Mud20/player/k/bak/
Mud20/player/k/del/
Mud20/player/k/dmp/
Mud20/player/m/
Mud20/player/m/bak/
Mud20/player/o/
Mud20/player/o/bak/
Mud20/player/p/
Mud20/player/s/
Mud20/player/s/bak/
Mud20/player/s/del/
Mud20/player/t/
Mud20/player/t/del/
Mud20/player/v/
Mud20/public_html/
Mud20/races/
Mud20/skilltables/
__MACOSX/Mud20/accounts/
__MACOSX/Mud20/accounts/c/
__MACOSX/Mud20/accounts/f/
__MACOSX/Mud20/accounts/k/
__MACOSX/Mud20/accounts/s/
__MACOSX/Mud20/area_current/
__MACOSX/Mud20/area_current/core_areas/
__MACOSX/Mud20/area_current/helps/
__MACOSX/Mud20/area_current/newareas/
__MACOSX/Mud20/backups/
__MACOSX/Mud20/bin/
__MACOSX/Mud20/clans/
__MACOSX/Mud20/gods/
__MACOSX/Mud20/log/
__MACOSX/Mud20/old-sources/
__MACOSX/Mud20/player/
__MACOSX/Mud20/player/a/del/
__MACOSX/Mud20/player/b/
__MACOSX/Mud20/player/b/bak/
__MACOSX/Mud20/player/f/
__MACOSX/Mud20/player/f/bak/
__MACOSX/Mud20/player/f/del/
__MACOSX/Mud20/player/k/
__MACOSX/Mud20/player/k/bak/
__MACOSX/Mud20/player/k/del/
__MACOSX/Mud20/player/k/dmp/
__MACOSX/Mud20/player/m/
__MACOSX/Mud20/player/m/bak/
__MACOSX/Mud20/player/o/
__MACOSX/Mud20/player/o/bak/
__MACOSX/Mud20/player/p/
__MACOSX/Mud20/player/s/
__MACOSX/Mud20/player/s/bak/
__MACOSX/Mud20/player/t/del/
__MACOSX/Mud20/player/v/
__MACOSX/Mud20/public_html/
__MACOSX/Mud20/races/
__MACOSX/Mud20/skilltables/
/***************************************************************************
 * Mud20 1.0 by Todd H. Johnson (Kregor) a derivative of the Open Gaming   *
 * License by Wizards of the Coast. All comments referring to D20, OGL,    *
 * and SRD refer to the System Reference Document for the Open Gaming      *
 * system. Any inclusion of these derivatives must include credit to the   *
 * Mud20 system, the full and complete Open Gaming LIcense, and credit to  *
 * the respective authors. See ../doc/srd.txt for more information.        *
 *                                                                         *
 * Emud  2.2 by Igor van den Hoven, Michiel Lange, and Martin Bethlehem.   *
 *                                                                         *
 * MrMud 1.4 by David Bills, Dug Michael and Martin Gallwey                *
 *                                                                         *
 * 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 St{rfeld, Tom Madsen, and Katje Nyboe.     *
 ***************************************************************************/

/***************************************************************************
 * act_wiz.c: GM and administrative functions.													   *
 ***************************************************************************/

#include <sys/socket.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/resource.h>
#include "mud.h"

/*
	Local functions.
*/

bool		is_quest				args( ( unsigned char *pt ) );
void		save_html_who		args( ( void ) );

char *  const   function_flags [] =
{
	"builder",
	"helper",
	"enforcer",
	"god",
	"tester",
	"@",
	"@",
	"*"
};


void do_test( CHAR_DATA *ch, char *argument)
{
	int cnt;

	push_call("do_test(%p,%p)",ch,argument);

	if (*argument == 'b')
	{
		char bla[] = { 255, 253, 0 };
		char bli[] = { 255, 251, 0 };
		write_to_descriptor(ch->desc, bli, 3);
		write_to_descriptor(ch->desc, bla, 3);
	}

	if (*argument == 'e')
	{
		encrypt64(&argument[2]);
	}
	if (*argument == 'f')
	{
		char bla[] = { 255, 250, 39, 1, 3, 'U', 'S', 'E', 'R', 255, 240, 0 };
		write_to_descriptor(ch->desc, bla, 0);
	}
	if (*argument == 'p')
	{
		SET_BIT(mud->flags, MUD_SKIPOUTPUT);

		for (cnt = 0 ; cnt < MAX_PVNUM ; cnt++)
		{
			if (pvnum_index[cnt] == NULL)
			{
				continue;
			}
			if (get_player_world(ch, pvnum_index[cnt]->name) != NULL)
			{
				continue;
			}
			do_pload(ch, pvnum_index[cnt]->name);

			if (argument[1] != 'q' && pvnum_index[cnt])
			{
				do_pquit(ch, pvnum_index[cnt]->name);
			}
		}
		REMOVE_BIT(mud->flags, MUD_SKIPOUTPUT);
	}
	if (*argument == 'n')
	{
		write_to_descriptor(ch->desc, "\033[3h", 0);
	}
	if (*argument == 'o')
	{
		write_to_descriptor(ch->desc, "\033[?1h", 0);
	}
	pop_call();
	return;
}

/*
 * Display admin commands available to a player - Kregor
 */
void do_wizhelp( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	int cmd, col, level;

	push_call("do_wizhelp(%p,%p)",ch,argument);

	for (level = LEVEL_IMMORTAL, col = 0, buf[0] = '\0' ; level <= ch->level ; level++)
	{
		for (cmd = 0 ; cmd_table[cmd].name[0] != '\0' ; cmd++)
		{
			if (cmd_table[cmd].level == level && !IS_SET(cmd_table[cmd].flags, CMD_HIDE))
			{
				if (col % 5 == 0)
				{
					strcat(buf, get_color_string(ch, COLOR_TEXT, VT102_DIM));
				}
				cat_snprintf(buf, 16, "%d-%-13s", cmd_table[cmd].level, cmd_table[cmd].name);
				if (++col % 5 == 0)
				{
					strcat(buf, "\n\r");
				}
			}
		}
	}
	if (col % 5 != 0)
	{
		strcat(buf, "\n\r");
	}
	send_to_char(buf, ch);
	pop_call();
	return;
}

/*
 * Enable debug code for self or a specified player - Kregor
 */
void do_timemode( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;

	push_call("do_timemode(%p,%p)",ch,argument);

	if (!IS_GOD(ch))
	{
		pop_call();
		return;
	}
	
	if (argument[0] != '\0')
	{
		if ((victim = get_char_room(ch, argument)) == NULL)
		{
			send_to_char("That person is not here!\n\r", ch);
			pop_call();
			return;
		}
	}
	else
		victim = ch;

	if (IS_SET(victim->act, PLR_WIZTIME))
	{
		REMOVE_BIT( victim->act, PLR_WIZTIME);
		send_to_char( "Time and Debug info deactivated.\n\r", victim);
		if (victim != ch)
			send_to_char( "Time and Debug info deactivated.\n\r", ch);
	}
	else
	{
		SET_BIT( victim->act, PLR_WIZTIME);
		send_to_char( "Time and Debug info activated.\n\r", victim);
		if (victim != ch)
			send_to_char( "Time and Debug info activated.\n\r", ch);
	}
	pop_call();
	return;
}


/*
 * Display the specs for a room - Kregor
 */
void do_rstat( CHAR_DATA *ch, char *argument )
{
	int location;
	OBJ_DATA        *obj;
	CHAR_DATA       *rch;
	ROOM_TIMER_DATA *rtd;
	char arg1[MAX_INPUT_LENGTH];
	char buf1[MAX_STRING_LENGTH];
	char buf2[MAX_STRING_LENGTH];
	char buf3[MAX_STRING_LENGTH];
	char txt[MAX_STRING_LENGTH];
	char bld [10], dim [10];
	int door;

	push_call("do_rstat(%p,%p)",ch,argument);

	one_argument(argument, arg1);

	strcpy(dim, get_color_string(ch, COLOR_ACCENT,  VT102_DIM ));
	strcpy(bld, get_color_string(ch, COLOR_PROMPT,  VT102_BOLD));

	location = (arg1[0] == '\0') ? ch->in_room->vnum : find_location(ch, arg1);

	if (location == -1)
	{
		send_to_char( "No such location.\n\r", ch );
		pop_call();
		return;
	}

	if (!can_olc_modify(ch, location))
	{
		send_to_char("You can only stat rooms in your allocated range.\n\r", ch);
		pop_call();
		return;
	}

	sprintf(txt, "%s       Name:%s %s\n\r", dim, bld, room_index[location]->name);
	cat_sprintf(txt, "%s       Area:%s %s\n\r", dim, bld, room_index[location]->area->name);
	cat_sprintf(txt, "%s       Vnum:%s %u\n\r", dim, bld, room_index[location]->vnum);
	cat_sprintf(txt, "%s     Sector:%s %s\n\r", dim, bld, broken_bits(room_index[location]->sector_type, "SECT_", TRUE));
	cat_sprintf(txt, "%s   EffLight:%s %s\n\r", dim, bld, light_levels[get_room_light(room_index[location])]);
	cat_sprintf(txt, "%s LightApply:%s %d\n\r", dim, bld, room_index[location]->light);

	cat_sprintf(txt, "%s Room flags: %s%s\n\r", dim, bld, flag_string(room_index[location]->room_flags, r_flags));

	if (room_index[location]->first_extradesc != NULL )
	{
		EXTRA_DESCR_DATA *ed;

		sprintf(buf1, "%sExtra Descs:%s ",      dim, bld);
		sprintf(buf2, "%s,%s ",                 dim, bld);
		for (ed = room_index[location]->first_extradesc ; ed ; ed = ed->next)
		{
			strcat(buf1, ed->keyword);
			if (ed->next)
			{
				strcat(buf1, buf2);
			}
		}
		cat_sprintf(txt, "%s\n\r", buf1);
	}

	sprintf( buf1, "%s Characters:%s ",     dim, bld);
	sprintf( buf2, "%s,%s ",                dim, bld);
	for (rch = room_index[location]->first_person ; rch ; rch = rch->next_in_room)
	{
		if (can_see(ch, rch))
		{
			one_argument_nolower(rch->name, buf3);
			if (str_suffix(" ", buf1))
			{
				strcat(buf1, buf2);
			}
			strcat(buf1, buf3);
		}
	}
	cat_sprintf(txt, "%s\n\r", buf1);

	if (room_index[location]->first_content)
	{
		sprintf(buf1, "%s    Objects:%s ",      dim, bld);
		sprintf(buf2, "%s,%s ",                 dim, bld);
		for (obj = room_index[location]->first_content ; obj ; obj = obj->next_content)
		{
			if (can_see_obj(ch, obj))
			{
				if (strlen(buf1) > 33)
				{
					strcat(buf1, buf2);
				}
				one_argument_nolower(obj->name, buf3);
				strcat(buf1, buf3);
			}
		}
		cat_sprintf(txt, "%s\n\r", buf1);
	}

	for (door = 0 ; door <= 5 ; door++)
	{
		EXIT_DATA *pExit;

		if ((pExit = room_index[location]->exit[door]) != NULL)
		{
			sprintf(buf1,"%s      %5s:%s %5d", dim, capitalize(dir_name[door]), bld, pExit->to_room);
			sprintf(buf2,"%s Key:%s %5d",     dim, bld, pExit->key);
			sprintf(buf3,"%s Flags:%s %s",      dim, bld, flag_string(pExit->exit_info, exit_flags));

			cat_sprintf(txt, "%s%s%s\n\r", buf1, buf2, buf3);
		}
	}
	
	for (rtd = mud->f_room_timer ; rtd ; rtd = rtd->next)
	{
		if (rtd->vnum == location)
		{
			sprintf(buf1, "%s AffectedBy:%s (%s) %s%s - %s for %s\n\r", dim, bld, rtd->caster, dim,
				is_string(skill_table[rtd->type].name) ? skill_table[rtd->type].name : "Unknown",
				flag_string(rtd->bitvector, r_flags), format_duration(rtd->duration));
			strcat(txt, buf1);
		}
	}
	send_to_char_color(txt, ch);
	pop_call();
	return;
}

/*
 * Display the specs for an item - Kregor
 */
void do_ostat( CHAR_DATA *ch, char *argument )
{
	char buf [MAX_STRING_LENGTH];
	char buf1[MAX_STRING_LENGTH], buf2[MAX_STRING_LENGTH];
	char buf3[MAX_STRING_LENGTH], buf4[MAX_STRING_LENGTH];
	char output [MAX_STRING_LENGTH];
	char bld [10], dim [10];

	AFFECT_DATA *paf;
	OBJ_DATA    *obj;

	push_call("do_ostat(%p,%p)",ch,argument);

	if (*argument == '\0')
	{
		send_to_char( "Syntax: ostat <vnum|name>\n\r", ch );
		pop_call();
		return;
	}

	if (is_number(argument))
	{
		if ((obj = get_obj_vnum(ch, argument)) == NULL)
		{
			send_to_char( "No object loaded has that vnum.\n\r", ch );
			pop_call();
			return;
		}
	}
	else
	{
		if ((obj = get_obj_world(ch, argument)) == NULL)
		{
			send_to_char( "No object loaded has that name.\n\r", ch );
			pop_call();
			return;
		}
	}

	if (!can_olc_modify(ch, obj->pIndexData->vnum))
	{
		send_to_char("You can only stat objects in your allocated vnum range.\n\r", ch);
		pop_call();
		return;
	}

	strcpy(dim, get_color_string(ch, COLOR_ACCENT,  VT102_DIM ));
	strcpy(bld, get_color_string(ch, COLOR_PROMPT,  VT102_BOLD));

	sprintf(output, "%s    Name:%s %s\n\r", dim, bld, obj->name);
	cat_sprintf(output, "%s   Short:%s %s\n\r", dim, bld, obj->short_descr);
	cat_sprintf(output, "%s    Long:%s %s\n\r", dim, bld, obj->long_descr);

	if (obj->pIndexData->first_extradesc)
	{
		EXTRA_DESCR_DATA *ed;

		sprintf(buf1, "%sKeywords:%s", dim, bld);

		for (ed = obj->pIndexData->first_extradesc ; ed != NULL ; ed = ed->next)
		{
			strcat(buf1, " ");
			strcat(buf1, ed->keyword);
		}

		cat_sprintf(output, "%s\n\r", buf1);
	}

	if (obj->carried_by != NULL)
	{
		cat_sprintf(output, "%s Carrier:%s %s\n\r", dim, bld, get_name(obj->carried_by));
	}
	else if (obj->in_room != NULL)
	{
		cat_sprintf(output, "%s InRoom:%s %s\n\r", dim, bld, obj->in_room->name);
	}

	sprintf(buf1, "%s    Vnum:%s %-10u",   dim, bld, obj->pIndexData->vnum);
	sprintf(buf2, "%s   Index:%s %-30lld", dim, bld, obj->obj_ref_key);
	sprintf(buf3, "%s   Total:%s %-10d",   dim, bld, obj->pIndexData->total_objects);

	cat_sprintf(output, "%s%s%s\n\r", buf1, buf2, buf3);

	sprintf(buf1, "%s   Level:%s %-10d", dim, bld, obj->level);
	sprintf(buf2, "%s    Cost:%s %-10d", dim, bld, obj->cost);
	sprintf(buf , "%d.%d", get_obj_weight(obj)/10, get_obj_weight(obj)%10);
	sprintf(buf3, "%s  Weight:%s %-10s", dim, bld, buf);
	sprintf(buf4, "%s    Type:%s %-10s", dim, bld, item_type_name(obj));

	cat_sprintf(output, "%s%s%s%s\n\r", buf1, buf2, buf3, buf4);

	sprintf(buf1, "%s    Room:%s %-10u", dim, bld, obj->in_room ? obj->in_room->vnum : 0);
	sprintf(buf2, "%s  In obj:%s %-10u", dim, bld, obj->in_obj ? obj->in_obj->pIndexData->vnum : 0);
	sprintf(buf3, "%s Wearloc:%s %-10d", dim, bld, obj->wear_loc);
	sprintf(buf4, "%s In game:%s %-10d", dim, bld, obj->pIndexData->total_objects);

	cat_sprintf(output, "%s%s%s%s\n\r", buf1, buf2, buf3, buf4);

	sprintf(buf1, "%s  Value0:%s %-10d", dim, bld, obj->value[0]);
	sprintf(buf2, "%s  Value1:%s %-10d", dim, bld, obj->value[1]);
	sprintf(buf3, "%s  Value2:%s %-10d", dim, bld, obj->value[2]);
	sprintf(buf4, "%s  Value3:%s %-10d", dim, bld, obj->value[3]);

	cat_sprintf(output, "%s%s%s%s\n\r", buf1, buf2, buf3, buf4);

	sprintf(buf1, "%s  Value4:%s %-10d", dim, bld, obj->value[4]);
	sprintf(buf2, "%s  Value5:%s %-10d", dim, bld, obj->value[5]);
	sprintf(buf3, "%s  Value6:%s %-10d", dim, bld, obj->value[6]);
	sprintf(buf4, "%s  Value7:%s %-10d", dim, bld, obj->value[7]);

	cat_sprintf(output, "%s%s%s%s\n\r", buf1, buf2, buf3, buf4);

	switch (obj->item_type)
	{
		case ITEM_ARMOR:
			sprintf(buf1, "%s   armor:%s %s", dim, bld, armor_table[obj->value[0]].name);
			sprintf(buf2, "%s (AC: %d, max DEX bonus: %d, armor check: %d, spell fail: %d%%)",
				bld, armor_table[obj->value[0]].ac_bonus, armor_table[obj->value[0]].dex_max,
				armor_table[obj->value[0]].armor_check, armor_table[obj->value[0]].spell_fail);
			cat_sprintf(output, "%s%s\n\r", buf1, buf2);
			break;
		case ITEM_WEAPON:
			sprintf(buf1, "%s  weapon:%s %s", dim, bld, weapon_table[obj->value[0]].name);
			sprintf(buf2, "%s (dmg: %dd%d, threat range: %d, crit x: %d, range: %d%%)",
				bld, weapon_table[obj->value[0]].damnodice, weapon_table[obj->value[0]].damsizedice,
				weapon_table[obj->value[0]].threat, weapon_table[obj->value[0]].critical,
				weapon_table[obj->value[0]].range);
			cat_sprintf(output, "%s%s\n\r", buf1, buf2);
			break;
		case ITEM_SCROLL:
		case ITEM_PILL:
		case ITEM_POTION:
			cat_sprintf(output, "%s   spell:%s lvl %d %s, %s, %s\n\r", dim, bld, obj->value[0],
				skill_name(obj->value[1]), skill_name(obj->value[2]), skill_name(obj->value[3]));
			break;
		case ITEM_WAND:
		case ITEM_STAFF:
			sprintf(buf1, "%s  charge:%s %6d/%-3d", dim, bld, obj->value[1], obj->value[2]);
			sprintf(buf2, "%s   spell:%s lvl %d '%s'", dim, bld, obj->value[0], skill_name(obj->value[3]));
			if (obj->item_type == ITEM_STAFF)
				cat_sprintf(buf2, " '%s' '%s' '%s'", skill_name(obj->value[4]), skill_name(obj->value[5]), skill_name(obj->value[6]));
			cat_sprintf(output, "%s%s\n\r", buf1, buf2);
			break;
		case ITEM_LIGHT:
			cat_sprintf(output, "%s   light:%s %-10d\n\r", dim, bld, obj->value[2]);
			break;
		case ITEM_FIRE:
			cat_sprintf(output, "%s   hours:%s %-10d\n\r", dim, bld, obj->value[2]);
			break;
		case ITEM_COMPONENT:
			cat_sprintf(output, "%s    uses:%s %-10d\n\r", dim, bld, obj->value[0]);
			break;
		case ITEM_SYMBOL:
			cat_sprintf(output, "%s     god:%s %s\n\r", dim, bld, get_god_name(obj->value[2]));
			cat_sprintf(output, "%s   bonus:%s %-3d\n\r", dim, bld, obj->value[3]);
			break;
		case ITEM_FOUNTAIN:
			cat_sprintf(output, "%s  liquid:%s %-10s\n\r", dim, bld, type_string(obj->value[2], liq_types));
			break;
		case ITEM_DRINK_CON:
			sprintf(buf1, "%s  liquid:%s %-10s", dim, bld, type_string(obj->value[2], liq_types));
			sprintf(buf2, "%s  charge:%s %5d/%-4d", dim, bld, obj->value[0], obj->value[1]);
			sprintf(buf3, "%s  poison:%s %-10s", dim, bld, type_string(obj->value[3], poison_names));
			cat_sprintf(output, "%s%s%s\n\r", buf1, buf2, buf3);
			break;
		case ITEM_FOOD:
			cat_sprintf(output, "%s    fill:%s %10d\n\r", dim, bld, obj->value[0]);
			cat_sprintf(output, "%s  poison:%s %10s\n\r", dim, bld, type_string(obj->value[3], poison_names));
			break;
		case ITEM_PORTAL:
			sprintf(buf1, "%s  charge:%s %-10d", dim, bld, obj->value[0]);
			sprintf(buf2, "%s  toroom:%s %-10d", dim, bld, obj->value[3]);
			sprintf(buf3, "%s   enter:%s %s", dim, bld, flag_string(obj->value[2], portal_flags));
			cat_sprintf(output, "%s%s%s\n\r", buf1, buf2, buf3);
			break;
		case ITEM_TOOLS:
			sprintf(buf1, "%s    type:%s %-20s", dim, bld, tool_types[obj->value[0]]);
			sprintf(buf2, "%s  charge:%s %-10d", dim, bld, obj->value[1]);
			sprintf(buf2, "%s   bonus:%s %-10d", dim, bld, obj->value[2]);
			cat_sprintf(output, "%s%s%s\n\r", buf1, buf2, buf3);
			break;
		case ITEM_AMMO:
			cat_sprintf(output, "%s  weapon:%s %-10s\n\r", dim, bld, type_string(obj->value[0], bow_types));
			break;
		case ITEM_CONTAINER:
		case ITEM_SPELLPOUCH:
		case ITEM_CART:
		case ITEM_SHEATH:
		case ITEM_QUIVER:
			cat_sprintf(output, "%s   Carry:%s %-10d\n\r", dim, bld, obj->value[0]);
			cat_sprintf(output, "%s     Lid:%s %-10s\n\r", dim, bld, obj->value[1] < 1 ? "none" : flag_string(obj->value[1], cont_flags));
			cat_sprintf(output, "%s     Key:%s %-10s\n\r", dim, bld, obj->value[2] < 1 ? "none" : get_obj_index(obj->value[2]) ? get_obj_index(obj->value[2])->short_descr : "unknown");
			cat_sprintf(output, "%sCapacity:%s %-10d\n\r", dim, bld, obj->value[3]);
			break;
		case ITEM_FURNITURE:
			sprintf(buf1, "%s    Size:%s %-10d", dim, bld, obj->value[0]);
			sprintf(buf2, "%s   Poses:%s %s", dim, bld, flag_string(obj->value[2], f_flags));
			cat_sprintf(output, "%s%s\n\r", buf1, buf2);
			break;
	}

	sprintf(buf1, "%s HitPnts:%s %4d/%-4d ", dim, bld, obj->hit_points, get_obj_max_hit(obj));
	sprintf(buf2, "%sMaterial:%s %-10s", dim, bld, material_types[obj->material]);
	sprintf(buf3, "%s    Size:%s %-10s", dim, bld, size_types[obj->size]);
	sprintf(buf4, "%s   Owner:%s %-10d", dim, bld, obj->owned_by);

	cat_sprintf(output, "%s%s%s%s\n\r", buf1, buf2, buf3, buf4);

	sprintf(buf1, "%sSactimer:%s %-10d", dim, bld, obj->sac_timer);
	sprintf(buf2, "%s   Timer:%s %-10d", dim, bld, obj->timer);
	sprintf(buf3, "%sIdentify:%s %-10s", dim, bld, obj->identified > 0 ? "TRUE" : "FALSE");

	cat_sprintf(output, "%s%s%s\n\r", buf1, buf2, buf3);

	cat_sprintf(output, "%s ID Name:%s %s\n\r", dim, bld, obj->id_name ? obj->id_name : "None");
	cat_sprintf(output, "%s ID Desc:%s %s\n\r", dim, bld, obj->id_descr ? obj->id_descr : "None");
	cat_sprintf(output, "%sWearflag:%s %s\n\r", dim, bld, flag_string(obj->wear_flags, w_flags));
	cat_sprintf(output, "%sItemflag:%s %s\n\r", dim, bld, flag_string(obj->extra_flags, o_flags));

	for (paf = obj->first_affect ; paf != NULL ; paf = paf->next)
	{
		cat_sprintf(output, "%s Affects:%s %-22s%s %s by %d for%s\n\r", dim, bld, skill_table[(int) paf->type].name, dim, affect_loc_name(paf->location), paf->modifier, format_duration(paf->duration));
	}

	cat_sprintf(output, "%s   Quest:%s %-22s %s#%s\n\r", dim, bld, obj->pIndexData->area->name, dim, quest_bits_to_string(obj->obj_quest));

	if (obj->reset != NULL && obj->reset->obj == obj)
	{
		RESET_DATA *pReset = obj->reset;

		while (pReset != NULL)
		{
			cat_sprintf(output, "%s  Reset:%s %c %s %5d %4d %5d\n\r",
				dim, bld, pReset->command, dim,
				pReset->arg1, pReset->arg2, pReset->arg3);

			pReset = pReset->container;
		}
	}
	send_to_char_color(output, ch);
	pop_call();
	return;
}

/*
 * Display the specs for a PC or NPC - Kregor
 */
void do_mstat( CHAR_DATA *ch, char *argument )
{
	char tmp[MAX_STRING_LENGTH];
	char buf1[MAX_STRING_LENGTH];
	char buf2[MAX_STRING_LENGTH];
	char buf3[MAX_STRING_LENGTH];
	char buf4[MAX_STRING_LENGTH];
	char txt[MAX_STRING_LENGTH];
	char colw[10], colc[10];
	unsigned long num;
	int cnt, item;
	AFFECT_DATA *paf;
	CHAR_DATA   *victim;
	OBJ_DATA    *wield;
	AREA_DATA   *pArea;

	push_call("do_mstat(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		send_to_char("Syntax: mstat <vnum|name>\n\r", ch);
		pop_call();
		return;
	}

	if (is_number_argument(argument))
	{
		if ((victim = get_mob_vnum(ch, argument)) == NULL)
		{
			send_to_char( "No mobile loaded with that vnum.\n\r", ch );
			pop_call();
			return;
		}
	}
	else if ((victim = get_char_world(ch, argument)) == NULL)
	{
		send_to_char( "No mobile loaded with that name.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_NPC(victim) && !can_olc_modify(ch, victim->pIndexData->vnum))
	{
		send_to_char("You can only stat mobiles in your allocated vnum range.\n\r", ch);
		pop_call();
		return;
	}
	if (!IS_NPC(victim) && !IS_GOD(ch))
	{
		send_to_char("You can only stat NPCs.\n\r", ch);
		pop_call();
		return;
	}

	strcpy(colc, get_color_string(ch, COLOR_ACCENT,  VT102_DIM));
	strcpy(colw, get_color_string(ch, COLOR_PROMPT,  VT102_DIM));
	tmp[0] = '\0';

	sprintf(txt, "%s        Name: %s%s\n\r"  , colc, colw, victim->name);
	if (IS_NPC(victim))
	{
		cat_sprintf(txt, "%s       Short: %s%s\n\r"  , colc, colw, victim->short_descr);
		cat_sprintf(txt, "%s        Long: %s%s\n\r"  , colc, colw, victim->long_descr);
		cat_sprintf(txt, "%sResetMessage: %s%s\n\r"  , colc, colw, victim->pIndexData->reset_msg ? victim->pIndexData->reset_msg : "None");
	}

	if (IS_NPC(victim))
		cat_sprintf(txt, "%s        Vnum: %s%-11u "   , colc, colw, victim->pIndexData->vnum);
	else
		cat_sprintf(txt, "%s       Pvnum: %s%-11u "   , colc, colw, victim->pcdata->pvnum);
	cat_sprintf(txt, "%s       Level: %s%-11d "   , colc, colw, victim->level);
	cat_sprintf(txt, "%s        Room: %s%-11u\n\r", colc, colw, victim->in_room->vnum);

	if (!IS_NPC(victim))
	{
		cat_sprintf(txt, "%sHours Played: %s%-11d %s  Experience: %s%-11d\n\r",
			colc, colw, victim->pcdata->played/3600 + victim->pcdata->previous_hours,
			colc, colw, victim->pcdata->exp);
	}

	sprintf(buf1, "%s        Race: %s%-11s "   , colc, colw, !is_string(race_table[victim->race].race_name) ? "None" : race_table[victim->race].race_name);
	sprintf(buf2, "%s         Sex: %s%-11s "   , colc, colw, victim->sex <= 0 ? "Neutral" : victim->sex <= 1 ? "Male" : "Female");
	sprintf(buf3, "%s    Position: %s%-11s\n\r", colc, colw, p_types[victim->position]);

	cat_sprintf(txt, "%s%s%s", buf1, buf2, buf3);

	for (tmp[0] = '\0', cnt = 0 ; cnt < MAX_CLASS ; cnt++)
	{
		if (victim->mclass[cnt] <= 0)
			continue;
		if (strlen(tmp))
			cat_sprintf(tmp, ", ");
		cat_sprintf(tmp, "%s %d", class_table[cnt].who_name_long, victim->mclass[cnt]);
	}
	cat_sprintf(txt, "  %s     Class: %s%s\n\r", colc, colw, tmp);

	sprintf(buf4, "%s%s",
		IS_LAWFUL(victim) ? "L" : IS_CHAOTIC(victim) ? "C" : IS_NEUTRAL(victim) ? "T" : "N",
		IS_GOOD(victim) ? "G" : IS_EVIL(victim) ? "E" : "N");
	sprintf(buf1, "%s   Alignment: %s%-11s "   , colc, colw, buf4);
	sprintf(buf2, "%s Armor Class: %s%-11d "   , colc, colw, GET_AC(victim, FALSE));
	sprintf(buf3, "%s        Size: %s%-11s\n\r", colc, colw, size_types[get_size(victim)]);

	cat_sprintf(txt, "%s%s%s", buf1, buf2, buf3);

	sprintf(buf1, "%s         BAB: %s%-11d "   , colc, colw, base_attack(victim));
	victim->attack_part = get_body_part(victim, TYPE_HIT, 1);
	sprintf(tmp,  "%dd%d+%d", get_damnodice(victim), get_damsizedice(victim), stat_bonus(TRUE, victim, APPLY_STR));
	sprintf(buf2, "%s     Damroll: %s%-11s "   , colc, colw, tmp);
	if ((wield = get_wield(victim, FALSE)) != NULL)
	{
		sprintf(tmp, "%dd%d", weapon_table[wield->value[0]].damnodice, weapon_table[wield->value[0]].damsizedice);
	}
	else
	{
		sprintf(tmp, "none");
	}
	sprintf(buf3, "%s      Weapon: %s%-11s\n\r", colc, colw, tmp);

	cat_sprintf(txt, "%s%s%s", buf1, buf2, buf3);

	for (tmp[0] = '\0', cnt = 0 ; cnt < ATTK_MAX ; cnt++)
	{
		if (num_attacks(victim, cnt) <= 0)
			continue;
		if (strlen(tmp))
			cat_sprintf(tmp, ", ");
		victim->attack_part = cnt;
		cat_sprintf(tmp, "%dx%s %dd%d+%d", num_attacks(victim, cnt), capitalize(attack_part_flags[cnt]), get_damnodice(victim), get_damsizedice(victim), stat_bonus(TRUE, victim, APPLY_STR));
	}
	cat_sprintf(txt, "  %s   Attacks: %s%s\n\r", colc, colw, strlen(tmp) ? tmp : "None");

	sprintf(buf1, "%s   FORT Save: %s%-11d "   , colc, colw, get_fort_save(victim));
	sprintf(buf2, "%s   REFL Save: %s%-11d "   , colc, colw, get_refl_save(victim));
	sprintf(buf3, "%s   WILL Save: %s%-11d\n\r", colc, colw, get_will_save(victim));

	cat_sprintf(txt, "%s%s%s", buf1, buf2, buf3);

	sprintf(tmp, "%d/%d/%d", victim->hit, victim->nonlethal, get_max_hit(victim));
	sprintf(buf1, "%s HP/NL/HPMax: %s%-11s "   , colc, colw, tmp);
	sprintf(tmp, "%d/%d", victim->mana[ch->class], get_max_mana(victim, ch->class));
	sprintf(buf2, "%s        Mana: %s%-11s "   , colc, colw, tmp);
	sprintf(tmp, "%d/%d", victim->move, get_max_move(victim));
	sprintf(buf3, "%s        Move: %s%-11s\n\r", colc, colw, tmp);

	cat_sprintf(txt, "%s%s%s", buf1, buf2, buf3);

	cat_sprintf(txt, "%s  Attributes: Str:%s %2d/%-2d %sInt:%s %2d/%-2d %sWis:%s %2d/%-2d %sDex:%s %2d/%-2d %sCon:%s %2d/%-2d %sCha:%s %2d/%-2d\n\r",
		colc, colw, get_curr_str(victim), victim->perm_str,
		colc, colw, get_curr_int(victim), victim->perm_int,
		colc, colw, get_curr_wis(victim), victim->perm_wis,
		colc, colw, get_curr_dex(victim), victim->perm_dex,
		colc, colw, get_curr_con(victim), victim->perm_con,
		colc, colw, get_curr_cha(victim), victim->perm_cha);

	if (IS_NPC(victim))
	{
		for (tmp[0] = '\0', cnt = 0 ; valid_skill(cnt) ; cnt++)
		{
			if (skill_table[cnt].skilltype != FSKILL_FEAT)
				continue;
			if (!victim->learned[cnt])
				continue;
			if (strlen(tmp))
				cat_sprintf(tmp, ", ");
			cat_sprintf(tmp, "%s", skill_table[cnt].name);
		}
		if (strlen(tmp))
			cat_sprintf(txt, "  %s     Feats: %s%s\n\r", colc, colw, tmp);
	
		for (tmp[0] = '\0', cnt = 0 ; valid_skill(cnt) ; cnt++)
		{
			if (skill_table[cnt].skilltype != FSKILL_SKILL
			&& skill_table[cnt].skilltype != FSKILL_KNOWLEDGE
			&& skill_table[cnt].skilltype != FSKILL_CRAFT)
				continue;
			if (!victim->learned[cnt])
				continue;
			if (strlen(tmp))
				cat_sprintf(tmp, ", ");
			cat_sprintf(tmp, "%s %+d", skill_table[cnt].name, victim->learned[cnt]);
		}
		if (strlen(tmp))
			cat_sprintf(txt, "  %s     Skills: %s%s\n\r", colc, colw, tmp);
	
		for (tmp[0] = '\0', cnt = 0 ; valid_skill(cnt) ; cnt++)
		{
			if (skill_table[cnt].skilltype != FSKILL_ABILITY
			&& skill_table[cnt].skilltype != FSKILL_RACEATTACK)
				continue;
			if (!victim->learned[cnt])
				continue;
			if (strlen(tmp))
				cat_sprintf(tmp, ", ");
			cat_sprintf(tmp, "%s %+d", skill_table[cnt].name, victim->learned[cnt]);
		}
		if (strlen(tmp))
			cat_sprintf(txt, "  %s  Abilities: %s%s\n\r", colc, colw, tmp);
	}

	sprintf(buf1, "%sCarry Number: %s%-11d "   , colc, colw, victim->carry_number);
	sprintf(buf2, "%sCarry Weight: %s%-11d"   , colc, colw, victim->carry_weight);
	sprintf(buf3, "%s Crit Hit By: %s%-11d\n\r"   , colc, colw, victim->critical_hit_by);

	cat_sprintf(txt, "%s%s%s", buf1, buf2, buf3);

	sprintf(buf1, "%s    XP Value: %s%-11d "   , colc, colw, get_exp_worth(victim));
	sprintf(buf2, "%s    Fighting: %s%-11s\n\r"   , colc, colw, get_name(who_fighting(victim)));

	cat_sprintf(txt, "%s%s", buf1, buf2);

	for (paf = victim->first_affect ; paf != NULL ; paf = paf->next)
	{
		cat_sprintf(txt, "%s      Affect: %s%-22s%s %s by %d for%s\n\r", colc, colw, skill_table[(int) paf->type].name, colc, affect_loc_name(paf->location), paf->modifier, format_duration(paf->duration));
	}

	if (IS_NPC(victim))
		cat_sprintf(txt, "%s   Act Flags: %s%s\n\r", colc, colw, flag_string(victim->act, act_flags));
	else
		cat_sprintf(txt, "%sPlayer Flags: %s%s\n\r", colc, colw, flag_string(victim->act, plr_flags));
	cat_sprintf(txt, "%sAffect Flags: %s%s\n\r", colc, colw, flag_string(victim->affected_by, a_flags));
	cat_sprintf(txt, "%s  Aff2 Flags: %s%s\n\r", colc, colw, flag_string(victim->affected2_by, a2_flags));

	sprintf(buf1, "%s      Master: %s%-11s "   , colc, colw, victim->master   ? victim->master->name        : "none");
	sprintf(buf2, "%s      Leader: %s%-11s "  , colc, colw, victim->leader   ? victim->leader->name        : "none");
	if (IS_NPC(victim))
		sprintf(buf3, "%s%12s: %s%s\n\r"        , colc, IS_SET(victim->act, ACT_WIMPY) ? "Fearing" : "Hating", colw, !victim->npcdata->hate_fear ? "none" : pvnum_index[victim->npcdata->hate_fear]->name);
	else
		sprintf(buf3, "\n\r");

	cat_sprintf(txt, "%s%s%s", buf1, buf2, buf3);

	if (IS_NPC(victim))
	{
		if (victim->pIndexData->spec_fun != NULL)
		{
			cat_sprintf(txt, "%s    Spec Fun: %s%s\n\r", colc, colw, spec_name_lookup(victim->pIndexData->spec_fun));
		}
		cat_sprintf(txt, "%s       Quest: %s%-22s%s #%s\n\r", colc, colw, victim->pIndexData->area->name, colc, quest_bits_to_string(victim->npcdata->mob_quest));

		if (victim->reset != NULL && victim->reset->mob == victim)
		{
			RESET_DATA *pReset = victim->reset;
	
			cat_sprintf(txt, "%s       Reset:%s %c %s %5d %4d %5d\n\r",
				colc, colw, pReset->command, colc,
				pReset->arg1, pReset->arg2, pReset->arg3);
		}
		for (cnt = 0 ; cnt < MAX_WEAR ; cnt++)
		{
			if ((item = victim->pIndexData->load_eq[cnt]) > 0)
			{
				cat_sprintf(txt, "      %sLoadEQ: %s%s - %s\n\r", colc, colw, capitalize(wear_locs[cnt]), obj_index[item]->name);
			}
		}
	}
	else
	{
		cat_sprintf(txt, "%s      Thirst: %s%-11d %s        Full: %s%-11d %s       Drunk: %s%-11d\n\r",
			colc, colw, victim->pcdata->condition[COND_THIRST],
			colc, colw, victim->pcdata->condition[COND_FULL],
			colc, colw, victim->pcdata->condition[COND_DRUNK]);

		cat_sprintf(txt, "%s   Skill Pts: %s%-11d %s    Feat Pts: %s%-11d %s    Stat Pts: %s%-11d\n\r",
			colc, colw, victim->pcdata->practice,
			colc, colw, victim->pcdata->feat_pts,
			colc, colw, victim->pcdata->stat_pts);

		for (pArea = mud->f_area ; pArea ; pArea = pArea->next)
		{
			num = pArea->low_r_vnum/100;
			if (is_quest(victim->pcdata->quest[num]))
			{
				cat_sprintf(txt, "%s       Quest: %s%-22s%s #%s\n\r", colc, colw, pArea->name, colc, quest_bits_to_string(victim->pcdata->quest[num]));
			}
		}
	}
	send_to_char_color(txt, ch);

	pop_call();
	return;
}

int cnt_op_lines( AREA_DATA *area )
{
	int cnt, vnum;
	MPROG_DATA *oprog;
	NPC_TOKEN  *token;

	push_call("cnt_mp_lines(%p)",area);

	for (cnt = 0, vnum = area->low_o_vnum ; vnum <= area->hi_o_vnum ; vnum++)
	{
		if (obj_index[vnum] == NULL)
		{
			continue;
		}

		for (oprog = obj_index[vnum]->first_prog ; oprog ; oprog = oprog->next)
		{
			for (token = oprog->first_token ; token ; token = token->next)
			{
				cnt++;
			}
		}
	}
	pop_call();
	return cnt;
}

int cnt_mp_lines( AREA_DATA *area )
{
	int cnt, vnum;
	MPROG_DATA *mprog;
	NPC_TOKEN  *token;

	push_call("cnt_mp_lines(%p)",area);

	for (cnt = 0, vnum = area->low_m_vnum ; vnum <= area->hi_m_vnum ; vnum++)
	{
		if (mob_index[vnum] == NULL)
		{
			continue;
		}

		for (mprog = mob_index[vnum]->first_prog ; mprog ; mprog = mprog->next)
		{
			for (token = mprog->first_token ; token ; token = token->next)
			{
				cnt++;
			}
		}
	}
	pop_call();
	return cnt;
}

/*
 * Display the specs for a zone - Kregor
 */
void do_astat( CHAR_DATA *ch, char *argument )
{
	AREA_DATA *pArea;
	bool found;

	push_call("do_astat(%p,%p)",ch,argument);

	found = FALSE;

	if (argument[0] != '\0')
	{
		for (pArea = mud->f_area ; pArea ; pArea = pArea->next)
		{
			if (!strcasecmp(pArea->filename, argument)
			|| !str_prefix(argument, pArea->name))
			{
				found = TRUE;
				break;
			}
		}

		if (!found)
		{
			if (argument[0] != '\0' )
			{
				send_to_char( "Syntax: astat [filename|areaname]\n\r", ch );
				pop_call();
				return;
			}
		}
	}
	else
	{
		pArea = ch->in_room->area;
	}

	if (!can_olc_modify(ch, pArea->low_r_vnum))
	{
		ch_printf_color(ch, "You can only stat areas in your allocated vnum range\n\r");
		pop_call();
		return;
	}

	ch_printf_color( ch, "{078}      name: {178}%s\n\r",		pArea->name);
	ch_printf_color( ch, "{078}  filename: {178}%-20s\n\r",	pArea->filename);
	ch_printf_color( ch, "{078}   authors: {178}%s\n\r",		pArea->authors);
	ch_printf_color( ch, "{078}  resetmsg: {178}%s\n\r",		pArea->resetmsg);
	ch_printf_color( ch, "{078}area flags: {178}%s\n\r",		flag_string(pArea->flags, area_flags));
	ch_printf_color( ch, "{078} Courtroom: {178}%d - %s\n\r",	pArea->courtroom, !pArea->courtroom ? "None" : room_index[pArea->courtroom] == NULL ? "NULL room" : room_index[pArea->courtroom]->name);
	ch_printf_color( ch, "{078}   Dungeon: {178}%d - %s\n\r",	pArea->dungeon, !pArea->dungeon ? "None" : room_index[pArea->dungeon] == NULL ? "NULL room" : room_index[pArea->dungeon]->name);
	ch_printf_color( ch, "{078} Storeroom: {178}%d - %s\n\r",	pArea->storeroom, !pArea->storeroom ? "None" : room_index[pArea->storeroom] == NULL ? "NULL room" : room_index[pArea->storeroom]->name);
	ch_printf_color( ch, "{078}     Judge: {178}%s\n\r",	!pArea->judge ? "None" : mob_index[pArea->judge] == NULL ? "NULL mob" : mob_index[pArea->judge]->player_name);
	ch_printf_color( ch, "{078}     Guard: {178}%s\n\r",	!pArea->guard ? "None" : mob_index[pArea->guard] == NULL ? "NULL mob" : mob_index[pArea->guard]->player_name);
	ch_printf_color( ch, "{078}     Quest: {178}%s\n\r",	quest_bits_to_string(pArea->area_quest));
	ch_printf_color( ch, "{078}       age: {178}%5d         {078}           players: {178}%5d\n\r",	pArea->age,			pArea->nplayer);
	ch_printf_color( ch, "{078}     level: {178}%5d         {078}             count: {178}%5d\n\r",	pArea->average_level,	pArea->count);
	ch_printf_color( ch, "{078}    mprogs: {178}%5d         {078}            oprogs: {178}%5d\n\r",	cnt_mp_lines(pArea),	cnt_op_lines(pArea));
	ch_printf_color( ch, "{078} low_range: {178}%5d         {078}          hi_range: {178}%5d\n\r",	pArea->olc_range_lo,	pArea->olc_range_hi);
	ch_printf_color( ch, "{078}  low_room: {178}%5d         {078}           hi_room: {178}%5d\n\r",	pArea->low_r_vnum,		pArea->hi_r_vnum);
	ch_printf_color( ch, "{078}   low_obj: {178}%5d         {078}            hi_obj: {178}%5d\n\r",	pArea->low_o_vnum,		pArea->hi_o_vnum);
	ch_printf_color( ch, "{078}   low_mob: {178}%5d         {078}            hi_mob: {178}%5d\n\r",	pArea->low_m_vnum,		pArea->hi_m_vnum);
	ch_printf_color( ch, "{078}soft range: {178}%2d-%2d         {078}        hard range: {178}%2d-%2d\n\r",	pArea->low_soft_range,	pArea->hi_soft_range, pArea->low_hard_range, pArea->hi_hard_range);

	pop_call();
	return;
}

char *  const   bab_saves [] =
{
	"none",
	"poor",
	"good",
	"best",
	"poor",
	"good",
	"best",
	"epic",
	"*"
};	
	

/*
 * Display the specs for a character class - Kregor
 */
void do_showclass( CHAR_DATA *ch, char *argument)
{
	char buf[MAX_STRING_LENGTH];
	char name[MAX_INPUT_LENGTH];
	int cnt, sn, col;

	push_call("do_showclass(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		send_to_char("Syntax: showclass <name|all>\n\r", ch);
		pop_call();
		return;
	}
	if (!strcasecmp(argument, "all"))
	{
		strcpy(buf,"{200}Class list:\n\r");
		for (cnt = col = 0 ; cnt < MAX_CLASS ; cnt++)
		{
			sprintf(name, "%s (%s)", class_table[cnt].who_name_long, class_table[cnt].who_name);
			if (col && col % 3 == 0)
				strcat(buf, "\n\r");
			else if (col)
				strcat(buf, " ");
			cat_sprintf(buf, "{178}%2d{200}] {078}%-22s", cnt, name);
			col++;
		}
		if (col % 3 != 0)
			strcat(buf, "\n\r");
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}
	if ((cnt = lookup_class(argument)) != -1)
	{
		sprintf(buf,"{200}Class name:{178} %s (%s)\n\r", class_table[cnt].who_name_long, class_table[cnt].who_name);
		strcat(buf,"{200}Prime attr:{178} ");
		switch(class_table[cnt].attr_prime)
		{
			case APPLY_STR : strcat(buf,"STR");break;
			case APPLY_DEX : strcat(buf,"DEX");break;
			case APPLY_INT : strcat(buf,"INT");break;
			case APPLY_WIS : strcat(buf,"WIS");break;
			case APPLY_CON : strcat(buf,"CON");break;
			case APPLY_CHA : strcat(buf,"CHA");break;
			default : strcat(buf,"???)");break;
		}
		strcat(buf,"    ");
		cat_sprintf(buf, "{200}Hit die:{178} d%d    {200}Skill Points/Level:{178} %d    {200}Max Level:{178} %d\n\r", class_table[cnt].hp_max, class_table[cnt].skill_pts, class_table[cnt].max_level);
		strcat(buf,"{200}Second attr:{178} ");
		switch(class_table[cnt].attr_second)
		{
			case APPLY_STR : strcat(buf,"STR");break;
			case APPLY_DEX : strcat(buf,"DEX");break;
			case APPLY_INT : strcat(buf,"INT");break;
			case APPLY_WIS : strcat(buf,"WIS");break;
			case APPLY_CON : strcat(buf,"CON");break;
			case APPLY_CHA : strcat(buf,"CHA");break;
			default : strcat(buf,"???)");break;
		}
		strcat(buf,"    ");
		cat_sprintf(buf, "{200}BAB:{178}%5s    {200}FORT:{178}%5s    {200}REFL:{178}%5s    {200}WILL:{178}%5s\n\r",
			bab_saves[class_table[cnt].base_attack], bab_saves[class_table[cnt].fort_save], bab_saves[class_table[cnt].refl_save], bab_saves[class_table[cnt].will_save] );
		strcat(buf, "{200}Class Skills:\n\r");
		for (sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_SKILL)
				continue;
			if (skill_table[sn].skill_level[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, " {178}%-22s%2d ", skill_table[sn].name, skill_table[sn].skill_level[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
			}
		}
// 		if (col % 3 != 0)
// 			cat_sprintf(buf, "\n\r");
// 		strcat(buf, "{200}Trade Skills:\n\r");
		for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_CRAFT)
				continue;
			if (skill_table[sn].skill_level[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, " {178}%-22s%2d ", skill_table[sn].name, skill_table[sn].skill_level[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
			}
		}
// 		if (col % 3 != 0)
// 			cat_sprintf(buf, "\n\r");
// 		strcat(buf, "{200}Knowledge Skills:\n\r");
		for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_KNOWLEDGE)
				continue;
			if (skill_table[sn].skill_level[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, " {178}%-22s%2d ", skill_table[sn].name, skill_table[sn].skill_level[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");
		strcat(buf, "{200}Bonus Feats:\n\r");
		for (sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_FEAT)
				continue;
			if (skill_table[sn].bonus_feat[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, " {178}%-22s%2d ", skill_table[sn].name, skill_table[sn].bonus_feat[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");
		cat_sprintf(buf, "{200}Class Abilities:\n\r");
		for (sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_FEAT
			&& skill_table[sn].skilltype != FSKILL_ABILITY)
				continue;
			if (skill_table[sn].skill_level[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, " {178}%-22s%2d ", skill_table[sn].name, skill_table[sn].skill_level[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");
		cat_sprintf(buf, "{200}Weapons:\n\r");
		for (sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_WEAPON)
				continue;
			if (skill_table[sn].skill_level[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, " {178}%-22s%2d ", skill_table[sn].name, skill_table[sn].skill_level[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}
	ch_printf(ch, "%s is not a valid class.\n\r", argument);
	pop_call();
	return;
}


char *  const   feat_types [] =
{
	"Metamagic",
	"General",
	"Creation",
	"Combat",
	"Fighter",
	"Rogue",
	"Advanced",
	"Style",
	"Style",
	"Paladin",
	"Wizard",
	"*"
};


/*
 * Display the specs for a skill/feat/spell/ability
 * modified to list by speficied skill type, spells
 * can be filtered by school. Lists display class levels - Kregor
 */
void do_slookup( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH * 2];
	char dtype[MAX_INPUT_LENGTH];
	char sdesc[MAX_INPUT_LENGTH];
	char bld[10], dim[10], type[12];
	int sn, cnt, col, school;

	push_call("do_slookup(%p,%p)",ch,argument);

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

	strcpy(bld, ansi_translate_text(ch, "{178}"));
	strcpy(dim, ansi_translate_text(ch, "{078}"));

	if (!strcasecmp(argument, "all"))
	{
		for (buf[0] = '\0', sn = 0 ; sn < MAX_REAL_SKILL ; sn++)
		{
			if (!is_string(skill_table[sn].name))
				continue;

			switch (skill_table[sn].skilltype)
			{
				default:
					continue;
					break;
				case FSKILL_SKILL:
					sprintf(type, "Skill");
					break;
				case FSKILL_ABILITY:
					sprintf(type, "Ability");
					break;
				case FSKILL_CRAFT:
					sprintf(type, "Craft");
					break;
				case FSKILL_SPELL:
					sprintf(type, "Spell");
					break;
				case FSKILL_FEAT:
					sprintf(type, "Feat");
					break;
				case FSKILL_WEAPON:
					sprintf(type, "Weapon");
					break;
				case FSKILL_KNOWLEDGE:
					sprintf(type, "Knowledge");
					break;
				case FSKILL_RACEATTACK:
					sprintf(type, "Attack");
					break;
			}

			cat_sprintf(buf, "%sSn:%s %4d  %s%12s '%s%s%s'\n\r", dim, bld, sn, dim, type, bld, skill_table[sn].name, dim);
		}
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}

	if (strstr(argument, "spells"))
	{
		argument = one_argument(argument, buf);

		school = get_flag(argument, school_types);
			
		for (buf[0] = '\0', sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (!is_spell(sn))
				continue;
				
			if (school != -1 && skill_table[sn].spell_school != school)
				continue;

			cat_sprintf(buf, "%sSn:%s %3d %-20s%s %-15s ", dim, bld, sn, skill_table[sn].name, dim, school_types[skill_table[sn].spell_school]);
			for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
			{
				if (skill_table[sn].skill_level[cnt] < 75)
					cat_sprintf(buf, "%3s%d ", class_table[cnt].who_name, skill_table[sn].skill_level[cnt]);
			}
			strcat(buf, "\n\r");
			col++;
		}
		cat_sprintf(buf, "\n\r{200}%d spells total.\n\r", col);
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}

	if (strstr(argument, "feats"))
	{
		argument = one_argument(argument, buf);
		
		school = get_flag(argument, feat_types);

		for (buf[0] = '\0', sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_FEAT)
				continue;
				
			if (school != -1 && !IS_SET(skill_table[sn].spell_school, 1 << school))
				continue;

			cat_sprintf(buf, "%sSn:%s %3d %s%s [%-s]\n\r", dim, bld, sn, skill_table[sn].name, dim, flag_string(skill_table[sn].spell_school, feat_types));
			col++;
		}
		cat_sprintf(buf, "\n\r{200}%d feats total.\n\r", col);
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}

	if (strstr(argument, "skills"))
	{
		argument = one_argument(argument, buf);

		for (buf[0] = '\0', sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_SKILL
			&& skill_table[sn].skilltype != FSKILL_CRAFT
			&& skill_table[sn].skilltype != FSKILL_KNOWLEDGE)
				continue;
				
			if (skill_table[sn].skilltype == FSKILL_SKILL)
				cat_sprintf(buf, "%sSn:%s %3d %-20s%s ", dim, bld, sn, skill_table[sn].name, dim);
			else if (skill_table[sn].skilltype == FSKILL_KNOWLEDGE)
				cat_sprintf(buf, "%sSn:%s %3d %-20s%s ", dim, bld, sn, format("knowledge(%s)", skill_table[sn].name), dim);
			else if (skill_table[sn].skilltype == FSKILL_CRAFT)
				cat_sprintf(buf, "%sSn:%s %3d %-20s%s ", dim, bld, sn, format("trade(%s)", skill_table[sn].name), dim);
			for (cnt = 0 ; cnt < MAX_CLASS ; cnt++)
			{
				if (skill_table[sn].skill_level[cnt] < 75)
					cat_sprintf(buf, "%3s ", class_table[cnt].who_name);
			}
			strcat(buf, "\n\r");
			col++;
		}
		cat_sprintf(buf, "\n\r{200}%d skills total.\n\r", col);
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}

	if ((sn = skill_lookup(argument)) != -1)
	{
		switch (skill_table[sn].skilltype)
		{
			default:
				sprintf(type, "Skill");
				break;
			case FSKILL_ABILITY:
				sprintf(type, "Ability");
				break;
			case FSKILL_CRAFT:
				sprintf(type, "Craft");
				break;
			case FSKILL_SPELL:
				sprintf(type, "Spell");
				break;
			case FSKILL_KNOWLEDGE:
				sprintf(type, "Knowledge");
				break;
			case FSKILL_FEAT:
				sprintf(type, "Feat");
				break;
			case FSKILL_WEAPON:
				sprintf(type, "Weapon");
				break;
			case FSKILL_RACEATTACK:
				sprintf(type, "Attack");
				break;
		}
	
		sprintf(buf,		 "{078}Sn:{178} %3d   {078}%s: '{178}%s{078}'\n\r", sn, type, skill_table[sn].name);
	
		sprintf(dtype, "%s", skill_table[sn].dam_type == 0 ? "none" : flag_string(skill_table[sn].dam_type, dtype_flags));
		sprintf(sdesc, "%s", skill_table[sn].spell_desc == 0 ? "none" : flag_string(skill_table[sn].spell_desc, sdesc_flags));
		cat_sprintf(buf, "{078}DamType:{178} %-14s {078}Descs:{178} %s\n\r", dtype, sdesc);
		cat_sprintf(buf, "{078}Flags:{178} %s\n\r", flag_string(skill_table[sn].flags, spell_flags));
	
		switch (skill_table[sn].skilltype)
		{
			default:
				break;
			case FSKILL_ABILITY:
				break;
			case FSKILL_CRAFT:
				strcat(buf, "{078}Components:{178}");
				for (col = cnt = 0 ; cnt < 5 ; cnt++)
				{
					if (skill_table[sn].components[cnt] == 0)
						continue;
					cat_sprintf(buf, " %s", component_flags[skill_table[sn].components[cnt]]);
					col++;
				}
				if (!col)
				strcat(buf, " None");
				strcat(buf, "\n\r");
				break;
			case FSKILL_SPELL:
				cat_sprintf(buf, "{078}School:{178} %-13s   {078}Target:{178} %-13s   {078}Save:{178} %-13s\n\r",
					school_types[skill_table[sn].spell_school], target_types[skill_table[sn].target], save_flags[skill_table[sn].save]);
				strcat(buf, "{078}Components:{178}");
				for (col = cnt = 0 ; cnt < 5 ; cnt++)
				{
					if (skill_table[sn].components[cnt] == 0)
						continue;
					cat_sprintf(buf, " %s", component_flags[skill_table[sn].components[cnt]]);
					col++;
				}
				if (!col)
				strcat(buf, " None");
				strcat(buf, "\n\r");
				break;
			case FSKILL_KNOWLEDGE:
				break;
			case FSKILL_FEAT:
				break;
			case FSKILL_WEAPON:
				break;
			case FSKILL_RACEATTACK:
				break;
		}
		cat_sprintf(buf, "{200}Classes:\n\r");
		for (col = cnt = 0 ; cnt < MAX_CLASS ; cnt++)
		{
			if (skill_table[sn].skill_level[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, "{078}  %-21s {178}%d", class_table[cnt].who_name_long, skill_table[sn].skill_level[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
				else
					cat_sprintf(buf, " ");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");
		cat_sprintf(buf, "{200}Bonus Feats:\n\r");
		for (col = cnt = 0 ; cnt < MAX_CLASS ; cnt++)
		{
			if (skill_table[sn].skilltype != FSKILL_FEAT)
				continue;
			if (skill_table[sn].bonus_feat[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, "{078}  %-21s {178}%d", class_table[cnt].who_name_long, skill_table[sn].bonus_feat[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
				else
					cat_sprintf(buf, " ");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");
		cat_sprintf(buf, "{200}Domains:\n\r");
		for (col = cnt = 0 ; cnt < MAX_DOMAIN ; cnt++)
		{
			if (skill_table[sn].domains[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, "{078}  %-21s {178}%d", domain_types[cnt], skill_table[sn].domains[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
				else
					cat_sprintf(buf, " ");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");
		cat_sprintf(buf, "{200}Styles:\n\r");
		for (col = cnt = 0 ; cnt < STYLE_MAX ; cnt++)
		{
			if (skill_table[sn].styles[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, "{078}  %-21s {178}%d", combat_styles[cnt], skill_table[sn].styles[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
				else
					cat_sprintf(buf, " ");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");
		cat_sprintf(buf, "{200}Bloodlines:\n\r");
		for (col = cnt = 0 ; cnt < BLOODLINE_MAX ; cnt++)
		{
			if (skill_table[sn].bloodline[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, "{078}  %-21s {178}%d", bloodline_types[cnt], skill_table[sn].bloodline[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
				else
					cat_sprintf(buf, " ");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");
		cat_sprintf(buf, "{200}Races:\n\r");
		for (col = cnt = 0 ; cnt < MAX_RACE ; cnt++)
		{
			if (skill_table[sn].race_skill[cnt] && skill_table[sn].race_skill[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, "{078}  %-21s {178}%d", race_table[cnt].race_name, skill_table[sn].race_skill[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
				else
					cat_sprintf(buf, " ");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");
	
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}
	send_to_char("No such skill or spell.\n\r", ch);
	pop_call();
	return;
}


/*
 * list mprog commands - Kregor
 */
void do_mpcommands(CHAR_DATA *ch, char *argument)
{
	char buf[MAX_STRING_LENGTH];
	int cmd, col, level;

	push_call("do_mpcommands(%p,%p)",ch,argument);

	for (level = LEVEL_IMMORTAL, col = 0, buf[0] = '\0' ; level <= MAX_LEVEL ; level++)
	{
		for (cmd = 0 ; cmd_table[cmd].name[0] != '\0'; cmd++)
		{
			if (cmd_table[cmd].level == level
			&& !str_infix("mp", cmd_table[cmd].name)
			&& IS_SET(cmd_table[cmd].flags, CMD_HIDE))
			{
				if (col %5 == 0)
				{
					strcat(buf, get_color_string(ch, COLOR_TEXT, VT102_DIM));
				}
				cat_sprintf(buf, "%d-%-13s", cmd_table[cmd].level, cmd_table[cmd].name);
				if (++col % 5 == 0)
				{
					strcat(buf, "\n\r");
				}
			}
		}
	}
	if (col % 5 != 0)
	{
		strcat(buf, "\n\r");
	}
	send_to_char(buf, ch);
	pop_call();
	return;
}


/*
 * Where is a specified object? - Kregor
 */
void do_owhere( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_INPUT_LENGTH];
	char buf1[MAX_INPUT_LENGTH];
	char buf2[MAX_INPUT_LENGTH];
	char buf3[MAX_INPUT_LENGTH];
	char bold[10], dim[10], objc[10], mobc[10];
	OBJ_DATA *obj;
	OBJ_DATA *in_obj;
	bool found, basic;
	int count,item_vnum;
	int total, total_room, total_npc, total_pc, total_cont, total_progs, total_non_basic;
	int total_pc_cont, total_npc_cont, total_null;

	push_call("do_owhere(%p,%p)",ch,argument);

	strcpy(dim,   get_color_string(ch, COLOR_PROMPT,  VT102_DIM ));
	strcpy(bold,  get_color_string(ch, COLOR_PROMPT,  VT102_BOLD));
	strcpy(objc,  get_color_string(ch, COLOR_OBJECTS, VT102_BOLD));
	strcpy(mobc,  get_color_string(ch, COLOR_MOBILES, VT102_DIM ));

	if (*argument == '\0')
	{
		if (IS_GOD(ch))
		{
			send_to_char("Syntax: owhere <basic|total|objVnum|objName>\n\r", ch);
		}
		else
		{
			send_to_char("Syntax: owhere <objVnum|objName>\n\r", ch);
		}
		pop_call();
		return;
	}

	basic = !strcasecmp(argument, "basic");

	if (!strcasecmp(argument, "total"))
	{
		total			= 0;
		total_room		= 0;
		total_npc			= 0;
		total_pc			= 0;
		total_cont		= 0;
		total_pc_cont		= 0;
		total_npc_cont		= 0;
		total_progs		= 0;
		total_null		= 0;
		total_non_basic	= 0;

		for (obj = mud->f_obj ; obj ; obj = obj->next)
		{
			total++;
			if (IS_SET(obj->extra_flags, ITEM_MODIFIED))
			{
				total_non_basic++;
			}
			if (obj->in_obj != NULL)
			{
				if (obj->in_obj->carried_by != NULL)
				{
					if (IS_NPC(obj->in_obj->carried_by))
					{
						total_npc_cont++;
					}
					else
					{
						total_pc_cont++;
					}
				}
				else
				{
					total_cont++;
				}
			}
			else if (obj->in_room != NULL)
			{
				total_room++;
			}
			else
			{
				if (obj->carried_by != NULL)
				{
					if (!IS_NPC(obj->carried_by))
					{
						total_pc++;
						if (obj->pIndexData->first_prog != NULL)
						{
							total_progs++;
						}
					}
					else
					{
						total_npc++;
					}
				}
				else
				{
					total_null++;
				}
			}
		}
		ch_printf_color(ch, "\n\r");
		ch_printf_color(ch, "   %s  Totalized list of objects                  \n\r", dim );
		ch_printf_color(ch, "   %s+----------------------------------+--------+\n\r", bold);
		ch_printf_color(ch, "   %s| %sObjects carried by players       %s| %s%6d %s|\n\r", bold, dim, bold, dim, total_pc,       bold);
		ch_printf_color(ch, "   %s| %sObjects carried by mobs          %s| %s%6d %s|\n\r", bold, dim, bold, dim, total_npc,      bold);
		ch_printf_color(ch, "   %s| %sObjects in containers in room    %s| %s%6d %s|\n\r", bold, dim, bold, dim, total_cont,     bold);
		ch_printf_color(ch, "   %s| %sObjects in containers on players %s| %s%6d %s|\n\r", bold, dim, bold, dim, total_pc_cont,  bold);
		ch_printf_color(ch, "   %s| %sObjects in containers on mobs    %s| %s%6d %s|\n\r", bold, dim, bold, dim, total_npc_cont, bold);
		ch_printf_color(ch, "   %s| %sObjects in rooms                 %s| %s%6d %s|\n\r", bold, dim, bold, dim, total_room,     bold);
		ch_printf_color(ch, "   %s| %sObjects with active obj programs %s| %s%6d %s|\n\r", bold, dim, bold, dim, total_progs,    bold);
		ch_printf_color(ch, "   %s| %sObjects in NULL                  %s| %s%6d %s|\n\r", bold, dim, bold, dim, total_null,     bold);
		ch_printf_color(ch, "   %s| %sTotal Non Basic Objects          %s| %s%6d %s|\n\r", bold, dim, bold, dim, total_non_basic,bold);
		ch_printf_color(ch, "   %s| %sTotal Objects                    %s| %s%6d %s|\n\r", bold, dim, bold, dim, total,          bold);
		ch_printf_color(ch, "   %s+----------------------------------+--------+\n\r", bold);

		pop_call();
		return;
	}

	found = FALSE;
	count = 0;

	item_vnum = is_number(argument) ? atol(argument) : -1;

	for (obj = mud->f_obj ; obj && count < 100 ; obj = obj->next)
	{
		if (item_vnum != obj->pIndexData->vnum
		&& !is_name_short(argument, obj->name)
		&& !basic)
		{
			continue;
		}

		if (!can_olc_modify(ch, obj->pIndexData->vnum))
		{
			continue;
		}

		if (basic && !IS_SET(obj->extra_flags, ITEM_MODIFIED))
		{
			continue;
		}
		found = TRUE;
		count++;

		for (in_obj = obj ; in_obj->in_obj != NULL && in_obj->in_obj != in_obj; in_obj = in_obj->in_obj)
		{
			;
		}
		sprintf (buf1, "%s[%s%5u%s]%s %s",
			bold, dim,  obj->pIndexData->vnum,
			bold, objc, str_resize(obj->short_descr, buf, -21));

		if (in_obj->carried_by != NULL)
		{
			sprintf (buf2, "%s[%s%5u%s]%s %s",
				bold, dim, in_obj->carried_by->in_room->vnum,
				bold, dim, str_resize(in_obj->carried_by->in_room->name, buf, -16));

			sprintf (buf3, "%s[%s%5u%s]%s %s",
				bold, dim,  IS_NPC(in_obj->carried_by) ? in_obj->carried_by->pIndexData->vnum                  : in_obj->carried_by->pcdata->pvnum,
				bold, mobc, IS_NPC(in_obj->carried_by) ? str_resize(in_obj->carried_by->short_descr, buf, -16) : in_obj->carried_by->name);
		}
		else if (in_obj->in_room == NULL)
		{
			sprintf (buf2, "%s[%s%5u%s]%s %s",
				bold, dim, -1,
				bold, dim, "NULL");

			buf3[0] = '\0';
		}
		else
		{
			sprintf (buf2, "%s[%s%5u%s]%s %s",
				bold, dim, in_obj->in_room->vnum,
				bold, dim, str_resize(in_obj->in_room->name, buf, -16));

			if (in_obj == obj)
			{
				buf3[0] = '\0';
			}
			else if (in_obj == NULL)
			{
				sprintf (buf3, "%s[%s%5d%s]%s %s",
					bold, dim, -1,
					bold, objc, "NULL");
			}
			else
			{
				sprintf (buf3, "%s[%s%5u%s]%s %s",
					bold, dim, in_obj->pIndexData->vnum,
					bold, objc, str_resize(in_obj->short_descr, buf, -16));
			}
		}
		sprintf(buf, "%s %s %s\n\r", buf1, buf2, buf3);
		send_to_char( buf, ch );
	}

	if ( !found )
	{
		send_to_char( "Nothing like that in hell, heaven or earth.\n\r", ch );
	}
	pop_call();
	return;
}


/*
 * Where is a specified character? - Kregor
 */
void do_mwhere( CHAR_DATA *ch, char *argument )
{
	char buf1[MAX_INPUT_LENGTH];
	char buf2[MAX_INPUT_LENGTH];
	char bold[10], dim[10], mobc[10];
	CHAR_DATA *victim;
	int count, mob_vnum;

	push_call("do_mwhere(%p,%p)",ch,argument);

	strcpy(dim,   get_color_string(ch, COLOR_PROMPT,  VT102_DIM ));
	strcpy(bold,  get_color_string(ch, COLOR_PROMPT,  VT102_BOLD));
	strcpy(mobc,  get_color_string(ch, COLOR_MOBILES, VT102_DIM ));

	count = 0;

	if (argument[0] == '\0')
	{
		send_to_char( "Syntax: mwhere <mobVnum|mobName>\n\r", ch );
		pop_call();
		return;
	}

	mob_vnum = atol(argument);

	for (victim = mud->f_char ; count < 100 && victim ; victim = victim->next)
	{
		if (IS_NPC(victim) && can_olc_modify(ch, victim->pIndexData->vnum))
		{
			if (mob_vnum)
			{
				if (victim->pIndexData->vnum != mob_vnum)
				{
					continue;
				}
			}
			else
			{
				if (!is_multi_name_list_short(argument, victim->name))
				{
					continue;
				}
			}
			count++;
			ch_printf_color(ch, "%s[%s%5u%s] %s%s %s[%s%5u%s] %s%s\n\r",
				bold,  dim, victim->pIndexData->vnum,
				bold, mobc, str_resize(victim->short_descr, buf1, -31),
				bold,  dim, victim->in_room->vnum,
				bold,  dim, str_resize(victim->in_room->name, buf2, -31));
		}
	}

	if (count == 0)
	{
		if (mob_vnum == 0)
		{
			act( "You didn't find any $T.", ch, NULL, argument, TO_CHAR);
		}
		else
		{
			act( "No mob loaded with vnum $T.", ch, NULL, argument, TO_CHAR);
		}
	}
	pop_call();
	return;
}


/*
 * List all areas - Kregor
 */
void do_alist( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	AREA_DATA *pArea;
	int vnum;

	push_call("do_alist(%p,%p)",ch,argument);

	if (IS_NPC(ch) || !IS_GOD(ch))
	{
		ch_printf_color(ch, "Sorry, Gods only.\n\r");
		pop_call();
		return;
	}

	strcpy(buf, "{088}");

	for (pArea = NULL, vnum = 1 ; vnum < MAX_VNUM ; vnum++)
	{
		if (room_index[vnum] && room_index[vnum]->area != pArea)
		{
			pArea = room_index[vnum]->area;
		}
		else if (mob_index[vnum] && mob_index[vnum]->area != pArea)
		{
			pArea = mob_index[vnum]->area;
		}
		else if (obj_index[vnum] && obj_index[vnum]->area != pArea)
		{
			pArea = obj_index[vnum]->area;
		}
		else
		{
			continue;
		}
		cat_sprintf(buf, "{828} [{878}%5u {828}- {878}%5u{828}] {878}%-30s %-25s\n\r",
			UMIN(pArea->low_r_vnum, UMIN(pArea->low_m_vnum, pArea->low_o_vnum)),
			UMAX(pArea->hi_r_vnum,  UMAX(pArea->hi_m_vnum,  pArea->hi_o_vnum)),
			pArea->filename,
			pArea->name);
	}
	send_to_char_color(buf, ch);
	pop_call();
	return;
}


typedef struct	user_list_data		USER_LIST_DATA;

struct user_list_data
{
	USER_LIST_DATA  * next;
	USER_LIST_DATA  * prev;
	DESCRIPTOR_DATA * desc;
};

/*
	This routine Returns which host is greatest by IP numbers for sorting
	Chaos - 3/19/96
*/
int hostcmp( DESCRIPTOR_DATA *d1, DESCRIPTOR_DATA *d2 )
{
	int cnt;

	push_call("hostcmp(%p,%p)",d1,d2);

	if (d1->host == NULL || d2->host == NULL)
	{
		pop_call();
		return 0;
	}

	for (cnt = 0 ; d1->host[cnt] != '\0' ; cnt++)
	{
		if (d1->host[cnt] < d2->host[cnt])
		{
			pop_call();
			return -1;
		}
		if (d1->host[cnt] > d2->host[cnt])
		{
			pop_call();
			return 1;
		}
	}
	pop_call();
	return 0;
}


int count_connects( DESCRIPTOR_DATA *d)
{
	DESCRIPTOR_DATA *dtemp;
	int cnt = 0;

	push_call("count_connects(%p)",d);

	for (dtemp = mud->f_desc ; dtemp ; dtemp = dtemp->next)
	{
		if (d->host && dtemp->host && !strcmp(d->host, dtemp->host))
		{
			cnt++;
		}
	}
	pop_call();
	return cnt;
}


void do_cpu( CHAR_DATA *ch, char *arg)
{
	lg_int tot_cpu;
	int tim;

	push_call("do_cpu(%p,%p)",ch,arg);

	send_to_char("Section                           Time (usec)    Freq (msec)  %Prog         %CPU\n\r" , ch );

	for (tot_cpu = tim = 0 ; tim < TIMER_MAXTIMER ; tim++)
	{
		tot_cpu += display_timer(ch, tim);
	}

	ch_printf_color(ch, "\n\rAverage IO bandwidth:       %10lld MB per month\n\r", mud->total_io_bytes * PULSE_PER_SECOND * 60 * 60 * 24 * 30 / 1000000 / UMAX(1, mud->total_io_ticks));
	ch_printf_color(ch, "Unknown CPU Usage:              %6.2f percent\n\r", (mud->total_io_exec - tot_cpu) * 100.0 / (mud->total_io_delay + mud->total_io_exec));
	ch_printf_color(ch, "Average CPU Usage:              %6.2f percent\n\r",  mud->total_io_exec            * 100.0 / (mud->total_io_delay + mud->total_io_exec));

	pop_call();
	return;
}

void do_usage( CHAR_DATA *ch, char *argument )
{
	PLAYER_GAME *fpl;
	char buf[MAX_STRING_LENGTH];
	bool weekly, average;
	int day, hour, topPlayers, topVal, curVal, val, nPlayer, ave_plr[24];

	push_call("do_usage(%p,%p)",ch,argument);

	weekly  = (argument[0] != '\0' && !str_prefix(argument, "weekly"));
	average = (argument[0] != '\0' && !str_prefix(argument, "average"));

	topPlayers = topVal = nPlayer = 0;

	for (fpl = mud->f_player ; fpl ; fpl = fpl->next)
	{
		if (!can_see_world(ch, fpl->ch))
		{
			continue;
		}
		nPlayer++;
	}

	if (weekly)
	{
		long nPlayers[7];

		for (day = 0 ; day < 7 ; day++)
		{
			nPlayers[day] = 0;
			for (hour = 0 ; hour < 24 ; hour++)
			{
				nPlayers[day] += mud->usage->players[hour][day];
			}
			nPlayers[day] /= 24;

			topPlayers = UMAX(topPlayers, nPlayers[day]);
			topVal     = UMAX(topVal, topPlayers);
		}
		topVal = UMAX(topVal, 10);

		for (buf[0] = '\0', val = 0 ; val < 10 ; val++)
		{
			curVal = topVal - val * (float)((float)topVal/(float)10.0);
			cat_sprintf(buf, "{128}%4d{878}:{838}", curVal);

			for (day = 0 ; day < 7 ; day++)
			{
				if (nPlayers[day] >= curVal)
				{
					if (day == mud->time.tm_wday)
					{
						strcat(buf, "{818}|-| {838}");
					}
					else
					{
						strcat(buf, "|-| ");
					}
				}
				else
				{
					strcat(buf, "    ");
				}
			}
			strcat(buf, "\n\r");
		}
		strcat(buf, "{878}    +---+---+---+---+---+---+---+\n\r{828}     Sun Mon Tue Wed Thu Fri Sat\n\r");
		send_to_char_color(buf, ch);
	}
	else if (average)
	{
		memset(ave_plr, 0, 24 * sizeof(int));

		for (hour = 0 ; hour < 24 ; hour++)
		{
			for (day = 0 ; day < 7 ; day++)
			{
				ave_plr[hour] += mud->usage->players[hour][day];
			}
		}

		for (hour = 0 ; hour < 24 ; hour++)
		{
			ave_plr[hour] /= 7;

			if (topPlayers < ave_plr[hour])
			{
				topPlayers = ave_plr[hour];
			}
		}
		topVal = UMAX(topVal, topPlayers);
		topVal = UMAX(topVal, 10);

		for (buf[0] = '\0', val = 0 ; val < 10 ; val++)
		{
			curVal = topVal - val * (float) ((float)topVal/(float)10.0);
			cat_sprintf(buf, "{128}%4d{878}:{838}", curVal);

			for (hour = 0 ; hour < 24 ; hour++)
			{
				if (hour == mud->time.tm_hour)
				{
					if (ave_plr[hour] >= curVal)
					{
						strcat(buf, "{818}|| {838}");
					}
					else
					{
						strcat(buf, "   ");
					}
				}
				else
				{
					if (ave_plr[hour] >= curVal)
					{
						strcat(buf, "|| ");
					}
					else
					{
						strcat(buf, "   ");
					}
				}
			}
			strcat(buf, "\n\r");
		}
		strcat(buf, "{878}    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\n\r{128}     00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n\r");
		send_to_char_color(buf, ch);
	}
	else
	{
		day = mud->time.tm_wday;

		if (argument[0] && argument[1] && argument[2])
		{
			switch (argument[0]+argument[1]+argument[2])
			{
				case ('s'+'u'+'n'): day = 0; break;
				case ('m'+'o'+'n'): day = 1; break;
				case ('t'+'u'+'e'): day = 2; break;
				case ('w'+'e'+'d'): day = 3; break;
				case ('t'+'h'+'u'): day = 4; break;
				case ('f'+'r'+'i'): day = 5; break;
				case ('s'+'a'+'t'): day = 6; break;
			}
		}

		for (hour = 0 ; hour < 24 ; hour++)
		{
			if (hour == mud->time.tm_hour && day == mud->time.tm_wday)
			{
				if (topPlayers < nPlayer)
				{
					topPlayers = nPlayer;
				}
			}
			else if (topPlayers < mud->usage->players[hour][day])
			{
				topPlayers = mud->usage->players[hour][day];
			}
		}
		topVal = UMAX(topVal, topPlayers);
		topVal = UMAX(topVal, 10);

		for (buf[0] = '\0', val = 0 ; val < 10 ; val++)
		{
			curVal = topVal - val * (float) ((float)topVal/(float)10.0);
			cat_sprintf(buf, "{128}%4d{878}:{838}", curVal);

			for (hour = 0 ; hour < 24 ; hour++)
			{
				if (hour == mud->time.tm_hour && day == mud->time.tm_wday)
				{
					if (nPlayer >= curVal)
					{
						strcat(buf, "{818}|| {838}");
					}
					else
					{
						strcat(buf, "   ");
					}
				}
				else
				{
					if (mud->usage->players[hour][day] >= curVal)
					{
						strcat(buf, "|| ");
					}
					else
					{
						strcat(buf, "   ");
					}
				}
			}
			strcat(buf, "\n\r");
		}
		strcat(buf, "{878}    +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+\n\r{128}     00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23\n\r");
		send_to_char_color(buf, ch);
	}
	pop_call();
	return;
}


void do_users( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	DESCRIPTOR_DATA *d;
	int count, val;

	push_call("do_users(%p,%p)",ch,argument);

	/*
		The complete descriptor list
	*/
	for (count = 0 ; count < MAX_LINKPERPORT + 20 ; count++)
	{
		sprintf(buf, "%3d ", count);

		if (getsockopt(count, SOL_SOCKET, SO_SNDBUF, (char *) &val, (unsigned int *) &val) < 0)
		{
			cat_sprintf(buf, "SN NA    ");
		}
		else
		{
			cat_sprintf(buf, "SN %-5d ", val);
		}

		if (getsockopt(count, SOL_SOCKET, SO_RCVBUF, (char *) &val, (unsigned int *) &val) < 0)
		{
			cat_sprintf(buf, "RC NA   ");
		}
		else
		{
			cat_sprintf(buf, "RC %-4d ", val);
		}

		if (getsockopt(count, SOL_SOCKET, SO_REUSEADDR, (char *) &val, (unsigned int *) &val) < 0)
		{
			cat_sprintf(buf, "RU N ");
		}
		else
		{
			cat_sprintf(buf, "RU %-1d ", val);
		}

	/*
		if (getsockopt(count, SOL_SOCKET, SO_DEBUG, (char *) &val, (unsigned int *) &val) < 0)
		{
			cat_sprintf(buf, "DE N ");
		}
		else
		{
			cat_sprintf(buf, "DE %-1d ", val);
		}
	*/

		if (getsockopt(count, SOL_SOCKET, SO_KEEPALIVE, (char *) &val, (unsigned int *) &val) < 0)
		{
			cat_sprintf(buf, "KE N ");
		}
		else
		{
			cat_sprintf(buf, "KE %-1d ", val);
		}

		if (getsockopt(count, SOL_SOCKET, SO_LINGER, (char *) &val, (unsigned int *) &val) < 0)
		{
			cat_sprintf(buf, "LG N ");
		}
		else
		{
			cat_sprintf(buf, "LG %-1d ", val);
		}

		if (getsockopt(count, SOL_SOCKET, SO_TYPE, (char *) &val, (unsigned int *) &val) < 0)
		{
			cat_sprintf(buf, "TY N ");
		}
		else
		{
			cat_sprintf(buf, "TY %-1d ", val);
		}

		cat_sprintf(buf, "OWN %-2d FLG %-5x ", fcntl(count, F_GETOWN), fcntl(count, F_GETFL) >= 0 ? fcntl(count, F_GETFL) : 0);

		for (d = mud->f_desc ; d ; d = d->next)
		{
			if (d->character && is_desc_valid(d->character))
			{
				if (d->descriptor == count)
				{
					cat_sprintf(buf, "%-3d %s", d->connected, d->character->name);
					break;
				}
			}
		}
		ch_printf_color(ch, "%s\n\r", buf);
	}
	pop_call();
	return;
}


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

	push_call("do_roomfragment(%p,%p)",ch,argument);

	strcpy( buf, "Room Fragmentation chart:\n\r");
	strcat( buf, "    0 1 2 3 4 5 6 7 8 9\n\r" );
	for (cnt = 0 ; cnt < MAX_VNUM/100 ; cnt++)
	{
		if (cnt % 10 == 0)
		{
			cat_sprintf(buf, "%2d  ",cnt/10);
		}
		if (room_index[cnt*100+1] != NULL)
		{
			strcat(buf, "X ");
		}
		else
		{
			strcat(buf, "  ");
		}
		if (cnt % 10 == 9)
		{
			strcat(buf, "\n\r");
		}
	}
	send_to_char(buf, ch);
	pop_call();
	return;
}


void do_termlist (CHAR_DATA * ch, char *arg)
{
	PLAYER_GAME *gpl;
	char buf[MAX_STRING_LENGTH];

	push_call("do_termlist(%p,%p)",ch,arg);

	for (buf[0] = '\0', gpl = mud->f_player ; gpl ; gpl = gpl->next)
	{
		cat_sprintf(buf, "{078}%15s {188}[{078}%2d{188}] [{078}%3d{188}] ", gpl->ch->name, gpl->ch->pcdata->vt100_type % 100, gpl->ch->pcdata->vt100_type / 100);

		cat_sprintf(buf, "{078}%s  %s  ", gpl->ch->pcdata->vt100 ? "VT102" : "VT100", gpl->ch->pcdata->ansi ? "ANSI" : "MONO");

		if (gpl->ch->desc && gpl->ch->desc->mccp)
		{
			cat_sprintf(buf, "MCCP %4.1f%%", 100 - 100.0 * gpl->ch->desc->mccp->total_out / UMAX(1, gpl->ch->desc->mccp->total_in));
		}
		else
		{
			cat_sprintf(buf, "          ");
		}
		cat_sprintf(buf, "%4d  %s\n\r", gpl->ch->pcdata->idle, gpl->ch->desc ? gpl->ch->desc->terminal_type : "");
	}
	send_to_char_color(buf, ch);
	pop_call();
	return;
}


void do_file( CHAR_DATA *ch, char *argument)
{
	CHAR_DATA  *victim;
	CRIME_DATA *record;
	char buf[MAX_STRING_LENGTH];
	char arg1[MAX_INPUT_LENGTH], arg2[MAX_INPUT_LENGTH];
	char colG[10], colY[10], colC[10], colW[10];
	int number, cnt;
	bool loaded;

	push_call("do_file(%p,%p)",ch,argument);

	strcpy(colG, ansi_translate_text(ch, "{128}"));
	strcpy(colY, ansi_translate_text(ch, "{138}"));
	strcpy(colC, ansi_translate_text(ch, "{168}"));
	strcpy(colW, ansi_translate_text(ch, "{178}"));

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

	if (arg1[0] == '\0')
	{
		send_to_char("Usage : file <victim> [<record #>]\n\r", ch);
		pop_call();
		return;
	}

	if ((victim = lookup_char(arg1)) == NULL)
	{
		if ((victim = start_partial_load(ch, arg1)) == NULL)
		{
			pop_call();
			return;
		}
		loaded = TRUE;
	}
	else
	{
		loaded = FALSE;
	}

	if (arg2[0] != '\0')
	{
		number = atoi(arg2);
	}
	else
	{
		number = -1;
	}

	if (victim->pcdata->first_record == NULL)
	{
		ch_printf_color(ch, "%s has no criminal record.\n\r", victim->name);
		if (loaded)
		{
			clear_partial_load(victim);
		}
		pop_call();
		return;
	}

	for (cnt = 0, buf[0] = '\0', record = victim->pcdata->first_record ; record ; record = record->next)
	{
		if (number == -1 || ++cnt == number)
		{
			cat_sprintf(buf, "%s%s %shas been arrested on %s%s %sby %s%s%s.\n\r", colY, victim->name, colW, colG, get_time_string(record->date), colW, colY, record->arrester, colW);

			cat_sprintf(buf, "%s%s %shas been imprisoned for %s%d %sdays, %s%d %shours and %s%d %sminutes.\n\r",
				colY, victim->name, colW,
				colG, record->jailtime / 86400, colW,
				colG, record->jailtime % 86400 / 3600, colW,
				colG, record->jailtime % 86400 % 3600 / 60, colW);

			if (record->released == TRUE)
			{
				cat_sprintf(buf, "%s%s %shas been released from this punishment by %s%s%s.\n\r",
					colY, victim->name, colW,
					colY, record->releaser, colW);
			}
			else
			{
				int time_left = victim->pcdata->jailtime - (mud->current_time - victim->pcdata->jaildate);
				if (time_left > 0)
				{
					cat_sprintf(buf, "%s%s %swill be autoreleased in %s%d %sdays, %s%d %shours and %s%d %sminutes.\n\r",
						colY, victim->name, colW,
						colG, time_left / 86400, colW,
						colG, time_left % 86400 / 3600, colW,
						colG, time_left % 86400 % 3600 / 60, colW);
				}
				else
				{
					cat_sprintf(buf, "%s%s %sis waiting to be auto released by the system.\n\r",
						colY, victim->name, colW);
				}
			}
			cat_sprintf(buf, "%sFile information:%s\n\r%s\n\r",
				colC, colW, record->crime_record);
		}
	}

	if (number != -1 && number > cnt)
	{
		sprintf(buf, "%s hasn't committed that many crimes.\n\r", victim->name);
	}
	send_to_char(buf, ch);

	if (loaded)
	{
		clear_partial_load(victim);
	}
	pop_call();
	return;
}


/*
 * Display XP progression for all levels - Kregor
 */
void do_showcurve(CHAR_DATA *ch, char *argument)
{
	int cnt, i, req_exp, dif_exp, prev_exp;
	char buf[MAX_STRING_LENGTH];

	push_call("do_showcurve(%p,%p)",ch,argument);

	cnt = i = req_exp = dif_exp = prev_exp = 0;

	if (argument[0] == '\0')
	{
		for (buf[0] = '\0',i = 1 ; i <= LEVEL_HERO ; i++)
		{
			req_exp	= exp_level(ch, i);
			dif_exp	= req_exp - prev_exp;
			prev_exp	= req_exp;
			cat_sprintf(buf, "{078}Level {138}%2d{178}: {078}%12d {138}- {078}%12d exp\n\r", i, req_exp, dif_exp);
		}
		send_to_char_color(buf, ch);

		pop_call();
		return;
	}

	if (!strcasecmp(argument, "mon"))
	{
		for (i = 1 ; i <= 300 ; i++)
		{
			req_exp	= exp_level(ch, i);
			dif_exp	= req_exp - prev_exp;
			prev_exp	= req_exp;
			cat_sprintf(buf, "{078}Level {138}%3d{178}: {078}%12d {138}- {078}%12d exp\n\r", i, req_exp, dif_exp);
		}
		send_to_char_color(buf, ch);

		pop_call();
		return;
	}
	pop_call();
	return;
}


/*
 * Locate a specified player - Kregor
 */
void do_where( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	PLAYER_GAME *fpl;

	push_call("do_where(%p,%p)",ch,argument);

	one_argument( argument, arg );

	if (!strcasecmp(arg, "all"))
	{
		strcpy(buf, "{178} Player               Area                     Leader        Address\n\r");
		strcat(buf, "{078}--------------------+------------------------+-------------+--------------------\n\r");

		for (fpl = mud->f_player ; fpl ; fpl = fpl->next)
		{
			victim = fpl->ch;

			if (!can_see_world(ch, victim))
			{
				continue;
			}

			if (!can_hear(ch, victim))
			{
				continue;
			}

			cat_sprintf(buf, "{200} %-19s{078}|", victim->name);

			cat_snprintf(buf, 30, "{200} %-29s{078}|", victim->in_room->area->name);

			if (victim->leader != NULL && is_same_group(victim, victim->leader) && victim != victim->leader)
			{
				cat_snprintf(buf, 20, "{078} %-20s\n\r", victim->leader->name);
			}
			else
			{
				cat_snprintf(buf, 20, "{078} %-20s\n\r", "-");
			}

			if (victim->desc)
			{
				cat_sprintf(buf, "{200}%s\n\r", get_domain(victim->desc->host));
			}
			else
			{
				cat_sprintf(buf, "{200}-\n\r");
			}
		}

		if (strlen(buf) < 190)
		{
			strcat(buf, "{178} None\n\r");
		}
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}

	if (arg[0] == '\0')
	{
		strcpy(buf, "{178} Player        Area                Location                      Leader\n\r");
		strcat(buf, "{078}-------------+-------------------+-----------------------------+----------------\n\r");

		for (fpl = mud->f_player ; fpl ; fpl = fpl->next)
		{
			victim = fpl->ch;

			if (!can_see_world(ch, victim))
			{
				continue;
			}

			if (!can_hear(ch, victim))
			{
				continue;
			}

			if (victim->in_room->area != ch->in_room->area)
			{
				continue;
			}

			if (findpath_search_victim(ch, victim, 11) == -1)
			{
				continue;
			}

			cat_sprintf(buf, "{178} %-12s{078}|", victim->name);

			cat_snprintf(buf, 25, "{200} %-24s{078}|", victim->in_room->area->name);
			cat_snprintf(buf, 35, "{200} %-34s{078}|", victim->in_room->name);

			if (victim->leader != NULL && is_same_group(victim, victim->leader) && victim != victim->leader)
			{
				cat_sprintf(buf, "{200} %s\n\r", victim->leader->name);
			}
			else
			{
				cat_sprintf(buf, "{200} -\n\r");
			}
		}

		if (strlen(buf) < 190)
		{
			strcat(buf, "{178} None\n\r");
		}
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}

	victim = findpath_search_name(ch, arg, 11);

	if (victim == NULL)
	{
		ch_printf_color(ch, "You didn't find '%s'.\n\r", arg);
		pop_call();
		return;
	}

	sprintf(buf, "%s\n\r", capitalize(get_name(victim)));
	cat_sprintf(buf, "%s\n\r", victim->in_room->area->name);
	cat_sprintf(buf, "%s\n\r", victim->in_room->name);

	send_to_char(buf, ch);
	pop_call();
	return;
}


/* Check the add helpfile file -- Xerves 8/24/99 */
void do_ahelp( CHAR_DATA *ch, char *argument )
{
	push_call("do_ahelp(%p,%p)",ch,argument);

	if (!strcasecmp( argument, "clear now"))
	{
		FILE *fp = my_fopen( HELP_FILE, "w", FALSE );
		if ( fp )
		  fclose( fp );
		send_to_char_color( "Add Help file cleared.\n\r", ch);
		pop_call();
		return;
	}
	else
	{
	  send_to_char_color( "\n\r{200}Help topics requested:{200} \n\r", ch );
		show_file( ch, HELP_FILE );
	}
	pop_call();
	return;
}


/*
 * List all available affect location applies - Kregor
 */
void print_applies( CHAR_DATA *ch )
{
	char text[MAX_STRING_LENGTH * 2];
	lg_int bit;
	
	push_call("print_applies(%p)",ch);
	
	for (*text = '\0', bit = 1 ; bit < MAX_APPLY ; bit++)
	{
		cat_sprintf(text, " {200}%-18s {300}%-21s %s\n\r", a_types[bit], bits_to_str(bit, "APPLY_"), affect_loc_name(bit));
	}
	send_to_char_color(text, ch);
	
	pop_call();
	return;
}


/*
 * GM informational command - Kregor
 */
void do_show( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];

	push_call("do_show(%p,%p)",ch,argument);

	argument = one_argument(argument, arg);

	if (IS_NPC(ch))
	{
		log_printf("do_show: used by mob");
		dump_stack();
		pop_call();
		return;
	}

	if (IS_GOD(ch) && !strcasecmp(arg, "openfiles"))
	{
		do_openfiles(ch, argument);
	}
	if (IS_GOD(ch) && !strcasecmp(arg, "addhelps"))
	{
		do_ahelp(ch, argument);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "cpu"))
	{
		do_cpu(ch, argument);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg,"memory"))
	{
		do_memory(ch, argument);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "terms"))
	{
		do_termlist(ch, argument);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "users"))
	{
		do_users(ch, argument);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "usage"))
	{
		do_usage(ch, argument);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "log"))
	{
		do_llog(ch, argument);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "arrests"))
	{
		do_file(ch, argument);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "accounts"))
	{
		do_lookup(ch, "accounts");
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "pets"))
	{
		do_lookup(ch, "pets");
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "roomaffects"))
	{
		do_lookup(ch, "timers");
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "exp"))
	{
		do_showcurve(ch, argument);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "stack"))
	{
		do_stack(ch, argument);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "hash"))
	{
		ch_printf_color(ch, "%s", str_hash_status(argument));
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "maxskill"))
	{
		ch_printf_color(ch, "Top skill sn: %d\n\r", MAX_REAL_SKILL);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "applies"))
	{
		print_applies(ch);
	}
	else if (IS_GOD(ch) && !strcasecmp(arg, "dicerolls"))
	{
		if (IS_GOD(ch) && !strcasecmp( argument, "clear now"))
		{
			FILE *fp = my_fopen( DICE_FILE, "w", FALSE );
			if ( fp )
				fclose( fp );
			send_to_char_color( "Dice file cleared.\n\r", ch);
			pop_call();
			return;
		}
	  send_to_char_color( "\n\r{200}Dice Rolls {300}\n\r", ch );
		show_file( ch, DICE_FILE );
	}
	else
	{
		send_to_char("Syntax: <field> <argument>\n\r\n\r", ch);
		send_to_char("Field being one of:\n\r", ch);
		send_to_char("  addhelps cpu memory terms users usage log arrests accounts\n\r", ch);
		send_to_char("  pets roomaffects exp stack hash maxskill applies dicerolls\n\r", ch);
	}
	pop_call();
	return;
}


/*
 * Set your GM teleportation echoes
 */
void do_bamfin( CHAR_DATA *ch, char *argument )
{
	push_call("do_bamfin(%p,%p)",ch,argument);

	if (*argument == '\0')
	{
		send_to_char("Set bamf in to what?\n\r", ch);
		pop_call();
		return;
	}

	if (!IS_NPC(ch))
	{
		smash_tilde(argument);
		STRFREE(ch->pcdata->bamfin);
		ch->pcdata->bamfin = STRALLOC(argument);
		ch_printf_color(ch, "Bamf in set to: %s\n\r", argument);
	}
	pop_call();
	return;
}


void do_bamfout( CHAR_DATA *ch, char *argument )
{
	push_call("do_bamfout(%p,%p)",ch,argument);

	if (*argument == '\0')
	{
		send_to_char("Set bamf out to what?\n\r", ch);
		pop_call();
		return;
	}

	if (!IS_NPC(ch))
	{
		smash_tilde( argument );
		STRFREE(ch->pcdata->bamfout );
		ch->pcdata->bamfout = STRALLOC( argument );
		ch_printf_color(ch, "Bamf out set to: %s\n\r", argument);
	}
	pop_call();
	return;
}


/*
 * Put a problem player in holding - Kregor
 */
void do_arrest( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char buf[MAX_STRING_LENGTH];
	int jailtime, multiplier, pvnum;

	push_call("do_arrest(%p,%p)",ch,argument);

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

	if (IS_NPC(ch))
	{
		pop_call();
		return;
	}

	pvnum = 0;

	if (ch->pcdata->editmode == MODE_NONE)
	{
		if (*arg1 == '\0')
		{

			sprintf(buf, "List of arrested players:\n\r\n\r");

			for (pvnum = 0 ; pvnum < MAX_PVNUM ; pvnum++)
			{
				if (pvnum_index[pvnum] == NULL)
				{
					continue;
				}
				if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_ARRESTED))
				{
					cat_sprintf(buf, "%-16s", pvnum_index[pvnum]->name);
				}
			}
			ch_printf_color(ch, "%s\n\r", justify(buf, 80));

			pop_call();
			return;
		}

		if (*arg2 == '\0')
		{
			send_to_char("Usage: arrest <name> <number> <hours|days|months|years>\n\r\n\r", ch);		
	
			pop_call();
			return;
		}
	
		if ((pvnum = get_pvnum_name(arg1)) == -1)
		{
			send_to_char("That player does not exist.\n\r", ch);
			pop_call();
			return;
		}

		if (pvnum < 100)
		{
			send_to_char("You cannot arrest a GM.\n\r", ch);
			pop_call();
			return;
		}

		if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_ARRESTED))
		{
			send_to_char("They've already been arrested.\n\r", ch);
			pop_call();
			return;
		}

		if ((jailtime = atoi(arg2)) <= 0)
		{
			send_to_char("You must enter a correct duration.\n\r", ch);
			pop_call();
			return;
		}

		switch (*argument)
		{
			case 'h':	case 'H': multiplier = 3600;		break;
			case 'd':	case 'D': multiplier = 86400;		break;
			case 'w': case 'W': multiplier = 604800;	break;
			case 'm':	case 'M': multiplier = 2635200;	break;
			case 'y': case 'Y': multiplier = 31536000;	break;

			default:
				send_to_char("You must specify 'years', 'months', 'weeks', 'hours' or 'days'.\n\r", ch);
				pop_call();
				return;
				break;
		}

		if (multiplier * jailtime > 31536000)
		{
			send_to_char("The maximum sentence is 1 year.\n\r", ch);
			pop_call();
			return;
		}

		if (pvnum_index[pvnum]->ch == NULL)
		{
			do_pload(ch, pvnum_index[pvnum]->name);
		}

		if (pvnum_index[pvnum] == NULL || pvnum_index[pvnum]->ch == NULL)
		{
			send_to_char("Failed to find pvnum data.\n\r", ch);
			pop_call();
			return;
		}

		victim = pvnum_index[pvnum]->ch;

		log_printf("[ARREST] %s has arrested %s", ch->name, victim->name);

		if (in_combat(victim))
		{
			char_from_combat( victim );
		}
		char_to_room(victim, ROOM_VNUM_ABYSS, TRUE);

		SET_BIT(pvnum_index[pvnum]->flags, PVNUM_ARRESTED);
		victim->pcdata->jailtime = jailtime * multiplier;
		victim->pcdata->jaildate = mud->current_time;

		send_to_char_color("{118}You have been condemned to the Abyss.\n\r", ch);
		ch_printf_color(ch, "%s has been arrested.\n\r", get_name(victim));

		save_players();
	}

	switch (ch->pcdata->editmode)
	{
		default :
			bug("do_arrest() : illegal editmode");
			pop_call();
			return;

		case MODE_RESTRICTED :
			send_to_char("You cannot arrest someone while editing something.\n\r",ch);
			pop_call();
			return;

		case MODE_NONE :
			ch->pcdata->edit_ptr = pvnum_index[pvnum];
			ch->pcdata->editmode = MODE_CRIME_RECORD;
			ch->pcdata->tempmode = MODE_NONE;
			start_editing(ch, ch->pcdata->edit_buf);
			pop_call();
			return;

		case MODE_CRIME_RECORD :
			add_crime(ch, ch->pcdata->edit_ptr);
			stop_editing(ch);
			pop_call();
			return;
	}
	pop_call();
	return;
}

void add_crime (CHAR_DATA *ch, PVNUM_DATA *pvnum)
{
	CHAR_DATA *victim;
	CRIME_DATA *new_record;

	push_call("add_crime(%p,%p)",ch,pvnum);

	if (pvnum->ch == NULL)
	{
		do_pload(ch, pvnum->name);
	}

	victim = pvnum->ch;

	ALLOCMEM(new_record, CRIME_DATA, 1);

	new_record->crime_record = copy_buffer(ch);
	new_record->arrester     = STRALLOC(ch->name);
	new_record->date         = mud->current_time;
	new_record->level        = UMIN(ch->level, MAX_LEVEL);
	new_record->jailtime     = victim->pcdata->jailtime;

	LINK(new_record, victim->pcdata->first_record, victim->pcdata->last_record, next, prev);

	pop_call();
	return;
}

/*
 * Release an arrested player - Kregor
 */
void do_unarrest( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA  *victim;
	CRIME_DATA *record;

	push_call("do_unarrest(%p,%p)",ch,argument);

	if ((victim = get_player_world(ch, argument)) == NULL)
	{
		send_to_char("That character could not be found.\n\r", ch);
		pop_call();
		return;
	}

	if (!IS_SET(pvnum_index[victim->pcdata->pvnum]->flags, PVNUM_ARRESTED))
	{
		send_to_char("That player is not imprisoned.\n\r", ch);
		pop_call();
		return;
	}

	record = victim->pcdata->last_record;

	if (record && record->level >= ch->level)
	{
		if (record->level == MAX_LEVEL && !strcasecmp(ch->name, record->arrester))
		{
			send_to_char("Overriding your own sentence!\n\r", ch);
		}
		else
		{
			ch_printf_color(ch, "You may not release %s", capitalize(victim->name));
			pop_call();
			return;
		}
	}

	if (record)
	{
		record->released = TRUE;
		STRFREE(record->releaser);
		record->releaser = STRALLOC(ch->name);
	}

	act( "$n has been released.", victim, NULL, NULL, TO_ROOM );
	char_from_room( victim );
	char_to_room( victim, ROOM_VNUM_TEMPLE, TRUE );
	act( "$n has been released.", victim, NULL, NULL, TO_ROOM );
	do_look( victim, "auto" );
	act( "$n has released you.", ch, NULL, victim, TO_VICT );

	REMOVE_BIT(pvnum_index[victim->pcdata->pvnum]->flags, PVNUM_ARRESTED);
	victim->pcdata->jailtime = 0;
	victim->pcdata->jaildate = 0;

	ch_printf_color(ch, "%s has been released.\n\r", get_name(victim));

	save_players();

	pop_call();
	return;
}


void auto_release( CHAR_DATA *ch )
{
	CRIME_DATA *record;

	push_call("auto_release(%p)",ch);

	record = ch->pcdata->last_record;

	if (record)
	{
		STRFREE(record->releaser);
		record->released = TRUE;
		record->releaser = STRALLOC("The System");
	}

	act( "$n has been released.", ch, NULL, NULL, TO_ROOM );
	char_from_room( ch );
	char_to_room( ch, ROOM_VNUM_TEMPLE, TRUE );
	act( "$n has been released.", ch, NULL, NULL, TO_ROOM );
	do_look( ch, "auto" );

	REMOVE_BIT(pvnum_index[ch->pcdata->pvnum]->flags, PVNUM_ARRESTED);
	ch->pcdata->jailtime = 0;
	ch->pcdata->jaildate = 0;

	send_to_char("You have been released from the dungeons.\n\r", ch);

	save_players();
	pop_call();
	return;
}


/*
 * Warn a player of a TOS infraction - Kregor 6/16/12
 */
void do_warn (CHAR_DATA * ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	char text2[MAX_STRING_LENGTH];
	char say_buf[MAX_STRING_LENGTH];
	CHAR_DATA *victim;
	int warning;

	push_call("do_warn(%p,%p)",ch,argument);

	if (!IS_GOD(ch))
	{
		pop_call();
		return;
	}
	
	argument = one_argument(argument, arg);

	if (arg[0] == '\0' || argument[0] == '\0')
	{
		send_to_char ("Syntax: warn <player> <twink|harassment|language|other>\n\r", ch);
		pop_call();
		return;
	}

	if ((victim = get_player_world(ch, arg)) == NULL)
	{
		send_to_char ("That player isn't here.\n\r", ch);
		pop_call();
		return;
	}

	if (victim->desc == NULL)
	{
		ch_printf_color(ch, "That player is link-dead.\n\r");
		pop_call();
		return;
	}

	if (!strcasecmp(argument, "twink"))
	{
		warning = 1;
	}
	else if (!strcasecmp(argument, "harassment"))
	{
		warning = 2;
	}
	else if (!strcasecmp(argument, "language"))
	{
		warning = 3;
	}
	else
	{
		warning = 0;
	}
	
	switch (warning)
	{
		case 0:
			sprintf(text2, "You are engaging in activity that is unacceptable to the Terms of Service. Please see HELP TOS for more information.");
			break;
		case 1:
			sprintf(text2, "You are engaging in activity that the GMs consider twinking. Please see HELP TWINK for more information.");
			break;
		case 2:
			sprintf(text2, "You are engaging in harassment, and are instructed to stop immediately. Please see HELP HARASSMENT for more information.");
			break;
		case 3:
			sprintf(text2, "You are using language that is out of period for this setting. Please see HELP LANGUAGE for more information.");
			break;
	}
	
	log_printf("[WARN] %s has warned %s: %s", ch->name, victim->name, text2);

	sprintf(say_buf, "You have warned %s: {178}%s\n\r", victim->name, text2);
	send_to_char_color(justify(say_buf, get_page_width(ch)), ch);

	sprintf(say_buf, "{118}[NOTICE] {178}%s\n\r", text2);
	send_to_char_color(justify(say_buf, get_page_width(victim)), victim);

	pop_call();
	return;
}


/*
 * Lasting disciplinary action against a player - Kregor 6/16/12
 */
void do_strike( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;

	push_call("do_strike(%p,%p)",ch,argument);

	if (*argument == '\0')
	{
		send_to_char("Strike whom?\n\r", ch);
		pop_call();
		return;
	}
	
	if ((victim = get_player_world(ch, argument)) == NULL)
	{
		send_to_char("You can only strike a player that is online.\n\r", ch);
		pop_call();
		return;
	}

	if (IS_GOD(victim))
	{
		send_to_char( "You cannot strike an admin.\n\r", ch );
		pop_call();
		return;
	}

	if (!victim->desc || !victim->desc->account)
	{
		send_to_char( "Could not locate the player's account!\n\r", ch );
		pop_call();
		return;
	}
	
	log_printf("%s has received a strike from %s", get_name(victim), ch->name);
	++victim->desc->account->strikes;
	victim->desc->account->rp_points -= 33; // each strike penalizes XP gain by 1/3

	if (++victim->desc->account->strikes >= 3)
	{
		SET_BIT(victim->desc->account->flags, ACCT_DENIED);
		ch_printf(ch, "%s has been banned for too many strikes!\n\r", get_name(victim));
	
		if (victim)
		{
			send_to_char_color("{118}You have been denied access due to your number of strikes!\n\r", victim);
			do_quit(victim, NULL);
		}
	}
	else
	{
		ch_printf(ch, "%s has been given a strike, for a total of %d strikes.\n\r", get_name(victim), victim->desc->account->strikes);

		if (victim)
		{
			ch_printf_color(victim, "{118}You have received a strike for your actions!\n\r");
			ch_printf_color(victim, "{118}if you receive %d more, you will be banned.\n\r", 3 - victim->desc->account->strikes);
		}
	}
	
	save_players();

	pop_call();
	return;
}


/*
 * Ban a specific PC from logging in - Kregor
 */
void do_deny( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;

	char buf[MAX_STRING_LENGTH];
	int pvnum;

	push_call("do_deny(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		sprintf(buf, "List of denied players:\n\r\n\r");

		for (pvnum = 0 ; pvnum < MAX_PVNUM ; pvnum++)
		{
			if (pvnum_index[pvnum] == NULL)
			{
				continue;
			}
			if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_DENIED))
			{
				cat_sprintf(buf, "%-16s", pvnum_index[pvnum]->name);
			}
		}
		ch_printf_color(ch, "%s\n\r", justify(buf, 80));
		pop_call();
		return;
	}

	if ((pvnum = get_pvnum_name(argument)) == -1)
	{
		send_to_char("That player does not exist.\n\r", ch);
		pop_call();
		return;
	}

	if (pvnum < 100)
	{
		send_to_char( "You failed.\n\r", ch );
		pop_call();
		return;
	}

	victim = get_char_pvnum(pvnum);

	TOGGLE_BIT(pvnum_index[pvnum]->flags, PVNUM_DENIED);

	if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_DENIED))
	{
		send_to_char( "They have been denied access.\n\r", ch );

		log_printf("%s has been denied by %s", pvnum_index[pvnum]->name, ch->name);

		if (victim)
		{
			send_to_char("You have been denied access.\n\r", victim);
			do_quit(victim, NULL);
		}
	}
	else
	{
		send_to_char( "They are no longer denied.\n\r", ch );

		log_printf("%s has been undenied by %s", pvnum_index[pvnum]->name, ch->name);
	}
	save_players();

	pop_call();
	return;
}

/*
 * Punt a player offline without warning
 */
void do_disconnect( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	DESCRIPTOR_DATA *d;
	CHAR_DATA *victim;
	int port;

	push_call("do_disconnect(%p,%p)",ch,argument);

	one_argument( argument, arg );

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

	if ((port = atol(arg)) == 0)
	{
		if ((victim = get_player_world(ch, arg)) == NULL)
		{
			send_to_char( "They aren't here.\n\r", ch );
			pop_call();
			return;
		}

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

		for (d = mud->f_desc ; d ; d = d->next)
		{
			if (is_desc_valid(d->character) && d == victim->desc)
			{
				close_socket(d, TRUE);
				send_to_char( "Ok.\n\r", ch );
				pop_call();
				return;
			}
		}
		send_to_char( "Descriptor of that name not found!\n\r", ch );
		pop_call();
		return;
	}

	for (d = mud->f_desc ; d ; d = d->next)
	{
		if (d->descriptor == port)
		{
			close_socket(d, TRUE);
			send_to_char( "Ok.\n\r", ch);
			pop_call();
			return;
		}
	}
	send_to_char( "Descriptor of that number not found!\n\r", ch );
	pop_call();
	return;
}

/*
 * Freeze a player from issuing commands online
 */
void do_freeze( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char buf[MAX_STRING_LENGTH];
	int pvnum;

	push_call("do_freeze(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		sprintf(buf, "List of frozen players:\n\r\n\r");

		for (pvnum = 0 ; pvnum < MAX_PVNUM ; pvnum++)
		{
			if (pvnum_index[pvnum] == NULL)
			{
				continue;
			}
			if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_FROZEN))
			{
				cat_sprintf(buf, "%-16s", pvnum_index[pvnum]->name);
			}
		}
		ch_printf_color(ch, "%s\n\r", justify(buf, 80));
		pop_call();
		return;
	}

	if ((pvnum = get_pvnum_name(argument)) == -1)
	{
		send_to_char("That player does not exists.\n\r", ch);
		pop_call();
		return;
	}

	if (pvnum < 100)
	{
		send_to_char( "You failed.\n\r", ch );
		pop_call();
		return;
	}

	victim = get_char_pvnum(pvnum);

	TOGGLE_BIT(pvnum_index[pvnum]->flags, PVNUM_FROZEN);

	if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_FROZEN))
	{
		send_to_char( "They have been frozen.\n\r", ch );
		log_printf("%s has been frozen by %s", get_name_pvnum(pvnum), ch->name);

		if (victim)
		{
			send_to_char( "You have been frozen.\n\r", victim);
		}
	}
	else
	{
		send_to_char("They are no longer frozen.\n\r", ch);
		log_printf("%s has been un-frozen by %s", get_name_pvnum(pvnum), ch->name);

		if (victim)
		{
			send_to_char( "You are no longer frozen.\n\r", victim);
		}
	}
	save_players();

	pop_call();
	return;
}


/*
 * Prevent a player from using speech or chat commands
 */
void do_mute( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	int pvnum;

	push_call("do_mute(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		sprintf(buf, "List of muted players:\n\r\n\r");

		for (pvnum = 0 ; pvnum < MAX_PVNUM ; pvnum++)
		{
			if (pvnum_index[pvnum] == NULL)
			{
				continue;
			}
			if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_MUTED))
			{
				cat_sprintf(buf, "%-16s", pvnum_index[pvnum]->name);
			}
		}
		ch_printf_color(ch, "%s\n\r", justify(buf, 80));
		pop_call();
		return;
	}

	if ((pvnum = get_pvnum_name(argument)) == -1)
	{
		send_to_char("That player does not exists.\n\r", ch);
		pop_call();
		return;
	}

	if (pvnum < 100)
	{
		send_to_char( "You failed.\n\r", ch );
		pop_call();
		return;
	}

	TOGGLE_BIT(pvnum_index[pvnum]->flags, PVNUM_MUTED);

	if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_MUTED))
	{
		send_to_char( "They have been muted.\n\r", ch );

		log_printf("%s has been muted by %s", get_name_pvnum(pvnum), ch->name);
	}
	else
	{
		send_to_char( "They are no longer muted.\n\r", ch );

		log_printf("%s has been un-muted by %s", get_name_pvnum(pvnum), ch->name);
	}
	save_players();

	pop_call();
	return;
}


/*
 * Enable logging all actions by a player
 */
void do_log( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_INPUT_LENGTH];
	int pvnum;

	push_call("do_log(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		sprintf(buf, "List of logged players:\n\r\n\r");

		for (pvnum = 0 ; pvnum < MAX_PVNUM ; pvnum++)
		{
			if (pvnum_index[pvnum] == NULL)
			{
				continue;
			}
			if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_LOGGED))
			{
				cat_sprintf(buf, "%-16s", pvnum_index[pvnum]->name);
			}
		}
		ch_printf_color(ch, "%s\n\r", justify(buf, 80));
		pop_call();
		return;
	}

	if ((pvnum = get_pvnum_name(argument)) == -1)
	{
		send_to_char("That player does not exists.\n\r", ch);
		pop_call();
		return;
	}

	TOGGLE_BIT(pvnum_index[pvnum]->flags, PVNUM_LOGGED);

	if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_LOGGED))
	{
		send_to_char( "They have been logged.\n\r", ch );

		log_printf("%s has been logged by %s", get_name_pvnum(pvnum), ch->name);
	}
	else
	{
		send_to_char( "They are no longer logged.\n\r", ch );

		log_printf("%s has been un-logged by %s", get_name_pvnum(pvnum), ch->name);
	}
	save_players();

	pop_call();
	return;
}

/*
 * Prevent a PC from using any communication commands
 */
void do_silence( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char buf[MAX_STRING_LENGTH];
	int pvnum;

	push_call("do_silence(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		sprintf(buf, "List of silenced players:\n\r\n\r");

		for (pvnum = 0 ; pvnum < MAX_PVNUM ; pvnum++)
		{
			if (pvnum_index[pvnum] == NULL)
			{
				continue;
			}
			if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_SILENCED))
			{
				cat_sprintf(buf, "%-16s", pvnum_index[pvnum]->name);
			}
		}
		ch_printf_color(ch, "%s\n\r", justify(buf, 80));
		pop_call();
		return;
	}

	if ((pvnum = get_pvnum_name(argument)) == -1)
	{
		send_to_char("That player does not exist.\n\r", ch);
		pop_call();
		return;
	}

	if (pvnum < 100)
	{
		send_to_char( "You failed.\n\r", ch );
		pop_call();
		return;
	}

	TOGGLE_BIT(pvnum_index[pvnum]->flags, PVNUM_SILENCED);

	victim = get_char_pvnum(pvnum);

	if (IS_SET(pvnum_index[pvnum]->flags, PVNUM_SILENCED))
	{
		send_to_char( "They have been silenced.\n\r", ch );

		log_printf("%s has been silenced by %s", get_name_pvnum(pvnum), ch->name);
		if (victim)
		{
			send_to_char("You have been silenced.\n\r", victim);
		}
	}
	else
	{
		send_to_char( "They are no longer silenced.\n\r", ch );

		log_printf("%s has been un-silenced by %s", get_name_pvnum(pvnum), ch->name);

		if (victim)
		{
			send_to_char("You are no longer silenced.\n\r", victim);
		}
	}
	save_players();

	pop_call();
	return;
}


/*
 * Wipe out IC criminal records from a PC - Kregor
 */
void do_pardon( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	BOUNTY_DATA *bounty, *bounty_next;

	push_call("do_pardon(%p,%p)",ch,argument);

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

	if (arg1[0] == '\0' || arg2[0] == '\0')
	{
		send_to_char( "Syntax: pardon <player> <killer|thief|outcast|crimes>.\n\r", ch );
		pop_call();
		return;
	}

	if ((victim = get_player_world(ch, arg1)) == NULL)
	{
		send_to_char( "They aren't here.\n\r", ch );
		pop_call();
		return;
	}

	if (!strcasecmp(arg2, "killer"))
	{
		TOGGLE_BIT(victim->act, PLR_KILLER);

		if (IS_SET(victim->act, PLR_KILLER))
		{
			victim->pcdata->killer_played = victim->pcdata->played;
			send_to_char( "Killer flag added.\n\r", ch );
			send_to_char( "You are now a KILLER!\n\r", victim );
		}
		else
		{
			send_to_char( "Killer flag removed.\n\r", ch );
			send_to_char( "You are no longer a KILLER.\n\r", victim );
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg2, "thief"))
	{
		TOGGLE_BIT(victim->act, PLR_THIEF);

		if (IS_SET(victim->act, PLR_THIEF))
		{
	 		send_to_char( "Thief flag added.\n\r", ch );
			send_to_char( "You are now a THIEF!\n\r", victim );
		}
		else
		{
			send_to_char( "Thief flag removed.\n\r", ch );
			send_to_char( "You are no longer a THIEF.\n\r", victim );
		}
		pop_call();
		return;
    }

	if (!strcasecmp(arg2, "outcast"))
	{
		TOGGLE_BIT(victim->act, PLR_OUTCAST);

		if (IS_SET(victim->act, PLR_OUTCAST))
		{
			send_to_char( "Outcast flag added.\n\r", ch );
			send_to_char( "You are now an OUTCAST!\n\r", victim );
		}
		else
		{
			send_to_char( "Outcast flag removed.\n\r", ch );
			send_to_char( "You are no longer an OUTCAST.\n\r", victim );
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg2, "crimes"))
	{
		for (bounty = mud->f_bounty ; bounty ; bounty = bounty_next)
		{
			bounty_next = bounty->next;
			
			if (bounty->pvnum == victim->pcdata->pvnum)
			{
				remove_bounty(bounty);
			}
			save_bounties();
		}
		act( "You have purged all of $N's criminal records.", ch, NULL, victim, TO_CHAR );
		pop_call();
		return;
	}
			
	send_to_char( "Syntax: pardon <player> <killer|thief|outcast>.\n\r", ch );
	pop_call();
	return;
}


/*
 * Echo something across the entire server
 */
void do_echo( CHAR_DATA *ch, char *argument )
{
	DESCRIPTOR_DATA *d;

	push_call("do_echo(%p,%p)",ch,argument);

	if (argument[0] == '\0')
	{
		if (ch != NULL)
		{
			send_to_char( "Echo what?\n\r", ch );
		}
		pop_call();
		return;
	}

	for (d = mud->f_desc ; d ; d = d->next)
	{
		if (is_desc_valid(d->character) && (d->connected == CON_PLAYING || d->connected == CON_EDITING))
		{
			if ((!IS_NPC(d->character) && (d->character->level == MAX_LEVEL) && (ch != NULL)))
			{
				ch_printf_color(d->character, "{178}[{078}%s{178}]\n\r", ch->name);
			}
			ch_printf_color(d->character, "%s\n\r", ansi_justify(argument, get_page_width(d->character)));
		}
	}
	pop_call();
	return;
}

/*
 * Return the room VNUM of a character
 */
int find_location( CHAR_DATA *ch, char *arg )
{
	CHAR_DATA *victim;

	push_call("find_location(%p,%p)",ch,arg);

	if (is_number(arg))
	{
		if (get_room_index(atol(arg)) == NULL)
		{
			pop_call();
			return -1;
		}
		pop_call();
		return atol(arg);
	}

	if ((victim = get_player_world(ch, arg)) != NULL)
	{
		pop_call();
		return victim->in_room->vnum;
	}

	if ((victim = get_char_world(ch, arg)) != NULL)
	{
		pop_call();
		return victim->in_room->vnum;
	}

	pop_call();
	return -1;
}

/*
 * Transfer a character around
 */
void do_transfer( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	int location;
	DESCRIPTOR_DATA *d;
	CHAR_DATA *victim;

	push_call("do_transfer(%p,%p)",ch,argument);

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

	if (arg1[0] == '\0')
	{
		send_to_char( "Transfer whom (and where)?\n\r", ch );
		pop_call();
		return;
	}

	if (IS_NPC(ch))
	{
		log_printf("[%u] Mob using transfer", ch->pIndexData->vnum);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "all") && IS_GOD(ch))
	{
		for (d = mud->f_desc ; d ; d = d->next)
		{
			if (d->connected >= CON_PLAYING
			&&  is_desc_valid(d->character)
			&&  d->character != ch
			&&  d->character->in_room != NULL
			&&  d->character->in_room != ch->in_room
			&&  !NEW_AUTH(d->character)
			&&  can_see_world(ch, d->character))
			{
				char buf[MAX_STRING_LENGTH];
				sprintf(buf, "%s %s", d->character->name, arg2);
				do_transfer(ch, buf);
			}
		}
		pop_call();
		return;
	}

	/*
		Thanks to Grodyn for the optional location parameter.
	*/
	if (arg2[0] == '\0')
	{
		location = ch->in_room->vnum;
	}
	else
	{
		if ((location = find_location(ch, arg2)) == -1)
		{
			send_to_char( "No such location.\n\r", ch );
			pop_call();
			return;
		}

		if (!can_olc_modify(ch, location))
		{
			send_to_char( "That location is not in your allocated vnum range.\n\r", ch);
			pop_call();
			return;
		}

		if (ch->level < LEVEL_IMMORTAL && room_is_private(room_index[location]))
		{
			send_to_char( "That room is private right now.\n\r", ch );
			pop_call();
			return;
		}
	}

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

	if (victim->in_room == NULL)
	{
		send_to_char( "They are in limbo.\n\r", ch );
		pop_call();
		return;
	}

	if (NOT_AUTHED(victim))
	{
		send_to_char( "That character is not authorized.\n\r", ch );
		pop_call();
		return;
	}

	if (in_combat(victim))
	{
		char_from_combat( victim );
	}
	act( "$n disappears in a mushroom cloud.", victim, NULL, NULL, TO_ROOM );
	victim->retran = victim->in_room->vnum;
	char_from_room( victim );
	char_to_room( victim, location, TRUE );
	act( "$n arrives from a puff of smoke.", victim, NULL, NULL, TO_ROOM );
	if (ch != victim)
	{
		act( "$n has transferred you.", ch, NULL, victim, TO_VICT );
	}
	do_look( victim, "auto" );

	pop_call();
	return;
}

/*
 * Put a character back where you transferred them from
 */
void do_retran( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	char buf[MAX_STRING_LENGTH];

	push_call("do_retran(%p,%p)",ch,argument);

	argument = one_argument( argument, arg );

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

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

	sprintf(buf, "'%s' %d", arg, victim->retran);
	do_transfer(ch, buf);
	pop_call();
	return;
}

/*
 * Raise a dead character without penalty - Kregor
 */
void do_resurrect( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	
	push_call("do_resurrect(%p,%p)",ch,argument);

	if (IS_NPC(ch) || !IS_IMMORTAL(ch))
	{
		pop_call();
		return;
	}
	
	if (!argument || argument[0] == '\0')
	{
		send_to_char("Resurrect whom?\n\r", ch);
		pop_call();
		return;
	}
	
	if ((victim = get_player_world_even_blinded(argument)) == NULL)
	{
		send_to_char("You can't find that player.\n\r", ch);
		pop_call();
		return;
	}
		
	if (!IS_PLR(victim, PLR_DEAD))
	{
		send_to_char("They have to be dead first, silly!\n\r", ch);
		pop_call();
		return;
	}

	act("{138}$n's spirit departs from the beyond!", victim, NULL, NULL, TO_ROOM);
	char_from_room(victim);
	char_to_room(victim, ch->in_room->vnum, TRUE);

	act("{138}You have been raised from the dead!", victim, NULL, NULL, TO_CHAR);
	act("{138}$n has been raised from the dead!", victim, NULL, NULL, TO_ROOM);
	REMOVE_BIT(victim->act, PLR_DEAD);
	
	do_look(victim, "");

	pop_call();
	return;
}

/*
 * Execute a command at another specified location
 */
void do_at( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	int location, original;
	CHAR_DATA *mount;
	OBJ_DATA  *furniture = NULL;

	push_call("do_at(%p,%p)",ch,argument);

	argument = one_argument( argument, arg );

	if (IS_NPC(ch))
	{
		log_printf( "[%u] Mob using at: %s", ch->pIndexData->vnum, argument);
		pop_call();
		return;
	}

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

	if ((location = find_location(ch, arg)) == -1)
	{
		send_to_char( "No such location.\n\r", ch );
		pop_call();
		return;
	}

	if (!can_olc_modify(ch, location))
	{
		send_to_char("That destination is not in your allocated vnum range.\n\r", ch);
		pop_call();
		return;
	}

	mount	= ch->mounting;
	original  = ch->in_room->vnum;

	if (ch->furniture)
	{
		furniture = ch->furniture;
		user_from_furniture( ch );
	}
	char_from_room( ch );
	char_to_room( ch, location, FALSE );

	interpret(ch, argument);

	/*
		See if 'ch' still exists before continuing!
		Handles 'at XXXX quit' case.
	*/

	if (ch->in_room)
	{
		char_from_room(ch);
		char_to_room(ch, original, FALSE);
		if (furniture)
			user_to_furniture(ch, furniture);
		ch->mounting  = mount;
	}
	pop_call();
	return;
}


/*
 * Find all instances of a named NPC
 */
void do_mfind( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	MOB_INDEX_DATA *pMobIndex;
	int nMatch, vnum;

	push_call("do_mfind(%p,%p)",ch,argument);

	one_argument( argument, arg );

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

	for (nMatch = 0, vnum = 0 ; vnum < MAX_VNUM ; vnum++)
	{
		if ((pMobIndex = get_mob_index(vnum)) != NULL)
		{
			if (!can_olc_modify(ch, pMobIndex->vnum))
			{
				continue;
			}
			if (is_multi_name_list_short(arg, pMobIndex->player_name) && ++nMatch)
			{
				ch_printf_color(ch, "{178}[{078}%5u{178}] %s%s\n\r",
					pMobIndex->vnum,
					get_color_string(ch, COLOR_MOBILES, VT102_DIM),
					capitalize(pMobIndex->short_descr));
			}
		}
	}

	if (nMatch)
	{
		ch_printf_color( ch, "Number of matches: %d\n", nMatch );
	}
	else
	{
		send_to_char( "Nothing like that in hell, heaven, or earth.\n\r", ch );
	}
	pop_call();
	return;
}

/*
 * Find all instances of a named object
 */
void do_ofind( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	OBJ_INDEX_DATA *pObjIndex;
	int nMatch, vnum;

	push_call("do_ofind(%p,%p)",ch,argument);

	one_argument( argument, arg );

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

	for (nMatch = 0, vnum = 0 ; vnum < MAX_VNUM ; vnum++)
	{
		if ((pObjIndex = get_obj_index(vnum)) != NULL)
		{
			if (!can_olc_modify(ch, pObjIndex->vnum))
			{
				continue;
			}
			if (is_multi_name_list_short(arg, pObjIndex->name) && ++nMatch)
			{
				ch_printf_color(ch, "{178}[{078}%5u{178}] %s%s\n\r",
					pObjIndex->vnum,
					get_color_string(ch, COLOR_OBJECTS, VT102_BOLD),
					capitalize(pObjIndex->short_descr));
			}
		}
	}
	if (nMatch)
	{
		ch_printf_color(ch, "Number of matches: %d\n", nMatch);
	}
	else
	{
		send_to_char( "Nothing like that in hell, earth, or heaven.\n\r", ch );
	}
	pop_call();
	return;
}


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

	push_call("do_find(%p,%p)",ch,argument);

	argument = one_argument(argument, arg);

	if (!strcasecmp(arg, "mob"))
	{
		do_mfind(ch, argument);
	}
	else if (!strcasecmp(arg, "obj"))
	{
		do_ofind(ch, argument);
	}
	else
	{
		ch_printf_color(ch, "Syntax: find <mob|obj> <name>\n\r");
	}
	pop_call();
	return;
}


void do_reboo( CHAR_DATA *ch, char *argument )
{
	push_call("do_reboo(%p,%p)",ch,argument);
	send_to_char( "If you want to REBOOT, spell it out.\n\r", ch );
	pop_call();
	return;
}

/*
 * Reboot the server, punting everyone off
 */
void do_reboot( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	PLAYER_GAME *pch, *pch_next;

	push_call("do_reboot(%p,%p)",ch,argument);

	if (argument[0] == 'S' || argument[0] == 's')
	{
		sprintf(buf, "Reboot scheduled after everyone is off the Realm.\n\rCompliments of %s\n\r", ch->name);
		do_echo( ch, buf );
		SET_BIT(mud->flags, MUD_EMUD_REBOOT);
		pop_call();
		return;
	}

	if (argument[0] == 'N' || argument[0] == 'n')
	{
		DESCRIPTOR_DATA *d;
		DESCRIPTOR_DATA *d_next;

		log_string("Saving Castles...");
		do_savearea(NULL, "forreal");

		log_string("Saving Clans...");
		save_all_clans();

		log_string("Saving Hiscores...");
		save_hiscores();

		log_string("Saving Timeinfo...");
		save_timeinfo();

		log_string("Saving Storerooms...");
		save_lockers();

		for (d = mud->f_desc; d ; d = d_next)
		{
			d_next = d->next;

			if (!d->character || d->connected < 0)
			{
				write_to_descriptor (d, "\n\rSorry, the game is Rebooting. Try again in one minute.\n\r", 0);
				close_socket(d, TRUE);
			}
		}

		log_string("Saving Players...");

		for (pch = mud->f_player ; pch ; pch = pch_next)
		{
			pch_next = pch->next;
			
			if (pch->ch == ch)
				continue;

			if (pch->ch->desc != NULL)
				write_to_descriptor(pch->ch->desc, "The game is now rebooting.  Try again in 1 minute.\n\r", 0 );

			do_quit(pch->ch, NULL);
		}
		do_quit(ch, NULL);

		SET_BIT(mud->flags, MUD_EMUD_DOWN);
		SET_BIT(mud->flags, MUD_EMUD_BOOTING);

		pop_call();
		return;
	}
	send_to_char( "You must specify 'now' or 'soon'.\n\r", ch);
	pop_call();
	return;
}

void do_shutdow( CHAR_DATA *ch, char *argument )
{
	push_call("do_shutdow(%p,%p)",ch,argument);

	send_to_char( "If you want to SHUTDOWN, spell it out.\n\r", ch );
	pop_call();
	return;
}

void mud_shutdown( CHAR_DATA *ch )
{
	PLAYER_GAME *pch, *pch_next;
	FILE *fp;
	char name[MAX_INPUT_LENGTH];
	char buf[MAX_STRING_LENGTH];
	char *time = STRALLOC(get_time_string(mud->current_time));

	push_call("do_shutdown(%p)",ch);

	if (IS_NPC(ch) || !IS_GOD(ch))
	{
		log_printf("%s tried to shutdown the mud.", get_name(ch));
		dump_stack();
		pop_call();
		return;
	}

	strcpy(name, get_name(ch));
	sprintf(buf, "%s by %s", time, name);
	
	log_printf("SHUTDOWN [%s] by %s.\n", time, name);

	fp = my_fopen(SHUTDOWN_FILE, "w", FALSE);
	fprintf(fp, "Shutdown by %s.\n", ch->name);
	my_fclose(fp);

	do_echo(NULL, "The game is shutting down now. Please try to connect in 15 minutes again.");

	log_string("Saving Clans...");
	save_all_clans();

	log_string("Saving Castles...");
	do_savearea(NULL, "forreal");

	log_string("Saving Hiscores...");
	save_hiscores();

	log_string("Saving Timeinfo...");
	save_timeinfo();

	log_string("Saving Storerooms...");
	save_lockers();

	log_string("Saving Players...");

	for (pch = mud->f_player ; pch ; pch = pch_next)
	{
		pch_next = pch->next;

		if (pch->ch != ch)
		{
			send_to_char("The game is now shut down.  Try again in 15 minutes.\n\r", pch->ch);
			do_quit(pch->ch, NULL);
		}
	}
	do_quit(ch, NULL);

	my_fclose_all();

	SET_BIT(mud->flags, MUD_EMUD_DOWN);
	SET_BIT(mud->flags, MUD_EMUD_BOOTING);

	pop_call();
	return;
}


/*
 * Save one or all PCs online
 */
void do_save (CHAR_DATA * ch, char *argument)
{
	PLAYER_GAME *gch;
	CHAR_DATA   *tch;

	push_call("do_save(%p,%p)",ch,argument);

	if (IS_NPC(ch))
	{
		pop_call();
		return;
	}

	if (ch->level < LEVEL_IMMORTAL)
	{
		send_to_char("Your character is saved every 10 minutes, and at important events.\n\r", ch);
		pop_call();
		return;
	}

	if (argument[0] == '\0')
	{
		send_to_char("Syntax: save <all|playername|objects|area>\n\r", ch);
		pop_call();
		return;
	}

	if (!strcasecmp(argument, "all"))
	{
		send_to_char("Saving all players.\n\r", ch);
		for (gch = mud->f_player ; gch ; gch = gch->next)
		{
			save_char_obj(gch->ch, NORMAL_SAVE);
		}
		pop_call();
		return;
	}
	
	if (!str_prefix(argument, "objects"))
	{
		save_lockers();
		send_to_char("Lockers have been saved.\n\r",ch);
		pop_call();
		return;
	}

	if (!str_prefix(argument, "area"))
	{
		do_savearea(ch, "");
		pop_call();
		return;
	}

	else if ((tch = get_player_world(ch, argument)) == NULL)
	{
		do_save(ch, "");
		pop_call();
		return;
	}

	ch_printf_color(ch, "Saving %s.\n\r", get_name(tch));

	save_char_obj(tch, NORMAL_SAVE);

	pop_call();
	return;
}

/*
 * Shutdown the server indefinitely
 */
void do_shutdown( CHAR_DATA *ch, char *argument )
{
	push_call("do_shutdown(%p,%p)",ch,argument);

	if (IS_NPC(ch) || !IS_GOD(ch))
	{
		log_printf("%s tried to shutdown the mud.", get_name(ch));
		dump_stack();
		pop_call();
		return;
	}

	if (*argument == '\0' || strcasecmp(argument, "now"))
	{
		send_to_char( "You must specify 'now' after the command.\n\r", ch);
		pop_call();
		return;
	}
	
	mud_shutdown(ch);

	pop_call();
	return;
}


/*
 * Force a write of HTML who list - Kregor
 */
void do_savewho( CHAR_DATA *ch, char *argument )
{
	push_call("do_savewho(%p,%p)",ch,argument);

	if (IS_NPC(ch) || !IS_GOD(ch))
	{
		send_to_char( "You cannot do that.\n\r", ch);
		pop_call();
		return;
	}

	save_html_who();
	send_to_char("HTML who list updated.\n\r", ch);

	pop_call();
	return;
}


/*
 * Follow a player's every move
 */
void do_snoop( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	DESCRIPTOR_DATA *d;
	CHAR_DATA *victim;
	bool notify;

	push_call("do_snoop(%p,%p)",ch,argument);

	argument = one_argument(argument, arg);

	if (arg[0] == '\0')
	{
		victim = ch;
	}
	else if ((victim = get_player_world(ch, arg)) == NULL)
	{
		send_to_char( "They aren't here.\n\r", ch );
		pop_call();
		return;
	}

	if (tolower(argument[0]) == 'n')
	{
		notify = TRUE;
	}
	else
	{
		notify = FALSE;
	}

	if (victim->desc == NULL)
	{
		send_to_char( "No descriptor to snoop.\n\r", ch );
		pop_call();
		return;
	}

	log_god_printf("(G) %s: snoop %s %s", ch->name, arg, notify ? "(notified)" : "");

	if (victim == ch)
	{
		send_to_char( "Cancelling all snoops.\n\r", ch );

		for (d = mud->f_desc ; d ; d = d->next)
		{
			if (d->snoop_by == ch->desc)
			{
				d->snoop_by = NULL;
			}
		}
		pop_call();
		return;
	}

	if (victim->desc->snoop_by == ch->desc)
	{
		act( "Cancelling snoop of $N.", ch, NULL, victim, TO_CHAR );
		if (notify)
		{
			ch_printf_color(victim, "%s is no longer snooping you.\n\r", get_name(ch));
		}
		victim->desc->snoop_by = NULL;
		pop_call();
		return;
	}

	if (victim->desc->snoop_by != NULL )
	{
		send_to_char( "Busy already.\n\r", ch );
		pop_call();
		return;
	}

	if (get_trust(victim) == MAX_LEVEL)
	{
		send_to_char( "You failed.\n\r", ch );
		pop_call();
		return;
	}

	if (ch->desc != NULL)
	{
		for (d = ch->desc->snoop_by ; d != NULL ; d = d->snoop_by)
		{
			if (d->character == victim || d->original == victim)
			{
				send_to_char( "No snoop loops.\n\r", ch );
				pop_call();
				return;
			}
		}
	}

	victim->desc->snoop_by = ch->desc;
	act( "You are now snooping $N.", ch, NULL, victim, TO_CHAR );
	if (notify)
	{
		ch_printf_color(victim, "%s is now snooping you.\n\r", get_name(ch));
	}
	pop_call();
	return;
}

/*
 * Switch into an NPC
 */
void do_switch( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;

	push_call("do_switch(%p,%p)",ch,argument);

	one_argument( argument, arg );

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

	if (ch->desc == NULL)
	{
		pop_call();
		return;
	}

	if (ch->desc->original != NULL)
	{
		send_to_char( "You are already switched.\n\r", ch );
		pop_call();
		return;
	}

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

	if (!IS_NPC(victim))
	{
		send_to_char( "You may not switch into a player's character.\n\r", ch );
		pop_call();
		return;
	}

	if (victim == ch)
	{
		send_to_char( "Ok.\n\r", ch );
		pop_call();
		return;
	}

	if (victim->desc != NULL)
	{
		send_to_char( "Character in use.\n\r", ch );
		pop_call();
		return;
	}

	ch->desc->character  = victim;
	ch->desc->original   = ch;
	victim->desc         = ch->desc;
	ch->desc             = NULL;
	ch->pcdata->switched = TRUE;
	vt100prompt( victim );
	act( "You have switched into $N.\n\r", ch, NULL, victim, TO_VICT );

	pop_call();
	return;
}


/*
 * Release a controlled NPC
 */
void do_return( CHAR_DATA *ch, char *argument )
{
	push_call("do_return(%p,%p)",ch,argument);

	if (ch->desc == NULL)
	{
		pop_call();
		return;
	}

	if (ch->desc->original == NULL)
	{
		if (argument != NULL)
		{
			send_to_char( "You are already yourself.\n\r", ch );
		}
		pop_call();
		return;
	}

	send_to_char( "You return to your original body.\n\r", ch );

	ch->desc->character					= ch->desc->original;
	ch->desc->character->timer	= 0;
	ch->desc->character->pcdata->switched	= FALSE;
	ch->desc->original					= NULL;
	ch->desc->character->desc		= ch->desc;
	ch->desc										= NULL;

	if (IS_NPC(ch) && argument != NULL)
	{
		switch (ch->pIndexData->vnum)
		{
			case 9911:
				extract_char(ch);
				break;
		}
	}
	pop_call();
	return;
}


/*
 * Load up an NPC instance
 */
void do_mload( CHAR_DATA *ch, char *argument )
{
	MOB_INDEX_DATA *pMobIndex;
	CHAR_DATA *victim;

	push_call("do_mload(%p,%p)",ch,argument);

	log_god_printf("(G) %s: mload %s", ch->name, argument);

	if (!is_number(argument))
	{
		ch_printf_color(ch, "Syntax: load mob <vnum>\n\r");
	}
	else if (!can_olc_modify(ch, atoi(argument)))
	{
		ch_printf_color(ch, "Vnum: %d is not in your allocated range.\n\r", atoi(argument));
	}
	else if ((pMobIndex = get_mob_index(atol(argument))) == NULL)
	{
		ch_printf_color(ch, "No mob has that vnum.\n\r");
	}
	else
	{
		victim = create_mobile( pMobIndex );
		victim->npcdata->mloaded = TRUE;
		char_to_room( victim, ch->in_room->vnum, FALSE );
		act( "$N takes shape in the center of the room.", ch, NULL, victim, TO_ROOM );
		act( "$N takes shape in the center of the room.", ch, NULL, victim, TO_CHAR );
	}
	pop_call();
	return;
}

/*
 * Load an object instance
 */
void do_oload( CHAR_DATA *ch, char *argument )
{
	OBJ_INDEX_DATA *pObjIndex;
	OBJ_DATA *obj;

	push_call("do_oload(%p,%p)",ch,argument);

	log_god_printf("(G) %s: oload %s", ch->name, argument);

	if (!is_number(argument))
	{
		ch_printf_color(ch, "Syntax: load obj <vnum>\n\r");
	}
	else if (!can_olc_modify(ch, atoi(argument)))
	{
		ch_printf_color(ch, "Vnum: %d is not in your allocated range.\n\r", atoi(argument));
	}
	else if ((pObjIndex = get_obj_index(atol(argument))) == NULL)
	{
		ch_printf_color(ch, "No obj has that vnum.\n\r");
	}
	else
	{
		obj = create_object( pObjIndex, 0);
		obj_to_char(obj, ch);
		act( "You create $p.", ch, obj, NULL, TO_CHAR );
	}
	pop_call();
	return;
}

/*
 * Purge NPCs or objects, or both
 */
void do_purge( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	OBJ_DATA *obj;
	int room, room_start;
	bool quite;

	push_call("do_purge(%p,%p)",ch,argument);

	if (!ch->in_room)
	{
		pop_call();
		return;
	}

	if (!can_olc_modify(ch, ch->in_room->vnum))
	{
		send_to_char( "This area is not in your assigned range.\n\r", ch);
		pop_call();
		return;
	}

	if (argument != NULL)
	{
		quite = FALSE;
		one_argument( argument, arg );
	}
	else
	{
		quite = TRUE;
		strcpy(arg, "");
	}

	if (!strcasecmp(arg, "area"))
	{
		arg[0] = '\0';
		room_start = ch->in_room->vnum;

		for (room = room_index[room_start]->area->low_r_vnum ; room <= room_index[room_start]->area->hi_r_vnum ; room++)
		{
			if (room_index[room] == NULL)
			{
				continue;
			}
			if (room_index[room]->area != room_index[room_start]->area)
			{
				break;
			}
			char_from_room(ch);
			char_to_room(ch, room, TRUE);
			do_purge(ch, NULL);
		}
		char_from_room(ch);
		char_to_room(ch, room_start, TRUE);
		send_to_char( "You have purged the Area.\n\r", ch);
		pop_call();
		return;
	}

	if (!is_string(arg))
	{
		CHAR_DATA *vnext;
		OBJ_DATA  *obj_next;

		for (victim = ch->in_room->first_person ; victim != NULL ; victim = vnext)
		{
			vnext = victim->next_in_room;
			if (IS_NPC(victim) && victim != ch)
			{
				junk_mob(victim);
			}
		}

		for (obj = ch->in_room->first_content ; obj != NULL ; obj = obj_next)
		{
			obj_next = obj->next_content;
			if (obj->item_type != ITEM_CORPSE_PC)
			{
				junk_obj( obj );
			}
		}
		if (!quite)
		{
			act( "$n purges the room!", ch, NULL, NULL, TO_ROOM);
			send_to_char( "Ok.\n\r", ch );
		}
		pop_call();
		return;
	}

	if ((victim = get_char_room(ch, arg)) == NULL)
	{
		send_to_char( "They aren't here.\n\r", ch );
		pop_call();
		return;
	}

	if (!IS_NPC(victim))
	{
		send_to_char( "Not on PC's.\n\r", ch );
		pop_call();
		return;
	}

	act( "$n purges $N.", ch, NULL, victim, TO_NOTVICT );
	junk_mob(victim);
	pop_call();
	return;
}

/*
 * Advance the character level of a PC
 */
void do_advance( CHAR_DATA *ch, char *argument )
{
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	int level;
	int iLevel;

	push_call("do_advance(%p,%p)",ch,argument);

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

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

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

	if (IS_NPC(ch))
	{
		log_printf("%s tried to advance %s.", ch->name, victim->name);
		pop_call();
		return;
	}

	if (IS_NPC(victim))
	{
		send_to_char( "Not on NPC's.\n\r", ch );
		pop_call();
		return;
	}

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

	if (level > get_trust(ch))
	{
		send_to_char( "Limited to your trust level.\n\r", ch );
		pop_call();
		return;
	}

	if (!IS_GOD(ch))
	{
		send_to_char("You are not allowed to advance.\n\r",ch);
		pop_call();
		return;
	}

	if (level < victim->level)
	{
		if (IS_GOD(victim))
		{
			send_to_char("You cannot lower the level of a God.\n\r", ch);
			pop_call();
			return;
		}

		send_to_char( "Lowering a player's level!\n\r", ch );
		send_to_char( "**** OOOOHHHHHHHHHH  NNNNOOOO ****\n\r", victim );
		for (iLevel = victim->level ; iLevel > level ; iLevel--)
		{
			send_to_char( "You lose a level!!  ", victim );
			lose_level( victim, FALSE );
		}
	}
	else
	{
		send_to_char( "Raising a player's level!\n\r", ch );
		send_to_char( "**** OOOOHHHHHHHHHH  YYYYEEEESSS ****\n\r", victim );

		for (iLevel = victim->level ; iLevel < level ; iLevel++)
		{
			send_to_char( "You raise a level!!  ", victim );
			victim->level += 1;
			victim->mclass[victim->class] +=1;
			advance_level( victim, FALSE );
		}
	}
	victim->hit      = get_max_hit(victim);
	victim->move     = get_max_move(victim);
	restore_mana(victim);

	sub_player (victim);
	add_player (victim);
	save_char_obj (victim, NORMAL_SAVE);
	save_char_obj (victim, BACKUP_SAVE);

	victim->pcdata->exp = exp_level(victim,victim->level-1) + 1;
	pop_call();
	return;
}

/*
 * Refresh and heal a PC
 */
void do_restore( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	int sn;

	push_call("do_restore(%p,%p)",ch,argument);

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

	if ((victim = get_char_room(ch, argument)) == NULL)
	{
		if (!IS_NPC(ch))
		{
			send_to_char( "They aren't here.\n\r", ch );
		}
		else
		{
			log_build_printf(ch->pIndexData->vnum, "do_restore: target not found: %s", argument);
		}
		pop_call();
		return;
	}

	victim->hit  = get_max_hit(victim);
	victim->move = get_max_move(victim);
	victim->nonlethal = 0;
	restore_mana(victim);
	update_pos(victim,-1);
	if (!IS_NPC(victim))
	{
		gain_condition( victim, COND_FULL, 50 );
		gain_condition( victim, COND_THIRST, 50 );
		gain_condition( victim, COND_DRUNK, -50 );
	}
	for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
		ch->uses[sn] = 0;
	act( "$n has restored you.", ch, NULL, victim, TO_VICT );
	act( "$n has restored $N.", ch, NULL, victim, TO_NOTVICT );
	act( "You have restored $N.", ch, NULL, victim, TO_CHAR );

	pop_call();
	return;
}


/*
 * Force a fight to stop
 */
void do_peace( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *rch;

	push_call("do_peace(%p,%p)",ch,argument);

	if (*argument != '\0')
	{
		if ((rch = get_char_room_even_blinded(ch, argument)) != NULL)
		{
			char_from_combat(rch);
			free_cast(rch);
			stop_hate_fear(rch);
		}
		pop_call();
		return;
	}

	for (rch = ch->in_room->first_person ; rch ; rch = rch->next_in_room)
	{
		if (rch->in_battle)
			clean_combat(rch->in_battle);
		stop_hate_fear(rch);
		free_cast(rch);
	}

	if (!IS_NPC(ch))
	{
		act( "$n booms 'PEACE!'", ch, NULL, NULL, TO_ROOM );
		send_to_char( "You boom 'PEACE!'\n\r", ch );
	}
	pop_call();
	return;
}

/*
 * Ban a specified IP or domain from connecting
 */
void do_ban( CHAR_DATA *ch, char *argument )
{
	BAN_DATA *pban;
	char skp[80];

	push_call("do_ban(%p,%p)",ch,argument);

	if (IS_NPC(ch))
	{
		pop_call();
		return;
	}

	if (argument[0] == '\0')
	{
		send_to_char("List of banned sites:\n\r", ch);

		for (pban = mud->f_ban ; pban ; pban = pban->next)
		{
			ch_printf_color(ch, "{158}%15s {138}banned on {118}%s {138}by {128}%s\n\r",
				pban->name,
				str_resize(get_time_string(pban->date), skp, -24),
				pban->banned_by);
		}
		pop_call();
		return;
	}

	for (pban = mud->f_ban ; pban ; pban = pban->next)
	{
		if (!strcasecmp(argument, pban->name))
		{
			UNLINK(pban, mud->f_ban, mud->l_ban, next, prev);
			STRFREE(pban->name);
			STRFREE(pban->banned_by);
			save_nsites();
			send_to_char("Siteban removed.\n\r", ch );
			pop_call();
			return;
		}
	}

	ALLOCMEM(pban, BAN_DATA, 1);
	pban->name		= STRALLOC( argument );
	pban->banned_by	= STRALLOC( ch->name );
	pban->date		= mud->current_time;
	LINK(pban, mud->f_ban, mud->l_ban, next, prev);

	save_sites();

	log_printf("The site: %s has been banned by %s", argument, ch->name);

	send_to_char("Siteban set.\n\r", ch );

	pop_call();
	return;
}


/*
 * Ban an IP or domain from creating new accounts
 */
void do_nban( CHAR_DATA *ch, char *argument )
{
	BAN_DATA *pban;
	char skp[80];

	push_call("do_nban(%p,%p)",ch,argument);

	if (IS_NPC(ch))
	{
		pop_call();
		return;
	}

	if (argument[0] == '\0')
	{
		send_to_char("List of newbie banned sites:\n\r", ch);

		for (pban = mud->f_nban ; pban ; pban = pban->next)
		{
			ch_printf_color(ch, "{158}%15s {138}banned on {118}%s {138}by {128}%s\n\r",
				pban->name,
				str_resize(get_time_string(pban->date), skp, -24),
				pban->banned_by);
		}
		pop_call();
		return;
	}

	for (pban = mud->f_nban ; pban ; pban = pban->next)
	{
		if (!strcasecmp(argument, pban->name))
		{
			UNLINK(pban, mud->f_nban, mud->l_nban, next, prev);
			STRFREE(pban->name);
			STRFREE(pban->banned_by);
			save_nsites();
			send_to_char("Newbie Siteban removed.\n\r", ch );
			pop_call();
			return;
		}
	}

	ALLOCMEM(pban, BAN_DATA, 1);
	pban->name		= STRALLOC( argument );
	pban->banned_by	= STRALLOC( ch->name );
	pban->date		= mud->current_time;
	LINK(pban, mud->f_nban, mud->l_nban, next, prev);

	save_nsites();

	log_printf("The site: %s has been banned by %s", argument, ch->name);

	send_to_char("Siteban set.\n\r", ch );

	pop_call();
	return;
}

/*
 * Shut down server to all but admins
 */
void do_wizlock( CHAR_DATA *ch, char *argument )
{
	push_call("do_wizlock(%p,%p)",ch,argument);

	TOGGLE_BIT(mud->flags, MUD_WIZLOCK);

	if (IS_SET(mud->flags, MUD_WIZLOCK))
	{
		send_to_char( "Game wizlocked.\n\r", ch );
		log_printf("do_wizlock(%s) *locked*", get_name(ch));
	}
	else
	{
		send_to_char( "Game un-wizlocked.\n\r", ch );
		log_printf("do_wizlock(%s) *unlocked*", get_name(ch));
	}
	pop_call();
	return;
}


void do_sla( CHAR_DATA *ch, char *argument )
{
	push_call("do_sla(%p,%p)",ch,argument);

	send_to_char( "If you want to SLAY, spell it out.\n\r", ch );

	pop_call();
	return;
}


/*
 * Slay a character without checks or resistances
 */
void do_slay( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	char arg[MAX_INPUT_LENGTH];

	push_call("do_slay(%p,%p)",ch,argument);

	one_argument( argument, arg );
	if ( arg[0] == '\0' )
	{
		send_to_char( "Slay whom?\n\r", ch );
		pop_call();
		return;
	}

	if ((victim = get_char_room(ch, arg)) == NULL)
	{
		send_to_char( "They aren't here.\n\r", ch );
		pop_call();
		return;
	}

	if (ch == victim)
	{
		send_to_char( "Suicide is a mortal sin.\n\r", ch );
		pop_call();
		return;
	}

	if ((!IS_NPC(victim) && victim->level == MAX_LEVEL) || victim == supermob)
	{
		act( "$N laughs at your pathetic attempt to slay $M.",  ch, NULL, victim, TO_CHAR   );
		act( "You laugh at $n's pathetic attempt to slay you.", ch, NULL, victim, TO_VICT   );
		act( "$N laughs at $n's pathetic attempt to slay $M.",  ch, NULL, victim, TO_NOTVICT);
		pop_call();
		return;
	}

	act( "You slay $M in cold blood!",  ch, NULL, victim, TO_CHAR   );
	act( "$n slays you in cold blood!", ch, NULL, victim, TO_VICT   );
	act( "$n slays $N in cold blood!",  ch, NULL, victim, TO_NOTVICT);

	raw_kill(victim, -1);

	stop_hate_fear(ch);

	pop_call();
	return;
}



/*
	Thanks to Grodyn for pointing out bugs in this function.
*/
void do_force( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	char buf[MAX_INPUT_LENGTH];

	push_call("do_force(%p,%p)",ch,argument);

	argument = one_argument( argument, arg );

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

	str_cpy_max(buf, argument, 80);

	if (!strcasecmp(arg, "all"))
	{
		PLAYER_GAME *vch, *vch_next;

		for (vch = mud->f_player ; vch ; vch = vch_next)
		{
			vch_next = vch->next;

			if (vch->ch != ch)
			{
				if (get_trust(vch->ch) < get_trust(ch))
				{
					act( "$n forces you to '$t'.", ch, argument, vch->ch, TO_VICT);
					interpret( vch->ch, buf );
				}
			}
		}
	}
	else
	{
		CHAR_DATA *victim;

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

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

		if (IS_NPC(victim) && ch->level < LEVEL_IMMORTAL && !IS_SET(mud->flags, MUD_EMUD_REALGAME))
		{
			send_to_char( "You can't force a mobile.\n\r", ch );
			pop_call();
			return;
		}

		if (!IS_NPC(victim) && victim->level >= ch->level)
		{
			send_to_char( "Do it yourself!\n\r", ch );
			pop_call();
			return;
		}

		act( "$n forces you to '$t'.", ch, argument, victim, TO_VICT );
		interpret( victim, buf );
	}
	send_to_char( "Ok.\n\r", ch );
	pop_call();
	return;
}

/*
 * Makes a GM invisible to players and lower level admins
 */
void do_invis( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;
	PLAYER_GAME *gpl;

	push_call("do_invis(%p,%p)",ch,argument);

	if (IS_NPC(ch))
	{
		pop_call();
		return;
	}

	if (ch->level < MAX_LEVEL || *argument == '\0')
	{
		victim = ch;
	}
	else if ((victim = get_player_world(ch, argument)) == NULL)
	{
		victim = ch;
	}
	if (IS_SET(victim->act, PLR_WIZINVIS) )
	{
		act( "$n slowly fades into existence.", victim, NULL, NULL, TO_ROOM );
		send_to_char( "You slowly fade back into existence.\n\r", victim);
	}
	else
	{
		for (gpl = mud->f_player ; gpl ; gpl = gpl->next)
		{
			if (gpl->ch->pcdata->reply == victim)
			{
				gpl->ch->pcdata->reply = NULL;
			}
		}
		act( "$n slowly fades into thin air.", victim, NULL, NULL, TO_ROOM );
		send_to_char( "You slowly vanish into thin air.\n\r", victim );
	}
	TOGGLE_BIT(victim->act, PLR_WIZINVIS);

	pop_call();
	return;
}

/*
 * Makes a GM invisible to players and the system
 */
void do_cloak( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;

	push_call("do_cloak(%p,%p)",ch,argument);

	if (IS_NPC(ch))
	{
		pop_call();
		return;
	}

	if (ch->level < MAX_LEVEL || *argument == '\0')
	{
		victim = ch;
	}
	else if ((victim = get_player_world(ch, argument)) == NULL)
	{
		victim = ch;
	}

	if (IS_SET(victim->act, PLR_WIZCLOAK))
	{
		act( "$n slowly fades into existence.", victim, NULL, NULL, TO_ROOM);
		send_to_char( "You slowly fade back into existence.\n\r", victim);
	}
	else
	{
		act( "$n slowly fades into thin air.", victim, NULL, NULL, TO_ROOM );
		send_to_char( "You slowly vanish into thin air.\n\r", victim );
	}
	TOGGLE_BIT(victim->act, PLR_WIZCLOAK);

	pop_call();
	return;
}

/*
 * Enables god mode for GMs
 */
void do_holylight( CHAR_DATA *ch, char *argument )
{
	push_call("do_holylight(%p,%p)",ch,argument);

	if (IS_NPC(ch))
	{
		pop_call();
		return;
	}

	if (IS_SET(ch->act, PLR_HOLYLIGHT))
	{
		send_to_char( "Holy light mode off.\n\r", ch );
	}
	else
	{
		send_to_char( "Holy light mode on.\n\r", ch );
	}
	TOGGLE_BIT(ch->act, PLR_HOLYLIGHT);

	pop_call();
	return;
}

/*
 * add or remove an exit to another room VNUM
 */
void do_connect( CHAR_DATA *ch, char *argument )
{
	int dest_vnum;
	int door;
	EXIT_DATA * pExit;
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	char arg3 [MAX_INPUT_LENGTH];

	push_call("do_connect(%p,%p)",ch,argument);

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

	if (arg1[0] == '\0' || arg2[0] == '\0')
	{
		send_to_char("Syntax: connect <direction> <vnum|remove> [both]\n\r", ch);
		pop_call();
		return;
	}

	if (!IS_NPC(ch) && !can_olc_modify(ch, ch->in_room->vnum))
	{
		send_to_char("This room is not in your allocated range.\n\r", ch);
		pop_call();
		return;
	}

	door  = direction_door(arg1);

	if (door < 0 || door > 5 )
	{
		if (IS_NPC(ch))
		{
			log_printf( "[%u] Invalid direction: <connect %s %s>", ch->pIndexData->vnum, arg1, arg2 );
		}
		send_to_char( "Invalid direction.\n\r",ch);
		pop_call();
		return;
	}
	
	if (!strcasecmp(arg2, "remove"))
	{
		if ((pExit = ch->in_room->exit[door]) == NULL)
		{
			if (IS_NPC(ch))
			{
				log_printf( "[%u] Invalid direction: <connect %s %s>", ch->pIndexData->vnum, arg1, arg2 );
			}
			send_to_char( "No exit in that direction.\n\r",ch);
			pop_call();
			return;
		}
		dest_vnum = pExit->to_room;

		delete_exit(room_index[dest_vnum], rev_dir[door]);
		delete_exit(ch->in_room, door);

		pop_call();
		return;
	}

	dest_vnum = atol( arg2 );

	if (get_room_index(dest_vnum) == NULL && dest_vnum != -1)
	{
		if (IS_NPC(ch))
		{
			log_printf( "[%u] Invalid destination vnum: <connect %s %s>", ch->pIndexData->vnum, arg1, arg2 );
		}
		send_to_char( "A room with that vnum does not exist.\n\r",ch);
		pop_call();
		return;
	}

	if (!IS_NPC(ch) && dest_vnum != -1 && !can_olc_modify(ch, dest_vnum))
	{
		ch_printf_color(ch, "That vnum is not in your allocated range.\n\r");
		pop_call();
		return;
	}

	set_exit(ch->in_room->vnum, door, dest_vnum);

	if (!strcasecmp(arg3, "both"))
	{
		set_exit( dest_vnum, rev_dir[door], ch->in_room->vnum);
	}
	pop_call();
	return;
}

extern void ListCheck(void);


void do_test1( CHAR_DATA *ch, char *argument )
{
	log_printf("do_test1(%p,%p)",ch,argument);

	send_to_char( "Siteban saving.\n\r", ch );
	save_sites();
}


/*
 * This function needs to be updated to support
 * d20 NPC specs, as it is it should NOT be used - Kregor
 */
void do_rescale( CHAR_DATA *ch, char *argument )
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	char arg3 [MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	CHAR_DATA *mch;
	int scale, divisor;

	lg_int temp_gold;

	push_call("do_rescale(%p,%p)",ch,argument);

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

	/*
	 * Took out global rescale, made single mob only - Kregor
	 */
	if (arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0')
	{
		send_to_char( "Syntax: rescale <mobName> <player> <percentage>\n\r", ch);
		pop_call();
		return;
	}

	if ((mch = get_char_room(ch, arg1)) == NULL)
	{
		send_to_char("They aren't here.\n\r", ch);
		pop_call();
		return;
	}
	if (!IS_NPC(mch))
	{
		send_to_char("You can only rescale mobiles.\n\r",ch);
		pop_call();
		return;
	}
	if ((victim = get_player_world_even_blinded(arg2)) == NULL)
	{
		send_to_char("They aren't here.\n\r", ch);
		pop_call();
		return;
	}
	if (IS_NPC(victim))
	{
		send_to_char("You can only rescale mobs on players.\n\r",ch);
		pop_call();
		return;
	}
	scale						= atol(arg3) * victim->level;
	divisor					= 200 * (100-victim->level) + 10000;

	temp_gold				= mch->pIndexData->gold;
	mch->gold				= temp_gold * scale / divisor;
	mch->level			= UMAX(1, mch->pIndexData->level * scale / 10000);

	mch->max_hit 		= mch->pIndexData->hitplus + dice(mch->level, mch->pIndexData->hitsizedice);
	mch->hit				= get_max_hit(mch);

	pop_call();
	return;
}

/*
 * Set values and flags for an exit
 */
void do_door( CHAR_DATA *ch, char *argument )
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	char arg3 [MAX_INPUT_LENGTH];
	int door, value;
	EXIT_DATA *pExit;

	push_call("do_door(%p,%p)",ch,argument);

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

	if (arg1[0] == '\0' || arg2[0] == '\0')
	{
		send_to_char( "Syntax: doorset <direction> <field> <argument>\n\r",ch );
		send_to_char( "Field being one of:  \n\r  desc name flag key\n\r",ch );
		pop_call();
		return;
	}

	door = direction_door(arg1);

	if (!can_olc_modify(ch, ch->in_room->vnum))
	{
		send_to_char( "This room is out of your assigned vnum range.\n\r", ch );
		pop_call();
		return;
	}
	if (door < 0)
	{
		door = atol(arg1);
	}
	if (door < 0 || door > 5)
	{
		send_to_char ("Invalid exit direction.\n\r",ch);
		pop_call();
		return;
	}

	if ((pExit = ch->in_room->exit[door]) == NULL)
	{
		send_to_char( "There is no exit in that direction.\n\r", ch);
		pop_call();
		return;
	}

	if ( !strcasecmp( arg2, "flag" ) )
	{
		if ((value = get_flag(arg3, exit_flags)) == -1)
		{
			if (IS_NPC(ch))
				log_build_printf(ch->pIndexData->vnum, "doorset: invalid flag: %s", arg3);
			else
				ch_printf_color(ch, "Syntax: flag <%s>\n\r", give_flags(exit_flags));
			pop_call();
			return;
		}
		TOGGLE_BIT(pExit->exit_info, 1LL << value);
		pop_call();
		return;
	}
	else if (!strcasecmp(arg2, "name"))
	{
		pExit->keyword = STRALLOC(arg3);
	}
	else if (!strcasecmp(arg2, "desc"))
	{
		pExit->description = STRALLOC(arg3);
	}
	else if (!strcasecmp(arg2, "key"))
	{
		pExit->key = atol(arg3);
	}
	pop_call();
	return;
}


/*
 * Advance the game by as many cycles as specified
 */
void do_tick( CHAR_DATA *ch, char *argument)
{
	int cnt, ticks;
	char arg1[MAX_INPUT_LENGTH];
	DESCRIPTOR_DATA *d;

	push_call("do_tick(%p,%p)",ch,argument);

	argument = one_argument(argument, arg1);
	
	if (!is_number(arg1) || argument[0] == '\0')
	{
		send_to_char("Tick how many minutes|hours?.\n\r", ch);
		pop_call();
		return;
	}
	ticks = atol(arg1);

	for (d = mud->f_desc ; d ; d = d->next)
	{
		if (is_desc_valid(d->character) && (d->connected == CON_PLAYING || d->connected == CON_EDITING))
		{
			if ((!IS_NPC(d->character) && (d->character->level == MAX_LEVEL) && (ch != NULL)))
			{
				ch_printf_color(d->character, "{178}[{078}%s{178}]\n\r", ch->name);
			}
			ch_printf_color(d->character, "{138}%s\n\r", ansi_justify("Time seems to freeze momentarily, as it warps forward!", get_page_width(d->character)));
		}
	}

	if (!strcasecmp(argument, "minute") || !strcasecmp(argument, "minutes"))
	{
		for (cnt = 0 ; cnt < ticks * PULSE_TICK ; cnt++)
		{
			update_handler();
		}
		for (d = mud->f_desc ; d ; d = d->next)
		{
			if (is_desc_valid(d->character) && (d->connected == CON_PLAYING || d->connected == CON_EDITING))
			{
				ch_printf_color(d->character, "Time advances %d mud %s.\n\r", ticks, short_to_name("minute", ticks));
			}
		}
	}
	if (!strcasecmp(argument, "hour") || !strcasecmp(argument, "hours"))
	{
		ticks = 1; // because ticking too many hours causes shutdown due to time lag
		for (cnt = 0 ; cnt < ticks * PULSE_TIME ; cnt++)
		{
			update_handler();
		}
		for (d = mud->f_desc ; d ; d = d->next)
		{
			if (is_desc_valid(d->character) && (d->connected == CON_PLAYING || d->connected == CON_EDITING))
			{
				ch_printf_color(d->character, "Time advances %d mud %s.\n\r", ticks, short_to_name("hour", ticks));
			}
		}
	}

	pop_call();
	return;
}

/*
 * Destroy a player or clan irrevocably
 */
void do_destroy( CHAR_DATA *ch, char * arg )
{
	char arg1[MAX_INPUT_LENGTH];
	CHAR_DATA *victim;

	push_call("do_destroy(%p,%p)",ch,arg);

	arg = one_argument(arg, arg1);

	if (!IS_GOD(ch))
	{
		log_printf("do_destroy [%s]: non-GM attempt!", ch->name);
		dump_stack();
		pop_call();
		return;
	}

	if (arg[0] == '\0')
	{
		send_to_char("Syntax: destroy <clan|player> <name>\n\r", ch );
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "clan"))
	{
		CLAN_DATA *clan;
		char buf[MAX_INPUT_LENGTH];

		if ((clan = get_clan(arg)) == NULL)
		{
			send_to_char( "That clan does not exist!\n\r", ch );
			pop_call();
			return;
		}

		if (ch->level < MAX_LEVEL)
		{
			send_to_char( "You are not allowed to destroy clans.\n\r", ch );
			pop_call();
			return;
		}
		sprintf(buf, "The clan of %s has been disbanded by the gods!", clan->name);
		do_echo(NULL, buf);

		destroy_clan(clan);

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "player"))
	{
		if ((victim = get_player_world(ch, arg)) == NULL)
		{
			send_to_char("Hmmm...can't find them.\n\r", ch);
			pop_call();
			return;
		}

		if (IS_GOD(victim))
		{
			send_to_char( "You cannot destroy gods.\n\r", ch);
			pop_call();
			return;
		}

		sprintf(arg1, "%s has sent %s's soul to oblivion.", get_name(ch), victim->name);
		do_echo(ch, arg1);

		delete_player(victim);

		pop_call();
		return;
	}
	do_destroy(ch, "");
	pop_call();
	return;
}

/*
 * Remove mprogs for an NPC or item
 */
void do_shutoff( CHAR_DATA *ch, char *argument )
{
	char arg[MAX_INPUT_LENGTH];
	OBJ_INDEX_DATA *obj;
	MOB_INDEX_DATA *mob;

	push_call("do_shutoff(%p,%p)",ch,argument);

	argument = one_argument(argument, arg);

	if (argument[0] == '\0' || arg[0] == '\0')
	{
		send_to_char( "Syntax: prog shutoff <mob|obj> <vnum>\n\r", ch );
		pop_call();
		return;
	}

	if (!can_olc_modify(ch, atoi(argument)))
	{
		ch_printf_color(ch, "That vnum is not in your allocated range.\n\r");
	}
	else if (!strcasecmp(arg, "obj"))
	{
		if ((obj = get_obj_index(atoi(argument))) != NULL)
		{
			ch_printf_color(ch, "Oprog index for obj %u erased.\n\r", obj->vnum);
			obj->progtypes = 0;
		}
		else
		{
			ch_printf_color(ch, "There no such object.\n\r");
		}
	}
	else if (!strcasecmp(arg, "mob"))
	{
		if ((mob = get_mob_index(atoi(argument))) != NULL)
		{
			ch_printf_color(ch, "Mprog index for mob %u erased.\n\r", mob->vnum);
			mob->progtypes = 0;
		}
		else
		{
			ch_printf_color(ch, "There is no such mobile.\n\r");
		}
	}
	else
	{
		do_shutoff(ch, "");
	}
	pop_call();
	return;
}


/*
 * Load up a PC whose not logged in
 */
void do_pload( CHAR_DATA *ch, char *argument)
{
	CHAR_DATA *fch;
	DESCRIPTOR_DATA *d;
	bool exists, fLoaded;

	push_call("do_pload(%p,%p)",ch,argument);

	if (*argument == '\0')
	{
		send_to_char( "Load what character?\n\r", ch );
		pop_call();
		return;
	}

	if (!check_parse_name(argument, FALSE))
	{
		send_to_char( "Either you chose a name with less than 3 characters, with a non-ascii character,\n\ror it was the name of a monster.\n\rIllegal name, try another.\n\r", ch );
		pop_call();
		return;
	}

	fch = lookup_char( argument );

	if (fch != NULL)
	{
		send_to_char( "This character is already loaded.\n\r", ch );
		pop_call();
		return;
	}
	
	if ((fch = start_partial_load(ch, argument)) == NULL)
	{
		send_to_char("There is no player by that name.\n\r", ch);
		pop_call();
		return;
	}
	else
	{
		fLoaded = TRUE;
	}

	if (!strcasecmp(fch->pcdata->account, ch->pcdata->account))
	{
		send_to_char("You cannot load one of your own characters!\n\r", ch);
		if (fLoaded)
			clear_partial_load(fch);
		pop_call();
		return;
	}

	if (fLoaded)
		clear_partial_load(fch);

	for (d = mud->f_desc ; d ; d = d->next)
	{
		if (is_desc_valid(d->character))
		{
			if (!strcasecmp(argument, d->character->name))
			{
				act( "$E was in the process of logging on. You close $S session.", ch, NULL, d->character, TO_CHAR);
				close_socket( d, TRUE);
			}
		}
	}

	ALLOCMEM(d, DESCRIPTOR_DATA, 1);
	d->original	= NULL;
	d->descriptor	= -998;  /* Special case for pload loads */
	exists		= load_char_obj( d, argument );
	fch			= d->character;
		
	if (!exists)
	{
		ch_printf_color(ch, "The character named '%s' cannot be found.\n\r", argument);

		if (d != NULL)
		{
			d->character = NULL;
			d->original  = NULL;
		}
		if (fch != NULL)
		{
			fch->desc = NULL;
			extract_char(fch);
		}
		if (d != NULL)
		{
			FREEMEM(d);
		}
		pop_call();
		return;
	}

	d->connected = CON_PLAYING;
	add_char(fch);
	add_player(fch);
	fch->desc = NULL;

	if (fch->in_room != NULL)
	{
		char_to_room( fch, fch->in_room->vnum, FALSE );
	}
	else
	{
		char_to_room( fch, ch->in_room->vnum, FALSE );
	}
	send_to_char( "You load the character.\n\r", ch );

	enter_game(fch);

	d->character = NULL;
	d->original  = NULL;

	FREEMEM(d);

	pop_call();
	return;
}


/*
 * Force a player to logoff
 */
void do_pquit( CHAR_DATA *ch, char *argument )
{
	CHAR_DATA *victim;

	push_call("do_pquit(%p,%p)",ch,argument);

	if (*argument == '\0')
	{
		send_to_char( "Force quit what character?\n\r", ch );
		pop_call();
		return;
	}

	if ((victim = get_player_world(ch, argument)) == NULL)
	{
		send_to_char( "That player does not exist in the realm.\n\r", ch );
		pop_call();
		return;
	}

	if (IS_NPC(victim))
	{
		send_to_char( "You are trying to pquit a mobile!\n\r", ch);
		pop_call();
		return;
	}

	if (victim->level >= ch->level && is_desc_valid(victim))
	{
		send_to_char( "You cannot force that player to quit.\n\r", ch);
		pop_call();
		return;
	}

	ch_printf_color(ch, "You forced %s to quit.\n\r", victim->name);
	do_quit(victim, NULL);

	pop_call();
	return;
}

/*
 * Reset a player's password
 */
void do_fixpass (CHAR_DATA* ch, char* argument)
{
	CHAR_DATA *victim;
	char arg1[MAX_INPUT_LENGTH];
	char arg2[MAX_INPUT_LENGTH];
	char arg3[MAX_INPUT_LENGTH];

	push_call("do_fixpass(%p,%p)",ch,argument);

	/*
		one_argument smashes case, using one_argument_nolower - Scandum
	*/

	argument = one_argument_nolower(argument, arg1);
	argument = one_argument_nolower(argument, arg2);
	argument = one_argument_nolower(argument, arg3);

	if (arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0')
	{
		send_to_char( "Syntax: fixpass <character> <new pass> <new pass>.\n\r", ch );
		pop_call();
		return;
	}

	if ((victim = get_player_world(ch, arg1)) == NULL)
	{
		send_to_char( "They aren't here (better pload them).\n\r", ch );
		pop_call();
		return;
	}

	if (victim->level > ch->level)
	{
		send_to_char( "You may not fix the password of higher level players.\n\r", ch );
		pop_call();
		return;
	}

	if (strcmp(arg2, arg3))
	{
		send_to_char( "The new password does not verify.\n\rPlease try again.\n\r", ch);
		pop_call();
		return;
	}

	if (!is_valid_password(arg2))
	{
		send_to_char("New password not acceptable, try again.\n\r", ch );
		pop_call();
		return;
	}

	if (!victim->desc || !victim->desc->account)
		victim->pcdata->password = encrypt64(arg2);
	else
		victim->desc->account->password = encrypt64(arg2);

	save_char_obj(victim, NORMAL_SAVE);
	ch_printf_color(ch, "Ok. %s has had their password changed.\n\r", victim->name );

	pop_call();
	return;
}


/* RECOVER command.  Restore a player's backup file.  Presto 8/98 */

void do_recover(CHAR_DATA *ch, char *argument)
{
	char arg[MAX_INPUT_LENGTH];
	char back_name[MAX_STRING_LENGTH], real_name[MAX_STRING_LENGTH];
	char victimname[MAX_STRING_LENGTH];
	int  i, length;
	CHAR_DATA *victim;
	FILE *back_file, *real_file;

	push_call("do_recover(%p,%p)",ch,argument);

	if (ch->level < MAX_LEVEL)
	{
		send_to_char("You may not do that.\n\r", ch);
		pop_call();
		return;
	}

	argument = one_argument(argument, arg);

	if (*arg == '\0')
	{
		send_to_char("Usage: recover <name>\n\r", ch);
		pop_call();
		return;
	}

	/* See if they're logged in. */

	if ((victim = get_player_world(ch, arg)) == NULL)
	{
		/* They aren't logged in. */
	}
	else
	{
		if (victim == ch)
		{
			send_to_char("You may not recover yourself.\n\r", ch);
			pop_call();
			return;
		}
		if (IS_NPC(victim))
		{
			send_to_char("You may not recover a mob.\n\r", ch);
			pop_call();
			return;
		}

		char_from_room(victim);
		char_to_room(victim, ROOM_VNUM_TEMPLE, TRUE);
		send_to_char("Your backup file is being restored. Quitting...\n\r", victim);
		send_to_char("Logging out player...\n\r", ch);
		strcpy(arg, victim->name);
		do_quit(victim, NULL);
	}

	/* See if the backup pfile exists. */

	strcpy(victimname, capitalize_name(arg));
	length = strlen(victimname);

	for (i = 1 ; i < length ; i++)
	{
		victimname[i] = tolower(victimname[i]);
	}


	sprintf(back_name, "%s/%c/del/%s", PLAYER_DIR, tolower(victimname[0]), victimname);

	if ((back_file = my_fopen(back_name, "r", FALSE)) == NULL)
	{
		sprintf(back_name, "%s/%c/bak/%s", PLAYER_DIR, tolower(victimname[0]), victimname);

		if ((back_file = my_fopen(back_name, "r", FALSE)) == NULL)
		{
			send_to_char("Could not open player's backup file.\n\r", ch);

			pop_call();
			return;
		}
	}
	send_to_char("Player's backup file is open...\n\r", ch);
		
	sprintf(real_name, "%s/%c/%s", PLAYER_DIR, tolower(victimname[0]), victimname);

	if ((real_file = my_fopen(real_name, "w", FALSE)) == NULL)
	{
		send_to_char("Could not open player's real file.\n\r", ch);
		my_fclose(back_file);

		pop_call();
		return;
	}
	else
	{
		send_to_char("Player's real file is open...\n\r", ch);
	}
	i = fgetc(back_file);

	while (i != EOF)
	{
		fprintf(real_file, "%c", i);
		i = fgetc(back_file);
	}

	my_fclose(real_file);
	my_fclose(back_file);

	remove(back_name);

	send_to_char("Recover was successful.\n\r", ch);

	pop_call();
	return;
}

char *quest_bits_to_string( unsigned char *pt)
{
	static char quest_bit_buf[100];
	sh_int cnt;

	push_call("quest_bits_to_string(%p)",pt);

	quest_bit_buf[0] = '\0';

	for (cnt = MAX_QUEST_BYTES-1 ; cnt >= 0 ; cnt--)
	{
		if (pt != NULL)
		{
			cat_sprintf(quest_bit_buf, "%02X", *(pt+cnt));
		}
		else
		{
			strcat(quest_bit_buf, "00" );
		}

		if (cnt % 2 == 0 && cnt > 0)
		{
			strcat(quest_bit_buf, "-");
		}
	}
	pop_call();
	return( quest_bit_buf );
}

bool is_quest( register unsigned char *pt )
{
	bool cnt;

	push_call("is_quest(%p)",pt);

	if (pt == NULL)
	{
		pop_call();
		return( FALSE );
	}

	for (cnt = 0 ; cnt < MAX_QUEST_BYTES ; cnt++)
	{
		if (*(pt+cnt) != 0)
		{
			pop_call();
			return( TRUE );
		}
	}
	pop_call();
	return( FALSE );
}

/*
 * Set administrator functions for a player account - Kregor
 */
void do_setfunc(CHAR_DATA *ch, char *argument)
{
	CHAR_DATA *victim;
	char arg[MAX_INPUT_LENGTH];
	char colc[10], colw[10], colW[10];
	int value;

	push_call("do_setfunc(%p,%p)",ch,argument);

	argument = one_argument(argument,arg);

	if (!IS_GOD(ch))
	{
		send_to_char("You cannot set player functions.\n\r",ch);
		pop_call();
		return;
	}
	
	strcpy(colc, get_color_string(ch, COLOR_ACCENT, VT102_DIM));
	strcpy(colw, get_color_string(ch, COLOR_TEXT, VT102_DIM));
	strcpy(colW, get_color_string(ch, COLOR_TEXT, VT102_BOLD));

	if (arg[0] == '\0')
	{
		ch_printf_color(ch, "%sSyntax: setfunc <player> <function>.\n\r", colw);
		ch_printf_color(ch, "%sValid functions:\n\r", colc);
		ch_printf_color(ch, "%s  <%s>\n\r", colw, give_flags(function_flags));
		pop_call();
		return;
	}

	if ((victim = get_player_world(ch, arg)) == NULL)
	{
		send_to_char("That person is not logged on currently.\n\r",ch);
		pop_call();
		return;
	}
	
	if (IS_NPC(victim))
	{
		send_to_char("Not on NPCs.\n\r",ch);
		pop_call();
		return;
	}
	
	if (victim->desc == NULL)
	{
		send_to_char("For some reason, that player has no descriptor.\n\r",ch);
		pop_call();
		return;
	}
	
	if (victim->desc->account == NULL)
	{
		send_to_char("For some reason, that player has no account.\n\r",ch);
		pop_call();
		return;
	}
	
	if (argument[0] == '\0')
	{
		ch_printf_color(ch, "%s%s's current functions: %s%s\n\r", 
				colc, get_name(victim), colW, flag_string(victim->desc->account->functions, function_flags));
		pop_call();
		return;
	}

	if ((value = get_flag(argument, function_flags)) == -1)
	{
		do_setfunc(ch, "");
	}
	else
	{
		TOGGLE_BIT(victim->desc->account->functions, 1 << value);
		do_setfunc(ch, get_name(victim));
	}

	pop_call();
	return;
}


/*
 * Manually set values and flags on an object instance
 */
void do_oset( CHAR_DATA *ch, char *argument )
{
	char arg1 [MAX_INPUT_LENGTH];
	OBJ_DATA *obj;
	CHAR_DATA *victim;

	push_call("do_oset(%p,%p)",ch,argument);

	if (!argument || argument[0] == '\0')
	{
		send_to_char("No argument for do_oset.\n\r", ch);
		pop_call();
		return;
	}
	if (IS_NPC(ch))
	{
		log_build_printf(ch->pIndexData->vnum, "trying to use oset instead of mposet.");
		send_to_char("mobiles use mposet instead.\n\r", ch);
		pop_call();
		return;
	}
	
	argument = one_argument( argument, arg1 );
	
	if (!strcasecmp(arg1, "on"))
	{
		argument = one_argument( argument, arg1 );
		if ((victim = get_char_room(ch, arg1)) == NULL)
		{
			ch_printf_color(ch, "They're not here.\n\r");
			pop_call();
			return;
		}
		argument = one_argument( argument, arg1 );
		{
			if ((obj = get_obj_carry(victim, arg1)) == NULL)
			{
				if ((obj = get_obj_wear(victim, arg1)) == NULL)
				{
					ch_printf_color(ch, "They're not carrying that.\n\r");
					pop_call();
					return;
				}
			}
		}
	}
	else if ((obj = get_obj_here(ch, arg1)) == NULL)
	{
		ch_printf_color(ch, "Object not found.\n\r");
		pop_call();
		return;
	}
	oset_obj(ch, obj, argument, FALSE);
	pop_call();
	return;
}


/*
 * Core function for oset used in both oset and mposet - Kregor
 */
void oset_obj( CHAR_DATA *ch, OBJ_DATA *obj, char *argument, bool mpcommand )
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	int value;

	push_call("do_oset(%p,%p)",ch,argument);

	if (!mpcommand)
		log_god_printf("OSET %s: oset %s %s", ch->name, obj->name, argument);

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

	if (arg1[0] == '\0' || arg2[0] == '\0' )
	{
		if (IS_NPC(ch))
		{
			log_build_printf(ch->pIndexData->vnum, "bad parameters <mposet %s %s %s>", obj->name, arg1, arg2);
		}
		else
		{
			ch_printf_color(ch, "Syntax: oset <field> <argument>\n\r");
			ch_printf_color(ch, "  Field being one of:\n\r");
			ch_printf_color(ch, "    v0 v1 v2 v3 v4 v5 v6 v7 name short long desc\n\r");
			ch_printf_color(ch, "    flags wear material level weight cost\n\r");
			ch_printf_color(ch, "    timer sactimer quest randquest   \n\r");
		}
		pop_call();
		return;
	}

	value = atol(arg2);

	if ( !strcasecmp( arg1, "capacity" ) )
	{
		switch(obj->item_type)
		{
			case ITEM_SHEATH:
			case ITEM_CART:
			case ITEM_CONTAINER:
			case ITEM_QUIVER:
			case ITEM_SPELLPOUCH:
				break;
			default:
				pop_call();
				return;
		}
		obj->value[0] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "cflags" ) )
	{
		switch(obj->item_type)
		{
			case ITEM_SHEATH:
			case ITEM_CART:
			case ITEM_CONTAINER:
			case ITEM_QUIVER:
			case ITEM_SPELLPOUCH:
				break;
			default:
				pop_call();
				return;
		}
		if ((value = get_flag(arg2, cont_flags)) == -1)
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "Syntax: cflags <%s>\n\r", give_flags(cont_flags));
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: invalid cflag %s", arg2);
			pop_call();
			return;
		}
		obj->hit_points = obj->hit_points * value / 100;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "charges" ) )
	{
		switch(obj->item_type)
		{
			case ITEM_WAND:
			case ITEM_STAFF:
				break;
			default:
				pop_call();
				return;
		}
		obj->value[1] = UMIN(value, obj->value[2]);
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "condition" ) )
	{
		if (value < 1 || value > 100)
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "Value must be between 1 and 100 percent.");
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: condition not between 1 and 100");
			pop_call();
			return;
		}
		obj->hit_points = obj->hit_points * value / 100;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "cost" ) )
	{
		obj->cost = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "desc" ) )
	{
		STRFREE (obj->description);
		if (!strcasecmp( arg2, "reset") )
		{
			obj->description = STRALLOC(obj->pIndexData->description);
		}
		else
		{
			obj->description = STRALLOC( arg2 );
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "flags" ) )
	{
		if ((value = get_flag(arg2, o_flags)) == -1)
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "Syntax: flags <%s>\n\r", give_flags(o_flags));
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: invalid flag %s", arg2);
			pop_call();
			return;
		}
		TOGGLE_BIT(obj->extra_flags, 1LL << value);
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "hitpts" ) )
	{
		obj->hit_points = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "identify" ) )
	{
		STRFREE (obj->id_descr);
		if( !strcasecmp( arg2, "null") )
		{
			obj->id_descr[0] = '\0';
		}
		else
		{
			obj->id_descr  = STRALLOC( arg2 );
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "key" ) )
	{
		switch(obj->item_type)
		{
			case ITEM_SHEATH:
			case ITEM_CART:
			case ITEM_CONTAINER:
			case ITEM_QUIVER:
			case ITEM_SPELLPOUCH:
				break;
			default:
				pop_call();
				return;
		}
		if (get_obj_index(value) == NULL)
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "That key does not exist.\n\r", give_flags(cont_flags));
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: invalid key %d", value);
			pop_call();
			return;
		}
		obj->value[2] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "level" ) )
	{
		obj->level = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "long" ) )
	{
		STRFREE (obj->long_descr );
		if (!strcasecmp( arg2, "reset"))
		{
			obj->long_descr = STRALLOC(obj->pIndexData->long_descr);
		}
		else
		{
			obj->long_descr = STRALLOC( arg2 );
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "mark" ) )
	{
		CHAR_DATA *victim;

		if ((victim = get_char_room_even_blinded(ch, arg2)) == NULL)
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "That person can't be found.\n\r", give_flags(material_types));
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: NULL victim", arg2);
			pop_call();
			return;
		}
		obj->owned_by = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "material" ) )
	{
		if ((value = get_flag(arg2, material_types)) == -1)
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "Syntax: material <%s>\n\r", give_flags(material_types));
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: invalid material %s", arg2);
			pop_call();
			return;
		}
		obj->material = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "name" ) )
	{
		STRFREE (obj->name );
		if( !strcasecmp( arg2, "reset") )
		{
			obj->name = STRALLOC(obj->pIndexData->name);
		}
		else
		{
			obj->name  = STRALLOC( arg2 );
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "quest" ) )
	{
		int firstBit,len;

		if (sscanf(arg2,"%d %d %d",&firstBit,&len,&value)!=3)
		{
			ch_printf_color(ch, "Bad parameters <set obj quest %s>", arg2);
			pop_call();
			return;
		}
		set_quest_bits( &obj->obj_quest, firstBit, len, value);

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "randquest" ) )
	{
		int firstBit,len;

		if(sscanf(arg2,"%d %d",&firstBit,&len)!=2)
		{
			ch_printf_color(ch, "Bad parameters <set obj randquest %s>", arg2);
			pop_call();
			return;
		}
		value = number_bits( len );
		set_quest_bits( &obj->obj_quest, firstBit, len, value);

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "sactimer" ) )
	{
		obj->sac_timer = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "short" ) )
	{
		STRFREE (obj->short_descr );
		if( !strcasecmp( arg2, "reset") )
		{
			obj->short_descr = STRALLOC(obj->pIndexData->short_descr);
		}
		else
		{
			obj->short_descr = STRALLOC( arg2 );
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "size" ) )
	{
		if ((value = get_flag(arg2, size_types)) == -1)
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "Syntax: size <%s>\n\r", give_flags(size_types));
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: invalid size %s", arg2);
			pop_call();
			return;
		}
		obj->size = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "slevel" ) )
	{
		switch(obj->item_type)
		{
			case ITEM_WAND:
			case ITEM_STAFF:
				break;
			default:
				pop_call();
				return;
		}
		obj->value[0] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "spell" ) )
	{
		if ((value = skill_lookup(arg2)) == -1 || !is_spell(value))
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "Not a valid spell\n\r");
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: invalid spell %s", arg2);
			pop_call();
			return;
		}
		switch(obj->item_type)
		{
			case ITEM_WAND:
			case ITEM_STAFF:
				obj->value[3] = value;
				break;
			case ITEM_SCROLL:
			case ITEM_PILL:
			case ITEM_POTION:
				obj->value[1] = value;
				break;
			default:
				if (!IS_NPC(ch))
					ch_printf_color(ch, "Not a valid item.\n\r");
				else
					log_build_printf(ch->pIndexData->vnum, "oset_obj: invalid item type for spell.");
				break;
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "timer" ) )
	{
		obj->timer = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "type" ) )
	{
		if ((value = get_flag(arg2, o_types)) == -1)
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "Syntax: type <%s>\n\r", give_flags(o_types));
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: invalid item_type %s", arg2);
			pop_call();
			return;
		}
		obj->item_type = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "value0" ) || !strcasecmp( arg1, "v0" ) )
	{
		obj->value[0] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "value1" ) || !strcasecmp( arg1, "v1" ) )
	{
		obj->value[1] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "value2" ) || !strcasecmp( arg1, "v2" ) )
	{
		obj->value[2] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "value3" ) || !strcasecmp( arg1, "v3" ) )
	{
		obj->value[3] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "value4" ) || !strcasecmp( arg1, "v4" ) )
	{
		obj->value[4] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "value5" ) || !strcasecmp( arg1, "v5" ) )
	{
		obj->value[5] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "value6" ) || !strcasecmp( arg1, "v6" ) )
	{
		obj->value[6] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "value7" ) || !strcasecmp( arg1, "v7" ) )
	{
		obj->value[7] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "weapontype" ) )
	{
		if ((value = get_flag(arg2, weap_types)) == -1)
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "Syntax: weapontype <%s>\n\r", give_flags(weap_types));
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: invalid weapon type %s", arg2);
			pop_call();
			return;
		}
		obj->value[0] = value;
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "wear" ) )
	{
		if ((value = get_flag(arg2, w_flags)) == -1)
		{
			if (!IS_NPC(ch))
				ch_printf_color(ch, "Syntax: wear <%s>\n\r", give_flags(w_flags));
			else
				log_build_printf(ch->pIndexData->vnum, "oset_obj: invalid wear loc %s", arg2);
			pop_call();
			return;
		}
		TOGGLE_BIT(obj->wear_flags, 1LL << value);
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "weight" ) )
	{
		obj->weight = value;
		pop_call();
		return;
	}

	if (IS_NPC(ch))
	{
		log_printf("[%u] Unknown argument: <mposet %s %s %s>", ch->pIndexData->vnum, obj->name, arg1, arg2);
	}
	pop_call();
	return;
}


/*
 * Manually set a character's values and flags
 */
void do_mset( CHAR_DATA *ch, char *argument )
{
	char arg1 [MAX_INPUT_LENGTH];
	CHAR_DATA *victim;

	push_call("do_mset(%p,%p)",ch,argument);

	if (!argument || argument[0] == '\0')
	{
		send_to_char("No argument for do_mset.\n\r", ch);
		pop_call();
		return;
	}
	if (IS_NPC(ch))
	{
		log_build_printf(ch->pIndexData->vnum, "trying to use mset instead of mpmset.");
		send_to_char("mobiles use mpmset instead.\n\r", ch);
		pop_call();
		return;
	}
	
	argument = one_argument( argument, arg1 );

	if ((victim = get_char_room(ch, arg1)) == NULL)
	{
		ch_printf_color(ch, "They aren't here.\n\r");
		pop_call();
		return;
	}

	mset_char(ch, victim, argument, FALSE);
	pop_call();
	return;
}

/*
 * Core function used for both mset and mpmset
 */
void mset_char( CHAR_DATA *ch, CHAR_DATA *victim, char *argument, bool mpcommand )
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	int value;

	push_call("mset_char(%p,%p)",ch,victim,argument);

	if (!mpcommand)
		log_god_printf("MSET %s: mset %s %s", ch->name, get_name(victim), argument);

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

	if (arg1[0] == '\0' || arg2[0] == '\0' )
	{
		if (IS_NPC(ch))
		{
			log_build_printf(ch->pIndexData->vnum, "bad parameters <mset_char %s %s %s>", victim->name, arg1, arg2);
		}
		ch_printf_color(ch, "Syntax: mset <target> <field> <argument>\n\r");
		ch_printf_color(ch, "  Field being one of:\n\r");
		ch_printf_color(ch, "    quest questr randquest randquestr sex level align ethos gold god\n\r");
		ch_printf_color(ch, "    domain school class mclass act race raceeenemy faithenemy\n\r");
		ch_printf_color(ch, "    str dex con int wis cha thirst drunk full air adjective name short\n\r");
		ch_printf_color(ch, "    long desc title spec percenthp percentmana percentmove currhp\n\r");
		ch_printf_color(ch, "    height weight currmana currmove statpts featpts skillpts learned\n\r");

		pop_call();
		return;
	}

	value = is_number(arg2) ? atol(arg2) : -1;

	if ( !strcasecmp( arg1, "quest" ) )
	{
		int firstBit,len;

		if (sscanf(arg2,"%d %d %d",&firstBit,&len,&value) != 3)
		{
			if (IS_NPC(ch))
			{
				log_build_printf(ch->pIndexData->vnum, "Bad parameters: <mpmset quest %s>", arg2);
			}
			ch_printf_color(ch, "Syntax: set mob <target> quest <offset> <numbits> <value>\n\r");
			pop_call();
			return;
		}

		if (IS_NPC(victim))
		{
			set_quest_bits( &victim->npcdata->mob_quest, firstBit, len, value );
		}
		else
		{
			if (IS_NPC(ch))
			{
				set_quest_bits( &victim->pcdata->quest[ch->pIndexData->area->low_r_vnum/100],firstBit,len, value);
			}
			else
			{
				set_quest_bits(&victim->pcdata->quest[victim->in_room->area->low_r_vnum/100], firstBit, len, value );
				ch_printf(ch, "Quest bit %d %d %d set on %s.\n\r", firstBit, len, value, get_name(victim));
			}
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "questr"))
	{
		int firstBit,len,vnum;

		if (sscanf(arg2,"%d %d %d %d",&vnum, &firstBit,&len,&value)!=4)
		{
			if (IS_NPC(ch))
			{
				log_build_printf(ch->pIndexData->vnum, "Bad parameters: <mpmset questr %s>", arg2);
			}
			ch_printf_color(ch, "Syntax: set mob <target> questr <vnum> <offset> <numbits> <value>\n\r");
			pop_call();
			return;
		}
		if (vnum < 0 || vnum >= MAX_VNUM || room_index[vnum]==NULL)
		{
			if (IS_NPC(ch))
			{
				log_build_printf(ch->pIndexData->vnum, "Bad area vnum: <mpmset questr %s>", arg2);
			}
			ch_printf_color(ch, "Room [%u] not found.\n\r", vnum);
			pop_call();
			return;
		}
		if (IS_NPC(victim))
		{
			set_quest_bits( &victim->npcdata->mob_quest, firstBit, len, value );
		}
		else
		{
			set_quest_bits(&victim->pcdata->quest[room_index[vnum]->area->low_r_vnum/100], firstBit, len, value );
		}
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Questr %d %d %d %d set on %s.\n\r", vnum, firstBit, len, value, get_name(victim));
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "randquest" ) )
	{
		int firstBit,len;

		if (sscanf(arg2,"%d %d",&firstBit,&len) !=2)
		{
			if (IS_NPC(ch))
			{
				log_build_printf(ch->pIndexData->vnum, "Bad parameters: <mpmset randquest %s>", arg2);
			}
			ch_printf_color(ch, "Syntax: randquest <offset> <numbits>\n\r");
			pop_call();
			return;
		}

		value = number_bits(len);
		if (IS_NPC(victim))
		{
			set_quest_bits( &victim->npcdata->mob_quest, firstBit, len, value );
		}
		else
		{
			if (IS_NPC(ch))
			{
				set_quest_bits(&victim->pcdata->quest[ch->pIndexData->area->low_r_vnum/100], firstBit, len, value );
			}
			else
			{
				set_quest_bits(&victim->pcdata->quest[victim->in_room->area->low_r_vnum/100], firstBit, len, value );
				ch_printf(ch, "Randquest %d %d %d set on %s.\n\r", firstBit, len, value, get_name(victim));
			}
		}
		pop_call();
		return;
	}

	if (!strcasecmp( arg1, "randquestr"))
	{
		int firstBit,len,vnum;

		if (sscanf(arg2,"%d %d %d",&vnum,&firstBit,&len)!=3)
		{
			if (IS_NPC(ch))
			{
				log_build_printf(ch->pIndexData->vnum, "Bad parameters: <mpmset randquestr %s>", arg2);
			}
			ch_printf_color(ch, "Syntax: set mob <target> randquestr <vnum> <offset> <numbits>\n\r");
			pop_call();
			return;
		}

		if (vnum < 0 || vnum >= MAX_VNUM || room_index[vnum] == NULL)
		{
			ch_printf_color(ch, "Vnum [%u] not found.\n\r", vnum);
			pop_call();
			return;
		}
		value = number_bits(len);

		if (IS_NPC(victim))
		{
			set_quest_bits( &victim->npcdata->mob_quest, firstBit, len, value );
		}
		else
		{
			set_quest_bits( &victim->pcdata->quest[room_index[vnum]->area->low_r_vnum/100], firstBit, len, value );
		}
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Randquestr %d %d %d %d set on %s.\n\r", vnum, firstBit, len, value, get_name(victim));
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "sex" ) )
	{
		if ((value = get_flag(arg2, sex_types)) == -1)
		{
			ch_printf_color(ch, "Syntax: sex <%s>\n\r", give_flags(sex_types));
			pop_call();
			return;
		}
		victim->sex = value;
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's sex to %s.\n\r", get_name(victim), sex_types[value]);
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "pos" ) )
	{
		if ((value = get_flag(arg2, p_types)) == -1)
		{
			ch_printf_color(ch, "Syntax: pos <%s>\n\r", give_flags(p_types));
			pop_call();
			return;
		}
		victim->position = value;
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's position to %s.\n\r", get_name(victim), p_types[value]);
		}

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "level" ) )
	{
		if ( !IS_NPC(victim) )
		{
			send_to_char( "Use 'advance' to change a PCs level.\n\r", ch );
			pop_call();
			return;
		}

		if (value < 1 || value > 99 )
		{
			send_to_char( "Level range is 1 to 99.\n\r", ch );
			pop_call();
			return;
		}
		victim->level = value;
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's level to %d.\n\r", get_name(victim), value);
		}

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "exp" ) )
	{
		if ( value < 0 )
		{
			pop_call();
			return;
		}
		if (!IS_NPC(victim))
		{
			victim->pcdata->exp = value;
			if (!IS_NPC(ch))
			{
				ch_printf(ch, "Setting %s's level to %d.\n\r", get_name(victim), value);
			}
		}
		else
		{
			send_to_char( "NPCs do not have XP.\n\r", ch );
			pop_call();
			return;
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "gold" ) )
	{
		if ( value < 0 )
		{
			pop_call();
			return;
		}
		victim->gold = value;
		victim->carry_weight = get_carry_w(victim);
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's gold to %s.\n\r", get_name(victim), format_coins(value, TRUE));
		}

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "height" ) )
	{
		if ( value < 0 )
		{
			pop_call();
			return;
		}
		victim->height = value;
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's height to %d'%d\".\n\r", get_name(victim), value/12, value %12);
		}

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "weight" ) )
	{
		if ( value < 0 )
		{
			pop_call();
			return;
		}
		victim->weight = value;
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's weight to %d.\n\r", get_name(victim), value);
		}

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "wait"))
	{
		wait_state(victim, value * PULSE_PER_SECOND);
		if (!IS_NPC(ch))
			ch_printf(ch, "Lagging %s for %d pulses.\n\r", get_name(victim), value);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "remember"))
	{
		if (!IS_NPC(ch) || !IS_NPC(victim))
		{
			pop_call();
			return;
		}
		STRFREE(ch->npcdata->remember);

		if (!strcasecmp(arg2, "null"))
		{
			victim->npcdata->remember = STRDUPE(str_empty);
		}
		else
		{
			victim->npcdata->remember = STRALLOC( arg2 );
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "hp" ) )
	{
		if ( value < 1 )
		{
			pop_call();
			return;
		}
		victim->max_hit = value;
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's hp to %d.\n\r", get_name(victim), value);
		}

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "currhp"))
	{
		value = URANGE(-9, value, get_max_hit(victim));
		victim->hit = value;
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's current hitpoints to %d.\n\r", get_name(victim), value);
		}

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "currmana"))
	{
		value = URANGE(0, value, get_max_mana(victim, victim->class));
		victim->mana[victim->class] = value;
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's current mana to %d.\n\r", get_name(victim), value);
		}

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "currmove"))
	{
		value = URANGE(-9, value, get_max_move(victim));
		victim->move = value;
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's current move to %d.\n\r", get_name(victim), value);
		}

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "percenthp"))
	{
		value = URANGE(1, value, 100);
		victim->hit = UMAX(1, get_max_hit(victim) * value / 100);
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's hitpoint percentage to %d%%.\n\r", get_name(victim), value);
		}

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "percentmana"))
	{
		value = URANGE(1, value, 100);
		victim->mana[victim->class] = UMAX(1, get_max_mana(victim, victim->class) * value / 100);
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's mana percentage to %d%%.\n\r", get_name(victim), value);
		}

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "percentmove"))
	{
		value = URANGE(1, value, 100);
		victim->move = UMAX(1, get_max_move(victim) * value / 100);
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's move percentage to %d%%.\n\r", get_name(victim), value);
		}

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "align"))
	{
		argument = one_argument(argument, arg2);

		if (is_number(arg2))
		{
			if ( value < -1000 || value > 1000 )
			{
				send_to_char( "Align range is -1000 to 1000.\n\r", ch );
				pop_call();
				return;
			}
			victim->alignment = value;
			if (!IS_NPC(ch))
			{
				ch_printf(ch, "Setting %s's alignment  to %d.\n\r", get_name(victim), value);
			}
	
			pop_call();
			return;
		}
			
		if ((!strcasecmp(arg2, "neutral") && argument[0] == '\0')
		|| (!strcasecmp(arg2, "true") && !strcasecmp(argument, "neutral")))
		{
			victim->alignment = 0;
			victim->ethos = 0;
			if (!IS_NPC(ch))
				ch_printf(ch, "Setting %s's alignment to true neutral.\n\r", get_name(victim));
			pop_call();
			return;
		}
		else if (!strcasecmp(arg2, "lawful"))
			victim->ethos = 1000;
		else if (!strcasecmp(arg2, "chaotic"))
			victim->ethos = -1000;
		else if (!strcasecmp(arg2, "neutral"))
			victim->ethos = 0;
		else
		{
			send_to_char("Invalid alignment.\n\r", ch);
			send_to_char("Syntax: mset <target> alignment [neutral|true neutral]\n\r", ch);
			send_to_char("        mset <target> alignment [lawful|neutral|chaotic][good|neutral|evil]\n\r", ch);
			pop_call();
			return;
		}
		if (!strcasecmp(argument, "good"))
			victim->alignment = 1000;
		else if (!strcasecmp(argument, "evil"))
			victim->alignment = -1000;
		else if (!strcasecmp(argument, "neutral"))
			victim->alignment = 0;
		else
		{
			send_to_char("Invalid alignment.\n\r", ch);
			send_to_char("Syntax: mset <target> alignment [neutral|true neutral]\n\r", ch);
			send_to_char("        mset <target> alignment [lawful|neutral|chaotic][good|neutral|evil]\n\r", ch);
			pop_call();
			return;
		}
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's alignment to %s %s.\n\r", 
			get_name(victim), victim->ethos < 0 ? "Chaotic" : victim->ethos > 0 ? "Lawful" : "Neutral",
			victim->alignment < 0 ? "Evil" : victim->alignment > 0 ? "Good" : "Neutral");
		}
		pop_call();
		return;
	}
	
	if (!strcasecmp(arg1, "ethos"))
	{
		if ( value < -1000 || value > 1000 )
		{
			send_to_char( "Ethos range is -1000 to 1000.\n\r", ch );
			pop_call();
			return;
		}
		victim->ethos = value;
		if (!IS_NPC(ch))
		{
			ch_printf(ch, "Setting %s's ehthos to %d.\n\r", get_name(victim), value);
		}

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "god"))
	{
		if ( IS_NPC(victim) )
		{
			send_to_char( "Not on mobs.\n\r", ch );
			pop_call();
			return;
		}
		if (lookup_god(argument) == -1)
		{
			ch_printf_color(ch, "No such god.\n\r");
			pop_call();
			return;
		}
		victim->god = lookup_god(argument);
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's deity to %s.\n\r", get_name(victim), god_table[lookup_god(argument)].god_name);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "class"))
	{
		if (lookup_class(argument) == -1)
		{
			ch_printf_color(ch, "No such class.\n\r");
			pop_call();
			return;
		}
		victim->class = lookup_class(argument);
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's class to %s.\n\r", get_name(victim), class_table[value].who_name_long);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "mclass"))
	{
		int class;

		argument = one_argument(argument, arg2);
		
		if ((class = lookup_class(arg2)) == -1)
		{
			ch_printf_color(ch, "No such class.\n\r");
			pop_call();
			return;
		}
		if(!is_number(argument))
		{
			ch_printf_color(ch, "mset mclass <class> <level>\n\r");
			pop_call();
			return;
		}
		value = atol(argument);
		victim->mclass[class] = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's %s level to %d.\n\r", get_name(victim), class_table[class].who_name_long, value);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "learned"))
	{
		int sn;
		
// 		if (!IS_NPC(victim))
// 		{
// 			send_to_char("Only on NPCs. Use sset or mpsetfeat for PCs.\n\r", ch);
// 			pop_call();
// 			return;
// 		}
		argument = one_argument(argument, arg2);
		
		if ((sn = skill_lookup(arg2)) == -1)
		{
			ch_printf_color(ch, "No such skill.\n\r");
			pop_call();
			return;
		}
		if(!is_number(argument))
		{
			ch_printf_color(ch, "mset learned <'skill name'> <value>\n\r");
			pop_call();
			return;
		}
		value = atol(argument);
		victim->learned[sn] = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's ranks in %s to %d.\n\r", get_name(victim), skill_table[sn].name, value);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "race"))
	{
		if (lookup_race(argument) == -1)
		{
			ch_printf_color(ch, "No such race.\n\r");
			pop_call();
			return;
		}
		victim->race = lookup_race(argument);
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's race to %s.\n\r", get_name(victim), race_table[victim->race].race_name);
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "act" ) )
	{
		if (!IS_NPC(victim))
		{
			ch_printf_color(ch, "Not on PCs.\n\r");
			pop_call();
			return;
		}
		if ((value = get_flag(argument, act_flags)) == -1)
		{
			ch_printf_color(ch, "Syntax: act <%s>\n\r", give_flags(act_flags));
			pop_call();
			return;
		}
		TOGGLE_BIT(victim->act, 1LL << value);
		if (!IS_NPC(ch))
			ch_printf(ch, "%s act flags: %s.\n\r", get_name(victim), flag_string(victim->act, act_flags));
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "raceenemy"))
	{
		int enemy;

		if (IS_NPC(victim))
		{
			ch_printf_color(ch, "Only on PCs.\n\r");
			pop_call();
			return;
		}
		argument = one_argument(argument, arg2);
		
		if ((enemy = get_flag(arg2, race_enemy_names)) == -1)
		{
			ch_printf_color(ch, "race enemies: <%s>\n\r", justify(give_flags(race_enemy_names), get_page_width(ch)));
			pop_call();
			return;
		}
		if(!is_number(argument))
		{
			ch_printf_color(ch, "mset raceenemy <'race name'> <value>\n\r");
			pop_call();
			return;
		}
		value = atol(argument);
		victim->pcdata->race_enemy[get_flag(arg2, race_enemy_names)] = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's favored enemy to %s - %+d.\n\r", get_name(victim), race_enemy_names[enemy], value);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "domain"))
	{
		if (IS_NPC(victim))
		{
			ch_printf_color(ch, "Only on PCs.\n\r");
			pop_call();
			return;
		}
		if ((value = get_flag(argument, domain_types)) == -1)
		{
			if (IS_NPC(ch))
			{
				log_build_printf(ch->pIndexData->vnum, "mpmset bad domain: %s", argument);
			}
			ch_printf_color(ch, "domain <%s>\n\r", justify(give_flags(domain_types), get_page_width(ch)));
			pop_call();
			return;
		}
		TOGGLE_BIT(victim->pcdata->domain[value], 1);
		if (!IS_NPC(ch))
		{
			if (victim->pcdata->domain[value])
				ch_printf(ch, "Giving %s the %s domain.\n\r", get_name(victim), domain_types[value]);
			else
				ch_printf(ch, "Removing %s's %s domain.\n\r", get_name(victim), domain_types[value]);
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "str"))
	{
		if (value < 3 || value > 99)
		{
			send_to_char( "Strength range is 3 to 99.\n\r", ch );
			pop_call();
			return;
		}
		victim->perm_str = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's Strength to %d.\n\r", get_name(victim), value);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "int"))
	{
		if (value < 3 || value > 99)
		{
			send_to_char( "Intelligence range is 3 to 99.\n\r", ch );
			pop_call();
			return;
		}
		victim->perm_int = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's Intelligence to %d.\n\r", get_name(victim), value);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "wis"))
	{
		if (value < 3 || value > 99)
		{
			send_to_char( "Wisdom range is 3 to 99.\n\r", ch );
			pop_call();
			return;
		}
		victim->perm_wis = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's Wisdom to %d.\n\r", get_name(victim), value);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "dex"))
	{
		if ( value < 3 || value > 99 )
		{
			send_to_char( "Dexterity range is 3 to 99.\n\r", ch );
			pop_call();
			return;
		}
		victim->perm_dex = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's Dexterity to %d.\n\r", get_name(victim), value);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "con"))
	{
		if (value < 3 || value > 99)
		{
			send_to_char( "Constitution range is 3 to 99.\n\r", ch );
			pop_call();
			return;
		}
		victim->perm_con = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's Constitution to %d.\n\r", get_name(victim), value);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "cha"))
	{
		if (value < 3 || value > 99)
		{
			send_to_char( "Charisma range is 3 to 99.\n\r", ch );
			pop_call();
			return;
		}
		victim->perm_cha = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's Charisma to %d.\n\r", get_name(victim), value);
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "thirst" ) )
	{
		if ( IS_NPC(victim) )
		{
			pop_call();
			return;
		}
		if ( value < 0 || value > 100 )
		{
			send_to_char( "Thirst range is 0 to 100.\n\r", ch );
			pop_call();
			return;
		}
		victim->pcdata->condition[COND_THIRST] = max_thirst(victim) * value / 100;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's thirst level to %d%%.\n\r", get_name(victim), value);

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "drunk" ) )
	{
		if ( IS_NPC(victim) )
		{
			send_to_char( "Not on mobs.\n\r", ch );
			pop_call();
			return;
		}

		if ( value < 0 || value > 100 )
		{
			send_to_char( "Drunk range is 0 to 100.\n\r", ch );
			pop_call();
			return;
		}
		victim->pcdata->condition[COND_DRUNK] = max_drunk(victim) * value / 100;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's drunk level to %d%%.\n\r", get_name(victim), value);

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "full" ) || !strcasecmp( arg1, "hunger" ))
	{
		if ( IS_NPC(victim) )
		{
			send_to_char( "Not on mobs.\n\r", ch );
			pop_call();
			return;
		}

		if ( value < 0 || value > 100 )
		{
			send_to_char( "Full range is 0 to 100.\n\r", ch );
			pop_call();
			return;
		}
		victim->pcdata->condition[COND_FULL] = max_hunger(victim) * value / 100;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's hunger level to %d%%.\n\r", get_name(victim), value);

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "air" ) )
	{
		if ( IS_NPC(victim) )
		{
			send_to_char( "Not on mobs.\n\r", ch );
			pop_call();
			return;
		}

		if ( value < 0 || value > 100 )
		{
			send_to_char( "Full range is 0 to 100.\n\r", ch );
			pop_call();
			return;
		}
		victim->pcdata->condition[COND_AIR] = max_air(victim) * value / 100;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's air level to %d%%.\n\r", get_name(victim), value);

		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "reputation"))
	{
		if ( IS_NPC(victim) )
		{
			send_to_char( "Not on mobs.\n\r", ch );
			pop_call();
			return;
		}
		victim->pcdata->reputation = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's Reputation to %d.\n\r", get_name(victim), value);

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "adjective" ) )
	{
		if ( IS_NPC(victim) )
		{
			send_to_char( "Not on NPCs.\n\r", ch );
			pop_call();
			return;
		}
		STRFREE (victim->pcdata->adjective);
		if(*arg2 == '\0')
		{
			victim->pcdata->adjective = STRALLOC("");
			if (!IS_NPC(ch))
				ch_printf(ch, "Removing %s's adjective.\n\r", get_name(victim), arg2);
		}
		else
		{
			victim->pcdata->adjective = STRALLOC( arg2 );
			if (!IS_NPC(ch))
				ch_printf(ch, "Setting %s's adjective to %s.\n\r", get_name(victim), arg2);
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "name" ) )
	{
		if ( !IS_NPC(victim) )
		{
			send_to_char( "Not on PCs.\n\r", ch );
			pop_call();
			return;
		}
		STRFREE (victim->name );
		if(*arg2 == '\0')
		{
			victim->name = STRALLOC(victim->pIndexData->player_name);
		}
		else
		{
			victim->name = STRALLOC( arg2 );
		}
		if (!IS_NPC(ch))
			ch_printf(ch, "%s's name is now %s.\n\r", get_name(victim), victim->name);
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "short" ) )
	{
		STRFREE (victim->short_descr );
		if(*arg2 == '\0')
		{
			if (IS_NPC(victim))
			{
				victim->short_descr = STRALLOC(victim->pIndexData->short_descr);
			}
			else
			{
				victim->short_descr = STRALLOC( "" );
			}
		}
		else
		{
			victim->short_descr = STRALLOC( arg2 );
		}
		if (!IS_NPC(ch))
			ch_printf(ch, "%s's short desc is now %s.\n\r", get_name(victim), victim->short_descr);
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "long" ) )
	{
		STRFREE (victim->long_descr );
		if(*arg2 =='\0')
		{
			if( IS_NPC( victim ) )
			{
				victim->long_descr = STRALLOC(victim->pIndexData->long_descr);
			}
			else
			{
				victim->long_descr = STRALLOC( "" );
			}
		}
		else
		{
			victim->long_descr = STRALLOC( arg2 );
		}
		if (!IS_NPC(ch))
			ch_printf(ch, "%s's long desc is now %s.\n\r", get_name(victim), victim->long_descr);
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "desc" ) )
	{
		STRFREE (victim->description);
		if(*arg2 == '\0')
		{
			if( IS_NPC(victim))
			{
				victim->description = STRALLOC(victim->pIndexData->description);
			}
			else
			{
				victim->description = STRALLOC( "" );
			}
		}
		else
		{
			victim->description = STRALLOC( arg2 );
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "title" ) )
	{
		if ( IS_NPC(victim) )
		{
			send_to_char( "Not on mobs.\n\r", ch );
			pop_call();
			return;
		}
		set_title( victim, arg2 );
		if (!IS_NPC(ch))
			ch_printf(ch, "%s's short title is now %s.\n\r", get_name(victim), arg2);

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "spec" ) )
	{
		if ( !IS_NPC(victim) )
		{
			send_to_char( "Not on PCs.\n\r", ch );
			pop_call();
			return;
		}

		if ( !strcasecmp( arg2, "none" ) )
		{
			victim->pIndexData->spec_fun = NULL;
			send_to_char( "Special function removed.\n\r", ch );
		}
		
		if ( ( victim->pIndexData->spec_fun = spec_lookup( arg2 ) ) == 0 )
		{
			if (IS_NPC(ch))
			{
				log_build_printf(ch->pIndexData->vnum, "mpmset unknown spec_fun: %s", arg2);
			}
			send_to_char( "No such spec_fun.\n\r", ch );
			pop_call();
			return;
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "featpts" ) )
	{
		if ( IS_NPC(victim) )
		{
			send_to_char( "Not on mobs.\n\r", ch );
			pop_call();
			return;
		}

		if ( value < 0 || value > 10 )
		{
			send_to_char( "Full range is 0 to 10.\n\r", ch );
			pop_call();
			return;
		}
		victim->pcdata->feat_pts = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's feat points to %d.\n\r", get_name(victim), value);

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "statpts" ) )
	{
		if ( IS_NPC(victim) )
		{
			send_to_char( "Not on mobs.\n\r", ch );
			pop_call();
			return;
		}

		if ( value < 0 || value > 10 )
		{
			send_to_char( "Full range is 0 to 10.\n\r", ch );
			pop_call();
			return;
		}
		victim->pcdata->stat_pts = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's stat points to %d.\n\r", get_name(victim), value);

		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "skillpts" ) )
	{
		if ( IS_NPC(victim) )
		{
			send_to_char( "Not on mobs.\n\r", ch );
			pop_call();
			return;
		}

		if ( value < 0 || value > 1000 )
		{
			send_to_char( "Full range is 0 to 1000.\n\r", ch );
			pop_call();
			return;
		}
		victim->pcdata->practice = value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's skill points to %d.\n\r", get_name(victim), value);

		pop_call();
		return;
	}
	
	if ( !strcasecmp( arg1, "master" ) )
	{
		CHAR_DATA *master;
		
		if (!IS_NPC(victim))
		{
			send_to_char( "Not on PCs.\n\r", ch );
			pop_call();
			return;
		}
		if ((master = get_char_room_even_blinded(ch, arg2)) == NULL)
		{
			if (IS_NPC(ch))
				log_build_printf(ch->pIndexData->vnum, "Bad target: <mpmset master %s>", arg2);
			send_to_char("That person isn't here.\n\r", ch);
			pop_call();
			return;
		}
		SET_BIT(victim->act, ACT_PET);
		add_follower(victim, master);
		if (!IS_NPC(ch))
			ch_printf(ch, "Setting %s's master to %s.\n\r", get_name(victim), get_name(master));
		pop_call();
		return;
	}	

	if (IS_NPC(ch))
	{
		log_printf("[%u] Unknown argument: <mpmset %s %s %s>", ch->pIndexData->vnum, victim->name, arg1, arg2);
	}
	pop_call();
	return;
}

/*
 * Add numerically to a value on a character
 */
void do_madd( CHAR_DATA *ch, char *argument )
{
	char arg1 [MAX_INPUT_LENGTH];
	CHAR_DATA *victim;

	push_call("do_madd(%p,%p)",ch,argument);

	if (!argument || argument[0] == '\0')
	{
		send_to_char("No argument for do_madd.\n\r", ch);
		pop_call();
		return;
	}
	if (IS_NPC(ch))
	{
		log_build_printf(ch->pIndexData->vnum, "trying to use madd instead of mpmadd.");
		send_to_char("mobiles use mpmadd instead.\n\r", ch);
		pop_call();
		return;
	}
	
	argument = one_argument( argument, arg1 );

	if ((victim = get_char_room(ch, arg1)) == NULL)
	{
		ch_printf_color(ch, "They aren't here.\n\r");
		pop_call();
		return;
	}

	madd_char(ch, victim, argument);
	pop_call();
	return;
}

/*
 * Core function used for both madd and mpmadd - Kregor
 */
void madd_char( CHAR_DATA *ch, CHAR_DATA *victim, char *argument )
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	int value;

	push_call("madd_char(%p,%p)",ch,victim,argument);

	if (!IS_NPC(ch))
		log_god_printf("MADD %s: madd %s %s", ch->name, get_name(victim), argument);

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

	if (arg1[0] == '\0' || arg2[0] == '\0' )
	{
		if (IS_NPC(ch))
		{
			log_build_printf(ch->pIndexData->vnum, "bad parameters <madd_char %s %s %s>", victim->name, arg1, arg2);
		}
		else
		{
			ch_printf_color(ch, "Syntax: madd <target> <field> <argument>\n\r");
			ch_printf_color(ch, "  Field being one of:\n\r");
			ch_printf_color(ch, "    quest questr randquest randquestr sex level align ethos gold god\n\r");
			ch_printf_color(ch, "    domain school class mclass act race raceeenemy faithenemy\n\r");
			ch_printf_color(ch, "    str dex con int wis cha thirst drunk full air adjective name short\n\r");
			ch_printf_color(ch, "    long desc title spec percenthp percentmana percentmove currhp\n\r");
			ch_printf_color(ch, "    height weight currmana currmove statpts featpts skillpts learned\n\r");
		}
		pop_call();
		return;
	}

	value = is_number(arg2) ? atol(arg2) : -1;

	if ( !strcasecmp( arg1, "quest" ) )
	{
		int firstBit,len;

		if(sscanf(arg2,"%d %d %d",&firstBit,&len,&value)!=3)
		{
			if (IS_NPC(ch))
			{
				log_build_printf(ch->pIndexData->vnum, "bad parameters <mpmadd quest %s>", arg2);
			}
			pop_call();
			return;
		}
		if(IS_NPC(victim))
		{
			value += get_quest_bits( victim->npcdata->mob_quest, firstBit, len);
		}
		else
		{
			if (IS_NPC(ch))
			{
				value += get_quest_bits(victim->pcdata->quest[ch->pIndexData->area->low_r_vnum/100], firstBit, len);
			}
			else
			{
				value += get_quest_bits(victim->pcdata->quest[victim->in_room->area->low_r_vnum/100], firstBit, len);
			}
		}
		if (IS_NPC(victim))
		{
			set_quest_bits( &victim->npcdata->mob_quest, firstBit, len, value );
		}
		else
		{
			if(IS_NPC(ch))
			{
				set_quest_bits(&victim->pcdata->quest[ch->pIndexData->area->low_r_vnum/100], firstBit, len, value );
			}
			else
			{
				set_quest_bits(&victim->pcdata->quest[victim->in_room->area->low_r_vnum/100],firstBit, len, value);
			}
		}
		pop_call();
		return;
	}

	if ( !strcasecmp( arg1, "questr" ) )
	{
		int firstBit,len,vnum;

		if(sscanf(arg2,"%d %d %d %d",&vnum,&firstBit,&len,&value)!=4)
		{
			if (IS_NPC(ch))
			{
				log_build_printf(ch->pIndexData->vnum, "bad parameters <mpmadd questr %s>", arg2);
			}
			pop_call();
			return;
		}
		if (vnum < 0 || vnum >= MAX_VNUM || room_index[vnum] == NULL)
		{
			if (IS_NPC(ch))
			{
				log_build_printf(ch->pIndexData->vnum, "bad area vnum <mpmadd questr %s>", arg2);
			}
			pop_call();
			return;
		}
		if (IS_NPC(victim))
		{
			value += get_quest_bits( victim->npcdata->mob_quest, firstBit, len);
		}
		else
		{
			value += get_quest_bits(victim->pcdata->quest[room_index[vnum]->area->low_r_vnum/100], firstBit, len);
		}
		if(IS_NPC(victim))
		{
			set_quest_bits( &victim->npcdata->mob_quest, firstBit, len, value );
		}
		else
		{
			set_quest_bits( &victim->pcdata->quest[room_index[vnum]->area->low_r_vnum/100],	firstBit, len, value );
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "level"))
	{
		if (IS_NPC(victim))
		{
			victim->level = URANGE(1, victim->level + value, 99);
		}
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d to %s's level (now %d).\n\r", value, get_name(victim), victim->level);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "exp"))
	{
		if (!IS_NPC(victim))
		{
			gain_exp(victim, value);
		}
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d experience points to %s (nowg.\n\r", value, get_name(victim));
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "practice") || !strcasecmp(arg1, "skillpts"))
	{
		if (!IS_NPC(victim))
		{
			victim->pcdata->practice = URANGE(0, victim->pcdata->practice + value, 10000);
		}
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d skill points to %s (now %d).\n\r", value, get_name(victim), victim->pcdata->practice);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "featpts"))
	{
		if (!IS_NPC(victim))
		{
			victim->pcdata->feat_pts = URANGE(0, victim->pcdata->feat_pts + value, 100);
		}
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d feat points to %s (now %d).\n\r", value, get_name(victim), victim->pcdata->feat_pts);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "statpts"))
	{
		if (!IS_NPC(victim))
		{
			victim->pcdata->stat_pts = URANGE(0, victim->pcdata->stat_pts + value, 100);
		}
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d stat points to %s (now %d).\n\r", value, get_name(victim), victim->pcdata->stat_pts);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "align"))
	{
		victim->alignment = URANGE(-1000, victim->alignment + value, 1000);
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d points of alignment to %s (now %d).\n\r", value, get_name(victim), victim->alignment);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "ethos"))
	{
		victim->ethos = URANGE(-1000, victim->ethos + value, 1000);
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d points of ethos to %s (now %d).\n\r", value, get_name(victim), victim->ethos);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "thirst"))
	{
		if (!IS_NPC(victim))
		{
			gain_condition(victim, COND_THIRST, value);
			if (!IS_NPC(ch))
				ch_printf(ch, "Added %d points of thirst to %s.\n\r", value, get_name(victim));
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "drunk"))
	{
		if (!IS_NPC(victim))
		{
			gain_condition(victim, COND_DRUNK, value);
			if (!IS_NPC(ch))
				ch_printf(ch, "Added %d points of drunkenness to %s.\n\r", value, get_name(victim));
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "full"))
	{
		if (!IS_NPC(victim))
		{
			gain_condition(victim, COND_FULL, value);
			if (!IS_NPC(ch))
				ch_printf(ch, "Added %d points of hunger to %s.\n\r", value, get_name(victim));
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "air"))
	{
		if (!IS_NPC(victim))
		{
			gain_condition(victim, COND_AIR, value);
			if (!IS_NPC(ch))
				ch_printf(ch, "Added %d points of air to %s.\n\r", value, get_name(victim));
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "reputation"))
	{
		if (!IS_NPC(victim))
		{
			gain_reputation(victim, value);
			if (!IS_NPC(ch))
				ch_printf(ch, "Added %d points of Reputation to %s (now %d.\n\r", value, get_name(victim), get_reputation(victim));
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "gold"))
	{
		victim->gold += value;
		victim->carry_weight = get_carry_w(victim);
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %s to %s.\n\r", format_coins(value, TRUE), get_name(victim));
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "money"))
	{
		if (gold_transaction(victim, value))
		{
			if (!IS_NPC(ch))
				ch_printf(ch, "Added %s to %s.\n\r", format_coins(value, TRUE), get_name(victim));
		}
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "currhp"))
	{
		victim->hit = URANGE(1, victim->hit + value, get_max_hit(victim));
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d hitpoints %s (now %d).\n\r", value, get_name(victim), victim->hit);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "currmana"))
	{
		victim->mana[ch->class] = URANGE(1, victim->mana[ch->class] + value, get_max_mana(victim, ch->class));
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d mana %s (now %d).\n\r", value, get_name(victim), victim->mana);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "currmove"))
	{
		victim->move = URANGE(1, victim->move + value, get_max_move(victim));
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d move points %s (now %d).\n\r", value, get_name(victim), victim->move);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "hp"))
	{
		victim->max_hit = URANGE(1, victim->max_hit + value, victim->level * 12);
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d hitpoints %s's maximum total (now %d).\n\r", value, get_name(victim), victim->max_hit);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "str"))
	{
		victim->perm_str += value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d points to %s's Strength (now %d).\n\r", value, get_name(victim), victim->perm_str);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "dex"))
	{
		victim->perm_dex += value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d points to %s's Dexterity (now %d).\n\r", value, get_name(victim), victim->perm_dex);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "con"))
	{
		victim->perm_con += value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d points to %s's Constitution (now %d).\n\r", value, get_name(victim), victim->perm_con);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "int"))
	{
		victim->perm_int += value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d points to %s's Intelligence (now %d).\n\r", value, get_name(victim), victim->perm_int);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "wis"))
	{
		victim->perm_wis += value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d points to %s's Wisdom (now %d).\n\r", value, get_name(victim), victim->perm_wis);
		pop_call();
		return;
	}

	if (!strcasecmp(arg1, "cha"))
	{
		victim->perm_cha += value;
		if (!IS_NPC(ch))
			ch_printf(ch, "Added %d points to %s's Charisma (now %d).\n\r", value, get_name(victim), victim->perm_cha);
		pop_call();
		return;
	}

	if (IS_NPC(ch))
	{
		log_build_printf(ch->pIndexData->vnum, "Unknown argument: <mpmadd %s %s %s>", arg1, arg1, arg2);
	}
	pop_call();
	return;
}

/*
 * Set skill ranks for a player, or set class/race/etc levels for a skill - Kregor
 */
void do_sset( CHAR_DATA *ch, char *argument )
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	char arg3 [MAX_INPUT_LENGTH];
	CHAR_DATA *victim;
	int value, sn, class_no, domain_no, style_no, race_no, cnt;
	bool fAll, fAllClass, fAllCross;

	push_call("do_sset(%p,%p)",ch,argument);

	log_god_printf("SSET %s: sset %s", ch->name, argument);

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

	if (arg1[0] == '\0' || arg2[0] == '\0' || arg3[0] == '\0')
	{
		send_to_char("Syntax: sset <player> <skill|all|allclass|allcross> <value>\n\r", ch);
		send_to_char("Syntax: sset <class> <skill> <level>\n\r", ch);
		send_to_char("Syntax: sset <combat style> <skill> <level>\n\r", ch);
		send_to_char("Syntax: sset <race> <skill> <level>\n\r", ch);
		send_to_char("Syntax: sset <domain> <skill> <level>\n\r", ch);
		pop_call();
		return;
	}

	if (!is_number(arg3) && strcasecmp(arg1, "components"))
	{
		send_to_char( "Value must be numeric.\n\r", ch );
		pop_call();
		return;
	}

	value = atol(arg3);

	if ((victim = get_player_world(ch, arg1)) == NULL)
	{
		if ((sn = skill_lookup (arg2)) == -1)
		{
			send_to_char("Syntax: sset <player> <skill|all|allclass|allcross> <value>\n\r", ch);
			send_to_char("Syntax: sset <class> <skill> <level>\n\r", ch);
			send_to_char("Syntax: sset <combat style> <skill> <level>\n\r", ch);
// 			send_to_char("Syntax: sset <race> <skill> <level>\n\r", ch);
			send_to_char("Syntax: sset <domain> <skill> <level>\n\r", ch);
			send_to_char("Syntax: sset components <skill> <component>\n\r", ch);
			pop_call();
			return;
		}
		else if (!strcasecmp(arg1, "components"))
		{
			if ((sn = skill_lookup (arg2)) == -1)
			{
				ch_printf_color (ch, "There is no such spell or craft as '%s'.\n\r", arg2);
				pop_call();
				return;
			}
			if (!is_spell(sn) && skill_table[sn].skilltype != FSKILL_CRAFT)
			{
				ch_printf_color (ch, "Components can only be set on spells or crafts.\n\r");
				pop_call();
				return;
			}
			if ((value = get_flag(arg3, component_flags)) == -1)
			{
				ch_printf_color(ch, "Syntax: sset components <'skill name'> <%s>\n\r", give_flags(component_flags));
				pop_call();
				return;
			}
			for (cnt = 0 ; cnt < 5 ; cnt++)
			{
				if (skill_table[sn].components[cnt] == 0)
				{
					skill_table[sn].components[cnt] = value;
					ch_printf_color (ch, "OK, %s will now use %s as a component.\n\r", skill_table[sn].name, component_flags[value]);
					break;
				}
				if (skill_table[sn].components[cnt] == value)
				{
					skill_table[sn].components[cnt] = 0;
					ch_printf_color (ch, "OK, %s will no longer use %s as a component.\n\r", skill_table[sn].name, component_flags[value]);
					break;
				}
			}
			if (cnt == 5)
			{
				ch_printf_color(ch, "You cannot add anymore components.\n\r");
			}
			pop_call();
			return;
		}	
		else if ((domain_no = get_flag(arg1, domain_types)) != -1)
		{
			if (value < 0 || value > LEVEL_IMMORTAL)
			{
				ch_printf_color (ch, "Level range is from 0 to %d.\n\r", LEVEL_IMMORTAL);
				pop_call();
				return;
			}
			
			skill_table[sn].domains[domain_no] = value;
			
			ch_printf_color (ch, "OK, the %s domain will now gain %s at level %d%s.\n\r", domain_types[domain_no],
										skill_table[sn].name, value, value == LEVEL_IMMORTAL ? " (i.e. never)" : "");
			
			save_domains();
			pop_call();
			return;
		}
		else if ((domain_no = get_flag(arg1, bloodline_types)) != -1)
		{
			if (value < 0 || value > LEVEL_IMMORTAL)
			{
				ch_printf_color (ch, "Level range is from 0 to %d.\n\r", LEVEL_IMMORTAL);
				pop_call();
				return;
			}
			
			skill_table[sn].bloodline[domain_no] = value;
			
			ch_printf_color (ch, "OK, the %s bloodline will now gain %s at level %d%s.\n\r", bloodline_types[domain_no],
										skill_table[sn].name, value, value == LEVEL_IMMORTAL ? " (i.e. never)" : "");
			
			fwrite_bloodlines();
			pop_call();
			return;
		}
		else if ((style_no = get_flag(arg1, combat_styles)) != -1)
		{
			if (value < 0 || value > LEVEL_IMMORTAL)
			{
				ch_printf_color (ch, "Level range is from 0 to %d.\n\r", LEVEL_IMMORTAL);
				pop_call();
				return;
			}
			
			skill_table[sn].styles[style_no] = value;
			
			ch_printf_color (ch, "OK, the %s style will now gain %s at level %d%s.\n\r", combat_styles[style_no],
										skill_table[sn].name, value, value == LEVEL_IMMORTAL ? " (i.e. never)" : "");
			
			save_styles();
			pop_call();
			return;
		}
		else if ((class_no = lookup_class(arg1)) != -1)
		{
			if (value < 0 || value > LEVEL_IMMORTAL)
			{
				ch_printf_color (ch, "Level range is from 0 to %d.\n\r", LEVEL_IMMORTAL);
				pop_call();
				return;
			}
			
			skill_table[sn].skill_level[class_no] = value;
			
			ch_printf_color (ch, "OK, %ss will now gain %s at level %d%s.\n\r", class_table[class_no].who_name_long,
										skill_table[sn].name, value, value == LEVEL_IMMORTAL ? " (i.e. never)" : "");
			
			save_classes();
			pop_call();
			return;
		}
		else if ((race_no = lookup_race(arg1)) != -1)
		{
			if (value < 0 || value > LEVEL_IMMORTAL)
			{
				ch_printf_color (ch, "Level range is from 0 to %d.\n\r", LEVEL_IMMORTAL);
				pop_call();
				return;
			}
			
			skill_table[sn].race_skill[race_no] = value;
			
			if (skill_table[sn].skilltype == FSKILL_SKILL)
				ch_printf_color (ch, "OK, %ss will now receive a %s%d skill bonus to %s.\n\r", race_table[race_no].race_name,
										value > 0 ? "+" : "", value, skill_table[sn].name);
			else if (skill_table[sn].skilltype == FSKILL_RACEATTACK)
				ch_printf_color (ch, "OK, %ss will now receive %s as a racial attack.\n\r", race_table[race_no].race_name,
										skill_table[sn].name);
			else if (value <= 0)
				ch_printf_color (ch, "OK, %ss will not gain %s as a racial ability.\n\r", race_table[race_no].race_name,
										skill_table[sn].name);
			else
				ch_printf_color (ch, "OK, %ss will gain %s as a racial ability.\n\r", race_table[race_no].race_name,
										skill_table[sn].name);
			
			fwrite_race(race_no);
			pop_call();
			return;
		}
		else if (!strcasecmp(arg1, "allclasses"))
		{
			for (class_no = 0 ; class_no < MAX_CLASS ; class_no++)
			{
				if (value < 0 || value > LEVEL_IMMORTAL)
				{
					ch_printf_color (ch, "Level range is from 0 to %d.\n\r", LEVEL_IMMORTAL);
					pop_call();
					return;
				}
				skill_table[sn].skill_level[class_no] = value;

				ch_printf_color (ch, "OK, %ss will now gain %s at level %d%s.\n\r", class_table[class_no].who_name_long,
											skill_table[sn].name, value, value == LEVEL_IMMORTAL ? " (i.e. never)" : "");
			}
			save_classes();
			pop_call();
			return;			
		}
		send_to_char("That person is not here.\n\r", ch);
		pop_call();
		return;
	}

	if (IS_NPC(victim))
	{
		send_to_char( "Not on NPCs.\n\r", ch );
		pop_call();
		return;
	}
	fAll = !strcasecmp(arg2, "all");
	fAllClass = !strcasecmp(arg2, "allclass");
	fAllCross = !strcasecmp(arg2, "allcross");

	if (!fAll && !fAllClass && !fAllCross)
	{
		if ((sn = skill_lookup(arg2)) < 0)
		{
			send_to_char( "No such skill or spell.\n\r", ch );
			pop_call();
			return;
		}
		else if (skill_table[sn].skilltype != FSKILL_SKILL
				&& skill_table[sn].skilltype != FSKILL_CRAFT
				&& skill_table[sn].skilltype != FSKILL_KNOWLEDGE)
		{
			send_to_char( "That is not a skill.\n\r", ch );
			pop_call();
			return;
		}
	}

	if (!fAll && !fAllClass && !fAllCross)
	{
		if (value < 0 || (multi(victim , sn) == -1 && value > (victim->level + 3) / 2) || (multi(victim , sn) != -1 && value > victim->level + 3) )
		{
			ch_printf_color(ch, "Value range is 0 to %d.\n\r", victim->level + 3);
			pop_call();
			return;
		}
	}

	if (fAll)
	{
		for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++ )
		{
			if (skill_table[sn].skilltype == FSKILL_SKILL
			|| skill_table[sn].skilltype == FSKILL_CRAFT
			|| skill_table[sn].skilltype == FSKILL_KNOWLEDGE)
			{
				if (multi(victim , sn) == -1)
				{
					victim->learned[sn] = UMIN(value, (victim->level + 3) / 2);
				}
				else
				{
					victim->learned[sn] = UMIN(value, victim->level + 3);
				}
			}
		}
	}
	else if (fAllClass)
	{
		for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++ )
		{
			if (skill_table[sn].skilltype == FSKILL_SKILL
			|| skill_table[sn].skilltype == FSKILL_CRAFT
			|| skill_table[sn].skilltype == FSKILL_KNOWLEDGE)
			{
				if (multi(victim , sn) != -1)
				{
					victim->learned[sn] = UMIN(value, victim->level + 3);
				}
			}
		}
	}
	else if (fAllCross)
	{
		for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++ )
		{
			if (skill_table[sn].skilltype == FSKILL_SKILL
			|| skill_table[sn].skilltype == FSKILL_CRAFT
			|| skill_table[sn].skilltype == FSKILL_KNOWLEDGE)
			{
				if (multi(victim , sn) == -1)
				{
					victim->learned[sn] = UMIN(value, (victim->level + 3) / 2);
				}
			}
		}
	}
	else
	{
		if (skill_lookup(arg2) == -1)
		{
			send_to_char( "That is not a skill.\n\r", ch );
			pop_call();
			return;
		}			
		victim->learned[skill_lookup(arg2)] = value;
	}
	pop_call();
	return;
}


/*
 * Display the specs for a race - Kregor
 */
void do_showrace( CHAR_DATA *ch, char *argument)
{
	char buf[MAX_STRING_LENGTH];
	int race, sn, cnt, col;

	push_call("do_showrace(%p,%p)",ch,argument);
	
	if (argument[0] == '\0')
	{
		send_to_char("Syntax: showrace <name|all|playable>\n\r", ch);
		pop_call();
		return;
	}
	if (!strcasecmp(argument, "all") || !strcasecmp(argument, "playable"))
	{
		buf[0] = '\0';
		
		for (race = col = 1 ; race < MAX_RACE ; race++)
		{
			if (!is_string(race_table[race].race_name))
				continue;
			if (!strcasecmp(argument, "playable") && !race_table[race].pcrace)
				continue;
				
			cat_sprintf(buf, "  {178}%3d{200}]{078} %-18s", race, race_table[race].race_name);
			if (col++ % 3 == 0)
				cat_sprintf(buf, "\n\r");
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");		
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}

	if ((race = lookup_race(argument)) == -1)
	{
		send_to_char("That is not a race.\n\r", ch);
		pop_call();
		return;
	}
	
	sprintf(buf, "{200}  Race Name:{178} %-18s      {200}HitDice:{178} %2d{200}       ParentRace:{178} %-12s\n\r", race_table[race].race_name, race_table[race].hit_dice, race_table[race_table[race].parent_race].race_name);
	cat_sprintf(buf, "{200}     Height:{178} %-6d   {200}Weight:{178} %-6d    {200}Size:{178} %-10s   {200}PCRace: {178}%-6s\n\r",
			race_table[race].height, race_table[race].weight, size_types[race_table[race].size], race_table[race].pcrace ? "yes" : "no");
	cat_sprintf(buf, "{200}      Speed: {078}Land:{178} %-d{078}, Burrow:{178} %-d{078}, Climb: {178}%-d{078}, Fly: {178}%-d{078}, Swim: {178}%-d\n\r",
			race_table[race].land_speed, race_table[race].burrow_speed, race_table[race].climb_speed, race_table[race].fly_speed, race_table[race].swim_speed);
	cat_sprintf(buf, "{200}      Armor:{178} %-2d   {200}Deflection:{178} %-2d   {200} FavClass: {178}%s\n\r",
			race_table[race].nat_armor, race_table[race].deflection, class_types[race_table[race].favored_class]);
	cat_sprintf(buf, "{200}      Align:{178} %-5d     {200}Ethos: {178}%-5d{200} LevelAdj: {178}%-+5d\n\r", race_table[race].alignment, race_table[race].ethos, race_table[race].lvl_adj);

	cat_sprintf(buf, "{200}   Stat Adj:{178} STR: %+2d DEX: %+2d CON: %+2d INT: %+2d WIS: %+2d CHA: %+2d\n\r",
			race_table[race].race_mod[0],
			race_table[race].race_mod[1],
			race_table[race].race_mod[2],
			race_table[race].race_mod[3],
			race_table[race].race_mod[4],
			race_table[race].race_mod[5]);

	cat_sprintf(buf, "{200} Nonability:{178}");
	for (cnt = 0 ; cnt < 6 ; cnt++)
	{
		if (race_table[race].nonability[cnt])
			cat_sprintf(buf, "%s", cnt == 0 ? " STR" : cnt == 1 ? " DEX" : cnt == 2 ? " CON" : cnt == 3 ? " INT" : cnt == 4 ? " WIS" : "CHA");
		else
			strcat(buf, "");
	}
	strcat(buf, "\n\r");

	cat_sprintf(buf, "{200}  Race Type:{178} %s [%s]{200} Body Type:{178} %s\n\r",
		type_string(race_table[race].type, rtype_flags), flag_string(race_table[race].flags, race_specs), type_string(race_table[race].body_type, body_types));

	cat_sprintf(buf, "{200}    Applies:{178} ");		
	for (cnt = col = 0 ; cnt < MAX_APPLY ; cnt++)
	{
		if (!race_table[race].apply[cnt])
			continue;
		if (col && col % 3 == 0)
			strcat(buf, "             ");
		cat_sprintf(buf, "{178}%-15s%2d    ", a_types[cnt], race_table[race].apply[cnt]);
		col++;
		if (col % 3 == 0)
			cat_sprintf(buf, "\n\r");
	}		
	if (col % 3 != 0)
		cat_sprintf(buf, "\n\r");

	if (race_table[race].affected_by)
		cat_sprintf(buf, "{200} AffectedBy:{178} %s\n\r", flag_string(race_table[race].affected_by, a_flags));
	cat_sprintf(buf, "{200}     Speaks:{178} %-12s", flag_string(race_table[race].speaks, lang_names));
	cat_sprintf(buf, "{200}Understands:{178} %s\n\r", flag_string(race_table[race].understands, lang_names));

	if (race_table[race].bonus_langs)
		cat_sprintf(buf, "{200} BonusLangs:{178} %s\n\r", flag_string(race_table[race].bonus_langs, lang_names));

	cat_sprintf(buf, "{200}   WearLocs:{178} %s\n\r", flag_string(race_table[race].wear_locs, w_flags));

	cat_sprintf(buf, "{200}    Attacks:{178} ");

	for (cnt = col = 0 ; cnt < ATTK_MAX ; cnt++)
	{
		if (!race_table[race].attacks[cnt])
			continue;
		if (col && col % 3 == 0)
			strcat(buf, "             ");
		cat_sprintf(buf, "{178}%-10s %2dx%dd%-2d  ",
			attack_part_flags[cnt], race_table[race].attacks[cnt], dam_no_dice[cnt].size[race_table[race].size], dam_size_dice[cnt].size[race_table[race].size]);
		col++;
		if (col % 3 == 0)
			cat_sprintf(buf, "\n\r");
	}		
	if (col % 3 != 0)
		cat_sprintf(buf, "\n\r");

	if (race_table[race].poison)
		cat_sprintf(buf, "{200}     Poison:{178} %s %s\n\r", !race_table[race].poison ? "none" : attack_part_flags[race_table[race].poison_part], poison_names[race_table[race].poison]);
	if (race_table[race].disease)
		cat_sprintf(buf, "{200}    Disease:{178} %s %s\n\r", !race_table[race].disease ? "none" : attack_part_flags[race_table[race].disease_part], disease_names[race_table[race].disease]);
		
	cat_sprintf(buf, "{200}     Skills: {078}(Ranks)\n\r");
	for (sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
	{
		if (skill_table[sn].skilltype != FSKILL_SKILL && skill_table[sn].skilltype != FSKILL_KNOWLEDGE)
			continue;
		if (skill_table[sn].race_skill[race])
		{
			cat_sprintf(buf, "  {178}%-20s%2d  ", skill_table[sn].name, skill_table[sn].race_skill[race]);
			col++;
			if (col % 3 == 0)
				cat_sprintf(buf, "\n\r");
		}
	}
	if (col % 3 != 0)
		cat_sprintf(buf, "\n\r");

	cat_sprintf(buf, "{200}  Abilities: {078}(Level gained)\n\r");
	for (sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
	{
		if (skill_table[sn].skilltype != FSKILL_FEAT
		&& skill_table[sn].skilltype != FSKILL_ABILITY
		&& skill_table[sn].skilltype != FSKILL_WEAPON
		&& skill_table[sn].skilltype != FSKILL_RACEATTACK)
		{
			continue;
		}
		if (skill_table[sn].race_skill[race])
		{
			cat_sprintf(buf, "  {178}%-20s%2d  ", skill_table[sn].name, skill_table[sn].race_skill[race]);
			col++;
			if (col % 3 == 0)
				cat_sprintf(buf, "\n\r");
		}
	}
	if (col % 3 != 0)
		cat_sprintf(buf, "\n\r");

	cat_sprintf(buf, "{200}  Spell-Like: {078}(Daily Uses or At-Will)\n\r");
	for (sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
	{
		if (skill_table[sn].skilltype != FSKILL_SPELL)
			continue;
		if (skill_table[sn].race_skill[race] >= 75)
		{
			cat_sprintf(buf, "  {178}%-20sAW  ", skill_table[sn].name);
			col++;
			if (col % 3 == 0)
				cat_sprintf(buf, "\n\r");
		}
		else if (skill_table[sn].race_skill[race])
		{
			cat_sprintf(buf, "  {178}%-20s%2d  ", skill_table[sn].name, skill_table[sn].race_skill[race]);
			col++;
			if (col % 3 == 0)
				cat_sprintf(buf, "\n\r");
		}
	}
	if (col % 3 != 0)
		cat_sprintf(buf, "\n\r");

	send_to_char_color(buf, ch);

	pop_call();
	return;
}


/* Lists the ranks for a player's skill(s)
 * Either shows all, or value for just a given skill
 * adapted from ACKMud - Kregor
 */
void do_sstat( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	char buf1[MAX_STRING_LENGTH];
	char arg[MAX_INPUT_LENGTH];
	int skill = -1;
	int sn, col;
	bool fSkill, fFeat, fWeapon, fSpell, fAbility;
	CHAR_DATA *victim;
	
	push_call("do_sstat(%p,%p)",ch,argument);
	
	fSkill = FALSE;
	fFeat = FALSE;
	fWeapon = FALSE;
	fSpell = FALSE;
	fAbility = FALSE;
	argument = one_argument( argument, arg );

	if ( arg[0] == '\0' )
	{
		send_to_char( "Usage: sstat <victim> [skill name|skill|feat|weapon|spell|ability]\n\r", ch );
		return;
	}
	
	if ( ( victim = get_char_world( ch, arg ) ) == NULL )
	{
		send_to_char( "Couldn't find target.\n\r", ch );
		return;
	}
	
	if ( argument[0] != '\0' )
	{
		if (!strcasecmp(argument, "skill"))
		{
			fSkill = TRUE;
		}
		else if (!strcasecmp(argument, "feat"))
		{
			fFeat = TRUE;
		}
		else if (!strcasecmp(argument, "weapon"))
		{
			fWeapon = TRUE;
		}
		else if (!strcasecmp(argument, "spell"))
		{
			fSpell = TRUE;
		}
		else if (!strcasecmp(argument, "ability"))
		{
			fAbility = TRUE;
		}
		else
		{
			skill = skill_lookup( argument );
			if ( skill <= 0 )
			{
				send_to_char( "No such skill/spell!\n\r", ch );
				return;
			}
			sprintf( buf, "{078}%s's {178}%s {078}skill: {200}%d\n\r",
				get_name(victim), skill_table[skill].name, learned(victim, skill) );
			send_to_char_color( buf, ch );
			pop_call();
			return;
		}
	}
	
	sprintf(buf1, "{178}%s's skills:\n\r", get_name(victim));
	
	for ( col = sn = 0; *skill_table[sn].name != '\0' ; sn ++ )
	{
		if ( skill_table[sn].skilltype == FSKILL_NONE )
			continue;
			
		if ( fSkill && skill_table[sn].skilltype != FSKILL_SKILL
		&& skill_table[sn].skilltype != FSKILL_CRAFT
		&& skill_table[sn].skilltype != FSKILL_KNOWLEDGE)
			continue;
			
		if ( fFeat && skill_table[sn].skilltype != FSKILL_FEAT )
			continue;
			
		if ( fSpell && skill_table[sn].skilltype != FSKILL_SPELL )
			continue;
			
		if ( fWeapon && skill_table[sn].skilltype != FSKILL_WEAPON )
			continue;
			
		if ( fAbility && skill_table[sn].skilltype != FSKILL_ABILITY )
			continue;
			
		if (!learned(victim, sn))
			continue;

		switch(skill_table[sn].skilltype)
		{
			case FSKILL_SKILL:
			case FSKILL_CRAFT:
			case FSKILL_KNOWLEDGE:
				sprintf( buf, " {078}%-23s{200}%2d", skill_table[sn].name, learned(victim, sn));
				break;
			default:
				sprintf( buf, " {078}%-25s{200}", skill_table[sn].name);
				break;
		}
		strcat( buf1, buf );
	 
		if ( ++col % 3 == 0 )
			strcat( buf1, "\n\r" );
		else
			strcat( buf1, " " );		
	}
	if ( col % 3 != 0 )
		strcat( buf1, "\n\r" );
		
	send_to_char_color( buf1, ch );
	buf1[0] = '\0';
	
	pop_call();
	return;
}
	
/*
 * Display the specs for a domain - Kregor
 */
void do_showdomain( CHAR_DATA *ch, char *argument )
{
	char buf[MAX_STRING_LENGTH];
	int sn, lev, cnt, dom, god;

	push_call("do_showdomain(%p,%p)",ch,argument);

	if (!strcasecmp(argument, "all"))
	{
		sprintf(buf, "{200}List of available domains:\n\r");

		for (cnt = lev = 0 ; cnt < MAX_DOMAIN ; cnt++)
		{
			cat_sprintf(buf, "  {078}%s\n\r", capitalize(domain_types[cnt]));
			lev++;
		}
		cat_sprintf(buf, "%d domains total.\n\r", lev);
		send_to_char_color(buf, ch);
	}
	else if ((dom = get_flag(argument, domain_types)) != -1)
	{
		sprintf(buf, "{200}Showdomain: %s\n\r", capitalize(domain_types[dom]));

		cat_sprintf(buf, "  {178}Dieties\n\r");		
		for (cnt = god = 0 ; god < MAX_GOD ; god++)
		{
			if (god_table[god].domain[dom])
			{
				if (cnt)
					strcat(buf, ", ");
				cat_sprintf(buf, "{078}%s", god_table[god].god_name);
				cnt++;
			}
		}
		cat_sprintf(buf, "\n\r\n\r  {178}Domain Spells\n\r");		
		for (lev = 1 ; lev <= 9 ; lev++)
		{
			cat_sprintf(buf, " {178}%2d{200}] {078}", lev);
			
			for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
			{
				if (skill_table[sn].skilltype == FSKILL_SPELL)
				{
					if (skill_table[sn].domains[dom] == lev)
					{
						cat_sprintf(buf, "%-19s", skill_table[sn].name);
					}
				}
			}
			cat_sprintf(buf, "\n\r");
		}
		cat_sprintf(buf, "\n\r  {178}Domain Abilities\n\r");		
		for (lev = 0 ; lev < LEVEL_IMMORTAL ; lev++)
		{
			for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
			{
				if (skill_table[sn].skilltype == FSKILL_ABILITY
				|| skill_table[sn].skilltype == FSKILL_SKILL
				|| skill_table[sn].skilltype == FSKILL_KNOWLEDGE
				|| skill_table[sn].skilltype == FSKILL_WEAPON
				|| skill_table[sn].skilltype == FSKILL_FEAT)
				{
					if (skill_table[sn].domains[dom] == lev)
					{
						cat_sprintf(buf, " {178}%2d{200}] {078}%-19s\n\r", lev, skill_table[sn].name);
					}
				}
			}
		}
		send_to_char_color(buf, ch);
	}
	else
	{
		send_to_char("Syntax: showdomain <all|domain>\n\r", ch);
	}
	pop_call();
	return;
}
									
/*
 * Display the specs for a deity - Kregor
 */
void do_showgod( CHAR_DATA *ch, char *argument)
{
	char buf[MAX_STRING_LENGTH * 2];
	int god, cnt, col, count;

	push_call("do_showgod(%p,%p)",ch,argument);
	
	if (argument[0] == '\0')
	{
		send_to_char("Syntax: showgod <name>\n\r", ch);
		pop_call();
		return;
	}
	if (!strcasecmp(argument, "all"))
	{
		buf[0] = '\0';
		
		for (god = col = 1 ; god < MAX_GOD ; god++)
		{
			if (!is_string(god_table[god].god_name))
				continue;
				
			cat_sprintf(buf, " {178}%3d{200}]{078} %-20s", god, god_table[god].god_name);
			if (col++ % 3 == 0)
				cat_sprintf(buf, "\n\r");
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");		
		send_to_char_color(buf, ch);
		pop_call();
		return;
	}

	if ((god = lookup_god(argument)) == -1)
	{
		send_to_char("That is not a god.\n\r", ch);
		pop_call();
		return;
	}
	
	sprintf(buf, "{200}   God Name:{178} %-24s\n\r", god_table[god].god_name);
	cat_sprintf(buf, "{200}  Alignment: {178}");
	
	if (!god_table[god].align && !god_table[god].ethos)
	{
		strcat(buf, "True Neutral\n\r");
	}
	else
	{		
		switch(god_table[god].ethos)
		{
			default:
				strcat(buf, "Neutral ");
				break;
			case 1000:
				strcat(buf, "Lawful ");
				break;
			case -1000:
				strcat(buf, "Chaotic ");
				break;
		}
		switch(god_table[god].align)
		{
			default:
				strcat(buf, "Neutral\n\r");
				break;
			case 1000:
				strcat(buf, "Good\n\r");
				break;
			case -1000:
				strcat(buf, "Evil\n\r");
				break;
		}
	}
	cat_sprintf(buf, "{200}       Race:{178} %s\n\r",
			flag_string(god_table[god].race, race_specs));

	cat_sprintf(buf, "{200}   Unproven:{178} %s\n\r",
			god_table[god].ranking[0]);

	cat_sprintf(buf, "{200}    Acolyte:{178} %s\n\r",
			god_table[god].ranking[1]);

	cat_sprintf(buf, "{200}    Prelate:{178} %s\n\r",
			god_table[god].ranking[2]);

	cat_sprintf(buf, "{200}InnerCircle:{178} %s\n\r",
			god_table[god].ranking[3]);

	cat_sprintf(buf, "{200}     Chosen:{178} %s\n\r",
			god_table[god].ranking[4]);

	cat_sprintf(buf, "{200}   Paladins:{178} %s\n\r",
			flag_string(god_table[god].paladin_multi, class_types));
			
	cat_sprintf(buf, "{200}      Monks:{178} %s\n\r",
			flag_string(god_table[god].monk_multi, class_types));

	cat_sprintf(buf, "{200}     Weapon:{178} %s\n\r",
			weap_types[god_table[god].favored_weapon]);

	cat_sprintf(buf, "{200}PlayerAlign:{178} %d to %d\n\r",
			god_table[god].align_lo, god_table[god].align_hi);

	cat_sprintf(buf, "{200}PlayerEthos:{178} %d to %d\n\r",
			god_table[god].ethos_lo, god_table[god].ethos_hi);

	cat_sprintf(buf, "{200}    Domains: {178}");

	for(cnt = count = 0 ; cnt < MAX_DOMAIN ; cnt++)
	{
		if (god_table[god].domain[cnt] == 0)
			continue;
		if (count)
			cat_sprintf(buf, ", ");
		cat_sprintf(buf, domain_types[cnt]);
		count++;
	}
	strcat(buf, "\n\r");

	cat_sprintf(buf, "{200}Faith Enemy: {178}");

	for(cnt = count = 0 ; cnt < MAX_GOD ; cnt++)
	{
		if (!god_table[god].faith_enemy[cnt])
			continue;
		if (count)
			cat_sprintf(buf, ", ");
		cat_sprintf(buf, god_table[cnt].god_name);
		count++;
	}
	strcat(buf, "\n\r");

	cat_sprintf(buf, "{200} Faith Ally: {178}");

	for(cnt = count = 0 ; cnt < MAX_GOD ; cnt++)
	{
		if (!god_table[god].faith_ally[cnt])
			continue;
		if (count)
			cat_sprintf(buf, ", ");
		cat_sprintf(buf, god_table[cnt].god_name);
		count++;
	}
	strcat(buf, "\n\r");

	send_to_char_color(buf, ch);

	pop_call();
	return;
}


/*
 * Display the specs for a sorcerer bloodline - Kregor
 */
void do_showbloodline( CHAR_DATA *ch, char *argument)
{
	char buf[MAX_STRING_LENGTH];
	int cnt, sn, col, lev;

	push_call("do_showbloodline(%p,%p)",ch,argument);

	if (strcasecmp(argument, "all") && (cnt = get_flag(argument, bloodline_types)) == -1)
	{
		send_to_char("Sytax: showbloodline <all|bloodline name>\n\r", ch);
		pop_call();
		return;
	}
	else if (!strcasecmp(argument, "all"))
	{
		sprintf(buf,"{200}Bloodlines:\n\r");
		for (col = cnt = 1 ; cnt < BLOODLINE_MAX; cnt++)
		{
			cat_sprintf(buf, " {178}%3d{200}]{078} %-20s", cnt, bloodline_types[cnt]);
			if (col++ % 3 == 0)
				cat_sprintf(buf, "\n\r");
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");		
	}
	else
	{ 
		sprintf(buf,"{200}Bloodline:{178} %s\n\r", bloodline_types[cnt]);
		
		strcat(buf, "{200}Class Skills:\n\r");
		for (sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_SKILL
			&& skill_table[sn].skilltype != FSKILL_KNOWLEDGE)
				continue;
			if (skill_table[sn].bloodline[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, " {178}%-22s%2d ", skill_table[sn].name, skill_table[sn].bloodline[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");

		cat_sprintf(buf, "{200}Bonus Feats:\n\r");
		for (sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_FEAT)
				continue;
			if (skill_table[sn].bloodline[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, " {178}%-24s ", skill_table[sn].name);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");

		cat_sprintf(buf, "{200}Class Abilities:\n\r");
		for (sn = col = 0 ; *skill_table[sn].name != '\0' ; sn++)
		{
			if (skill_table[sn].skilltype != FSKILL_ABILITY)
				continue;
			if (skill_table[sn].bloodline[cnt] < LEVEL_IMMORTAL)
			{
				cat_sprintf(buf, " {178}%-22s%2d ", skill_table[sn].name, skill_table[sn].bloodline[cnt]);
				col++;
				if (col % 3 == 0)
					cat_sprintf(buf, "\n\r");
			}
		}
		if (col % 3 != 0)
			cat_sprintf(buf, "\n\r");

		cat_sprintf(buf, "{200}Bonus Spells:\n\r");
		for (lev = 0 ; lev <= 9 ; lev++)
		{
			for (sn = 0 ; *skill_table[sn].name != '\0' ; sn++)
			{
				if (skill_table[sn].skilltype == FSKILL_SPELL)
				{
					if (skill_table[sn].bloodline[cnt] == lev)
					{
						cat_sprintf(buf, " {178}%2d{200}] {078}%-19s\n\r", lev, skill_table[sn].name);
					}
				}
			}
		}
	}
	send_to_char_color(buf, ch);
	pop_call();
	return;
}


/* Find non-existant help files. -Sadiq */
void do_nohelps(CHAR_DATA *ch, char *argument)
{
	AREA_DATA *tArea;
	char arg[MAX_STRING_LENGTH];
	char buf[MAX_STRING_LENGTH * 2];
	int cmd, col = 0, sn = 0;
	bool fCommands = FALSE;
	bool fSkills = FALSE;
	bool fSpells = FALSE;
	bool fAreas = FALSE;
	
	push_call("do_nohelps(%p,%p)",ch,argument);
	
	argument = one_argument( argument, arg );

	if(!IS_IMMORTAL(ch) || IS_NPC(ch) )
	{
		send_to_char("Huh?\n\r", ch);
		pop_call();
		return;
	}

	if ( arg[0] == '\0' || !strcasecmp(arg, "all") )
	{
		fCommands = TRUE;
		fSkills = TRUE;
		fAreas = TRUE;
	}
	else if(!strcasecmp(arg, "commands"))
		fCommands = TRUE;
	else if(!strcasecmp(arg, "skills"))
		fSkills = TRUE;
	else if(!strcasecmp(arg, "areas"))
		fAreas = TRUE;
	else if(!strcasecmp(arg, "spells"))
		fSpells = TRUE;
	else
	{
	 	send_to_char("Syntax:	nohelps <all|areas|commands|skills|spells>\n\r", ch);
	 	pop_call();
	 	return;
	}
 
	buf[0] = '\0';
	
	if(fCommands)
	{
		cat_sprintf(buf, "\n\r{200}Commands for which there are no help files:\n\r", ch);
	
		for ( col = sn = cmd = 0 ; cmd_table[cmd].name[0] != '\0' ; cmd++)
		{
			if (IS_SET(cmd_table[cmd].flags, CMD_NOHELP))
				continue;
			if(!get_help(ch, cmd_table[cmd].name) )
			{
				cat_sprintf(buf, "{078}%-19s", cmd_table[cmd].name);
				if ( ++col % 4 == 0 )
					cat_sprintf(buf, "\n\r");
			}
		}
		cat_sprintf(buf, "\n\r");
	}

	if(fSkills)
	{
		cat_sprintf(buf, "\n\r{200}Skills/Feats/Abilities for which there are no help files:\n\r", ch);
	
		for ( col = sn = 0 ; *skill_table[sn].name != '\0' ; sn++ )
		{
			switch (skill_table[sn].skilltype)
			{
				default:
					continue;
				case FSKILL_ABILITY:
				case FSKILL_FEAT:
				case FSKILL_SKILL:
				case FSKILL_CRAFT:
				case FSKILL_KNOWLEDGE:
					break;
			}
			if(!get_help(ch, skill_table[sn].name))
			{
				cat_sprintf(buf, " {078}%-25s", skill_table[sn].name);
				if ( ++col % 3 == 0 )
					cat_sprintf(buf, "\n\r");
			}
		}
		cat_sprintf(buf, "\n\r");
	}

	if(fSpells)
	{
		cat_sprintf(buf, "\n\r{200}Spells for which there are no help files:\n\r", ch);
	
		for ( col = sn = 0 ; *skill_table[sn].name != '\0' ; sn++ )
		{
			if (skill_table[sn].skilltype != FSKILL_SPELL)
				continue;

			if(!get_help(ch, skill_table[sn].name))
			{
				cat_sprintf(buf, " {078}%-25s", skill_table[sn].name);
				if ( ++col % 3 == 0 )
					cat_sprintf(buf, "\n\r");
			}
		}
		cat_sprintf(buf, "\n\r");
	}

	if(fAreas)
	{
		cat_sprintf(buf, "\n\r{200}Areas for which there are no help files:\n\r", ch);
	
		for (tArea = mud->f_area ; tArea ; tArea = tArea->next)
		{
			if(!get_help(ch, tArea->name))
			{
				cat_sprintf(buf, "{078}%-35s", tArea->name);
				if ( ++col % 2 == 0 )
					cat_sprintf(buf, "\n\r");
			}
		}
		cat_sprintf(buf, "\n\r");
	}
	send_to_char_color(buf, ch);
	pop_call();
	return;
}

/*
 * Immortal and mobile reward, bestows exp to char
 * or optional group, based on a average group level,
 * or a stated challenge rating - Kregor
 */
void do_reward( CHAR_DATA *ch, char *argument )
{
	char arg1 [MAX_INPUT_LENGTH];
	char arg2 [MAX_INPUT_LENGTH];
	CHAR_DATA *victim, *gch;
	bool group = FALSE;
	int cr, exp_gain, group_count, group_level, group_bonus, bonus;

	push_call("do_reward(%p,%p)",ch,argument);

	argument = one_argument( argument, arg1 );
	argument = one_argument( argument, arg2 );
	
	if (arg1[0] == '\0')
	{
		send_to_char( "Syntax: reward <victim> [group] [little|some|lots|level rating]\n\r", ch );
		if (IS_NPC(ch))
			log_build_printf(ch->pIndexData->vnum, "mpreward: bad argument");
		pop_call();
		return;
	}
	
	if (!IS_NPC(ch))
		log_god_printf("REWARD %s: reward %s", ch->name, argument);

	if (!strcasecmp(arg2, "group"))
	{
		group = TRUE;
		argument = one_argument( argument, arg2 );
	}		

	if ((victim = get_char_world( ch, arg1)) == NULL )
	{
		send_to_char( "They aren't here.\n\r", ch );
		if (IS_NPC(ch))
			log_build_printf(ch->pIndexData->vnum, "mpreward: bad target");
		pop_call();
		return;
	}

	if (IS_NPC(victim))
	{
		send_to_char( "Not on NPC's.\n\r", ch );
		if (IS_NPC(ch))
			log_build_printf(ch->pIndexData->vnum, "mpreward: trying to reward NPC");
		pop_call();
		return;
	}

	/* tally the number and total levels in group,
		add +10% exp for each PC grouped */
	for (group_level = group_bonus = group_count = 0, gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
	{
		/* if not in vict group, don't want to count 'em */
		if (!is_same_group(gch, victim))
			continue;

		/* if not group reward, don't want to count them either */
		if (!group && gch != victim)
			continue;
		
		group_count += 1;
		group_level += gch->level;

		wiz_printf("do_reward: pc level = %d %d", gch->level, group_level);

		/* mobs and vict don't give grouping bonus,
			but do count against group level */
		if (IS_NPC(gch))
			continue;			
		if (gch == victim)
			continue;
			
		group_bonus += 1;
	}

	wiz_printf("do_reward: group level = %d", group_level);

	group_level /= group_count;

	if (group_count > 1)
	{
		bonus = group_bonus * 10;
		bonus += 100;
	}
	
	wiz_printf("do_reward: group level = %d", group_level);
	
	if (arg2[0] == '\0')
		cr = group_level * 2;
	else if (!strcasecmp(arg2, "little"))
		cr = group_level;
	else if (!strcasecmp(arg2, "some"))
		cr = group_level * 2;
	else if (!strcasecmp(arg2, "lots"))
		cr = group_level * 3;
	else
	{
		if (!is_number( arg2 ))
		{
			send_to_char( "Value must be numeric.\n\r", ch );
			if (IS_NPC(ch))
				log_build_printf(ch->pIndexData->vnum, "mpreward: bad argument");
			pop_call();
			return;
		}
		if ((cr = atoi(arg2)) < 1 || cr > 30)
		{
			send_to_char( "Challenge range is 1 to 30.\n\r", ch );
			if (IS_NPC(ch))
				log_build_printf(ch->pIndexData->vnum, "mpreward: bad argument");
			pop_call();
			return;
		}
	}

	for (gch = victim->in_room->first_person ; gch ; gch = gch->next_in_room)
	{
		if (!is_same_group(gch, victim) || IS_NPC(gch))
			continue;
		
		if (strcasecmp(argument, "group") && gch != victim)
			continue;

		exp_gain = xp_compute_cr(gch, cr);
		if (group_count > 1)
			exp_gain = exp_gain * bonus / 100;
		wiz_printf("group_gain(%s) - bonus xp: %d", gch->name, exp_gain);
		exp_gain /= group_count;
		wiz_printf("group_gain(%s) - share: %d", gch->name, exp_gain);

		ch_printf_color(gch, "%sYou receive %d experience points.\n\r", get_color_string(gch, COLOR_ALERTS, VT102_BOLD), exp_gain);

		log_printf("REWARD: %s has received reward from %s", gch->name, ch->name);

		gain_exp(gch, exp_gain);
	}
	pop_call();
	return;
}