empiremud/cnf/
empiremud/doc/
empiremud/lib/boards/
empiremud/lib/etc/
empiremud/lib/misc/
empiremud/lib/plralias/F-J/
empiremud/lib/plralias/K-O/
empiremud/lib/plralias/P-T/
empiremud/lib/plralias/U-Z/
empiremud/lib/plrobjs/
empiremud/lib/plrobjs/F-J/
empiremud/lib/plrobjs/K-O/
empiremud/lib/plrobjs/P-T/
empiremud/lib/plrobjs/U-Z/
empiremud/lib/world/
empiremud/lib/world/mob/
empiremud/lib/world/obj/
empiremud/log/
/* ************************************************************************
*   File: act.immortal.c                                 EmpireMUD AD 1.0 *
*  Usage: Player-level imm commands and other goodies                     *
*                                                                         *
*  All rights reserved.  See license.doc for complete information.        *
*                                                                         *
*  Code base by Paul Clarke.  EmpireMUD Project, a tbgMUD Production.     *
*  Based upon CircleMUD 3.0, beta patch level 17, by Jeremy Elson.        *
*                                                                         *
*  Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University *
*  CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.               *
************************************************************************ */

#include "conf.h"
#include "sysdep.h"

#include "structs.h"
#include "utils.h"
#include "comm.h"
#include "vnums.h"
#include "interpreter.h"
#include "handler.h"
#include "db.h"
#include "skills.h"
#include "empire.h"

/*   external vars  */
extern FILE *player_fl;
void check_autowiz(Creature ch);
extern const char *apply_types[];
extern const char *affect_types[];
extern const char *affected_bits[];
extern const char *dsc_bits[];
extern const char *genders[];
extern int top_of_p_table;
extern struct player_index_element *player_table;


ACMD(do_autowiz) {
	check_autowiz(ch);
	}


ACMD(do_purgevnum) {
	int vnum, j;
	Creature i, next_i;

	skip_spaces(&argument);
	vnum = atoi(argument);

	for (i = character_list, j = 0; i && j < 1000; i = next_i) {
		next_i = i->next;
		if (REAL_NPC(i) && GET_MOB_VNUM(i) == vnum) {
			extract_char(i);
			j++;
			}
		}
	msg_to_char(ch, OK);

	msg_to_char(ch, "Current mob counts:\r\n");

	for (j = 0; j <= top_of_mobt; j++)
		msg_to_char(ch, "%-6d: %d\r\n", mob_index[j].vnum, mob_index[j].number);
	}


ACMD(do_authorize) {
	extern Creature is_playing(long id);
	void save_char_file_u(struct char_file_u st);
	struct char_file_u chdata;
	Creature vict;
	int id;

	argument = one_argument(argument, arg);
	skip_spaces(&argument);

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

	if (!*arg || !*argument)
		msg_to_char(ch, "Usage: authorize <character> <e-mail>\r\n");
	else if (!strstr(argument, "@"))
		msg_to_char(ch, "E-mail addresses must include an @.\r\n");
	else if (!(id = get_id_by_name(arg)))
		msg_to_char(ch, "Unable to find character '%s'?\r\n", arg);
	else {
		if ((vict = is_playing(id))) {
			if (GET_LEVEL(vict) < LVL_APPROVED)
				GET_LEVEL(vict) = LVL_APPROVED;
			if (GET_EMAIL(vict))
				free(GET_EMAIL(vict));
			GET_EMAIL(vict) = str_dup(argument);
			SAVE_CHAR(vict);
			msg_to_char(vict, "Your character has been validated.\r\n");
			mortlog(vict, "%s has been authorized!", PERS(vict, vict, 1));
			}
		else {
			if ((load_char(arg, &chdata)) > NOBODY) {
				if (chdata.char_specials_saved.idnum > 0) {
					if (chdata.level < LVL_APPROVED)
						chdata.level = LVL_APPROVED;
					strcpy(chdata.email, argument);
					save_char_file_u(chdata);
					}
				else {
					msg_to_char(ch, "You can't authorize someone with idnum 0.\r\n");
					return;
					}
				}
			else {
				msg_to_char(ch, "No player by that name.\r\n");
				return;
				}
			}
		syslog(GET_INVIS_LEV(ch), TRUE, "VALID: %s has been validated by %s", CAP(arg), GET_NAME(ch));
		msg_to_char(ch, "%s validated.\r\n", CAP(arg));
		}
	}


ACMD(do_random) {
	sprintf(buf, "goto %d", number(0, MAP_SIZE - 1));
	command_interpreter(ch, buf);
	}


ACMD(do_echo) {
	skip_spaces(&argument);

	if (!*argument)
		send_to_char("Yes.. but what?\r\n", ch);
	else {
		if (subcmd == SCMD_EMOTE)
			sprintf(buf, "$n %s", argument);
		else
			strcpy(buf, argument);
		act(buf, FALSE, ch, 0, 0, TO_ROOM);
		if (PRF_FLAGGED(ch, PRF_NOREPEAT))
			send_to_char(OK, ch);
		else
			act(buf, FALSE, ch, 0, 0, TO_CHAR);
		}
	}


ACMD(do_send) {
	Creature vict;

	half_chop(argument, arg, buf);

	if (!*arg) {
		send_to_char("Send what to who?\r\n", ch);
		return;
		}
	if (!(vict = get_char_vis(ch, arg, FIND_CHAR_WORLD))) {
		send_to_char(NOPERSON, ch);
		return;
		}
	send_to_char(buf, vict);
	send_to_char("\r\n", vict);
	if (PRF_FLAGGED(ch, PRF_NOREPEAT))
		send_to_char("Sent.\r\n", ch);
	else {
		sprintf(buf2, "You send '%s' to %s.\r\n", buf, GET_NAME(vict));
		send_to_char(buf2, ch);
		}
	}


/* Take a string, and return an rnum.. used for goto, at, etc.  -je 4/6/93 */
room_rnum find_target_room(Creature ch, char *rawroomstr) {
	room_vnum tmp;
	room_rnum location;
	Creature target_mob;
	Object target_obj;
	char roomstr[MAX_INPUT_LENGTH];
	char a[MAX_INPUT_LENGTH], b[MAX_INPUT_LENGTH];
	int x, y;
	char *str;

	/* Coordinates */
	if (*rawroomstr && strstr(rawroomstr, "(") && strstr(rawroomstr, ")") && strstr(rawroomstr, ",")) {
		strcpy(roomstr, rawroomstr);
		for (x = 0; x < strlen(roomstr); x++)
			if (roomstr[x] == '(' || roomstr[x] == ')' || roomstr[x] == ',')
				roomstr[x] = ' ';
		str = str_dup(roomstr);
		skip_spaces(&str);
		half_chop(roomstr, a, b);
		strcpy(roomstr, str);
		str = str_dup(b);
		skip_spaces(&str);
		strcpy(b, str);
		x = atoi(a);
		y = atoi(b);
		if (x >= 0 && x < MAP_WIDTH && y >= 0 && y < MAP_HEIGHT)
			return (MAP_HEIGHT*y+x);
		}

	one_argument(rawroomstr, roomstr);

	if (!*roomstr) {
		send_to_char("You must supply a room number or name.\r\n", ch);
   		return (NOWHERE);
		}
	if (isdigit(*roomstr) && !strchr(roomstr, '.')) {
		tmp = atoi(roomstr);
		if ((location = real_room(tmp)) < 0) {
			send_to_char("No room exists with that number.\r\n", ch);
			return (NOWHERE);
			}
		}
	else if ((target_mob = get_char_vis(ch, roomstr, FIND_CHAR_WORLD)) != NULL)
		location = target_mob->in_room;
	else if ((target_obj = get_obj_vis(ch, roomstr)) != NULL) {
		if (target_obj->in_room != NOWHERE)
			location = target_obj->in_room;
		else {
			send_to_char("That object is not available.\r\n", ch);
			return (NOWHERE);
			}
		}
	else {
		send_to_char("No such creature or object around.\r\n", ch);
		return (NOWHERE);
		}

	return (location);
	}


ACMD(do_at) {
	char command[MAX_INPUT_LENGTH];
	room_rnum location, original_loc;

	half_chop(argument, buf, command);
	if (!*buf) {
		send_to_char("You must supply a room number or a name.\r\n", ch);
		return;
		}

	if (!*command) {
		send_to_char("What do you want to do there?\r\n", ch);
		return;
		}

	if ((location = find_target_room(ch, buf)) < 0)
		return;

	/* a location has been found. */
	original_loc = ch->in_room;
	char_from_room(ch);
	char_to_room(ch, location);
	command_interpreter(ch, command);

	/* check if the char is still there */
	if (ch->in_room == location) {
		char_from_room(ch);
		char_to_room(ch, original_loc);
		}
	}


ACMD(do_goto) {
	Creature t;
	room_rnum location;

	if ((location = find_target_room(ch, argument)) < 0)
		return;

	if (subcmd != SCMD_GOTO && !CAN_USE_ROOM(ch, location, 0)) {
		msg_to_char(ch, "You can't teleport there.\r\n");
		return;
		}

	if (POOFOUT(ch)) {
		if (!strstr(POOFOUT(ch), "$n"))
			sprintf(buf, "$n %s", POOFOUT(ch));
		else
			strcpy(buf, POOFOUT(ch));
		}
	else
		strcpy(buf, "$n disappears in a puff of smoke.");

	for (t = world[ch->in_room].people; t; t = t->next_in_room)
		if (!REAL_NPC(t) && t != ch && CAN_SEE(t, ch))
			act(buf, TRUE, ch, 0, t, TO_VICT);
	char_from_room(ch);
	char_to_room(ch, location);

	if (POOFIN(ch)) {
		if (!strstr(POOFIN(ch), "$n"))
			sprintf(buf, "$n %s", POOFIN(ch));
		else
			strcpy(buf, POOFIN(ch));
		}
	else
		strcpy(buf, "$n appears with an ear-splitting bang.");

	for (t = world[ch->in_room].people; t; t = t->next_in_room)
		if (!REAL_NPC(t) && t != ch && CAN_SEE(t, ch))
			act(buf, TRUE, ch, 0, t, TO_VICT);
	look_at_room(ch);
	}


ACMD(do_trans) {
	Descr i;
	Creature victim;
	room_rnum to_room = ch->in_room;

	two_arguments(argument, buf, arg);

	if (*arg)
		if ((to_room = find_target_room(ch, arg)) == NOWHERE)
			to_room = ch->in_room;

	if (!*buf)
		send_to_char("Whom do you wish to transfer (and where)?\r\n", ch);
	else if (str_cmp("all", buf)) {
		if (!(victim = get_char_vis(ch, buf, FIND_CHAR_WORLD)))
			send_to_char(NOPERSON, ch);
		else if (victim == ch)
			send_to_char("That doesn't make much sense, does it?\r\n", ch);
		else {
			if ((GET_REAL_LEVEL(ch) < GET_REAL_LEVEL(victim)) && !REAL_NPC(victim)) {
				send_to_char("Go transfer someone your own size.\r\n", ch);
				return;
				}
			act("$n disappears in a mushroom cloud.", FALSE, victim, 0, 0, TO_ROOM);
			char_from_room(victim);
			char_to_room(victim, to_room);
			act("$n arrives from a puff of smoke.", FALSE, victim, 0, 0, TO_ROOM);
			act("$n has transferred you!", FALSE, ch, 0, victim, TO_VICT);
			look_at_room(victim);
			}
		}
	else {			/* Trans All */
		if (GET_LEVEL(ch) < LVL_IMPL) {
			send_to_char("I think not.\r\n", ch);
			return;
			}

		for (i = descriptor_list; i; i = i->next)
			if (STATE(i) == CON_PLAYING && i->character && i->character != ch) {
				victim = i->character;
				if (GET_LEVEL(victim) >= GET_LEVEL(ch))
					continue;
				act("$n disappears in a mushroom cloud.", FALSE, victim, 0, 0, TO_ROOM);
				char_from_room(victim);
				char_to_room(victim, to_room);
				act("$n arrives from a puff of smoke.", FALSE, victim, 0, 0, TO_ROOM);
				act("$n has transferred you!", FALSE, ch, 0, victim, TO_VICT);
				look_at_room(victim);
				}
		}
	send_to_char(OK, ch);
	}


ACMD(do_vnum) {
	half_chop(argument, buf, buf2);

	if (!*buf || !*buf2 || (!is_abbrev(buf, "mob") && !is_abbrev(buf, "obj"))) {
		send_to_char("Usage: vnum { obj | mob } <name>\r\n", ch);
		return;
		}
	if (is_abbrev(buf, "mob"))
		if (!vnum_mobile(buf2, ch))
			send_to_char("No mobiles by that name.\r\n", ch);

	if (is_abbrev(buf, "obj"))
		if (!vnum_object(buf2, ch))
			send_to_char("No objects by that name.\r\n", ch);
	}


/* Displays the vital statistics of ch->in_room to ch */
void do_stat_room(Creature ch) {
	extern const char *room_aff_bits[];
	extern const char *crops[];
	extern const char *dirs[];
	extern const char *sector_types[];
	extern const char *exit_bits[];
	Room rm = &world[ch->in_room];
	int i, found;
	Object j;
	Creature k;
	struct affected_type *aff;

	if (rm->sector_type == SECT_CROP)
		sprinttype(rm->type, crops, buf2);
	else
		sprinttype(rm->sector_type, sector_types, buf2);
	msg_to_char(ch, "Zone: [%3d], VNum: [&2%5d&0], RNum: [%5d], Type: &6%s&0\r\n", zone_table[rm->zone].number, rm->number, ch->in_room, buf2);

	if (real_empire(world[HOME_ROOM(ch->in_room)].owner) != NOTHING)
		if (real_empire(world[HOME_ROOM(ch->in_room)].owner))
			msg_to_char(ch, "Owner: %s%s&0.\r\n", empire[real_empire(world[HOME_ROOM(ch->in_room)].owner)].banner, empire[real_empire(world[HOME_ROOM(ch->in_room)].owner)].name);

	if (SECT(ch->in_room) == SECT_MOUNTAIN || BUILDING_TYPE(ch->in_room) == BUILDING_MINE) {
		if (world[ch->in_room].type2 == 0)
			msg_to_char(ch, "This area is unmined.\r\n");
		else
			msg_to_char(ch, "Mineral: %s, Amount remaining: %d\r\n", world[ch->in_room].type2 == ITEM_MAT_SILVER ? "silver" : "iron", world[ch->in_room].spare);
		}


	sprintf(buf, "Chars present:&3");
	for (found = 0, k = rm->people; k; k = k->next_in_room) {
		if (!CAN_SEE(ch, k))
			continue;
		sprintf(buf2, "%s %s(%s)", found++ ? "," : "", GET_NAME(k), (!IS_NPC(k) ? "PC" : (!IS_MOB(k) ? "NPC" : "MOB")));
		strcat(buf, buf2);
		if (strlen(buf) >= 62) {
			if (k->next_in_room)
				send_to_char(strcat(buf, ",\r\n"), ch);
			else
				send_to_char(strcat(buf, "\r\n"), ch);
			*buf = found = 0;
			}
		}
	msg_to_char(ch, "&0");

	if (*buf)
		send_to_char(strcat(buf, "\r\n&0"), ch);

	if (rm->contents) {
		sprintf(buf, "Contents:&2");
		for (found = 0, j = rm->contents; j; j = j->next_content) {
			if (!CAN_SEE_OBJ(ch, j))
				continue;
			sprintf(buf2, "%s %s", found++ ? "," : "", GET_OBJ_DESC(j, ch, 1));
			strcat(buf, buf2);
			if (strlen(buf) >= 62) {
				if (j->next_content)
					send_to_char(strcat(buf, ",\r\n"), ch);
				else
					send_to_char(strcat(buf, "\r\n"), ch);
				*buf = found = 0;
				}
			}

		if (*buf)
			send_to_char(strcat(buf, "\r\n"), ch);
		send_to_char("&0", ch);
		}
	for (i = 0; i < NUM_OF_DIRS; i++) {
		if (rm->dir_option[i]) {
			if (rm->dir_option[i]->to_room == NOWHERE)
				sprintf(buf1, " &6NONE&0");
			else
				sprintf(buf1, "&6%5d&0", GET_ROOM_VNUM(rm->dir_option[i]->to_room));
			sprintbit(rm->dir_option[i]->exit_info, exit_bits, buf2, TRUE);
			sprintf(buf, "Exit &6%-5s&0:  To: [%s], Keywrd: %s, Type: %s\r\n", dirs[i], buf1, rm->dir_option[i]->keyword ? rm->dir_option[i]->keyword : "None", buf2);
			send_to_char(buf, ch);
			}
		}

	/* Routine to show what spells a room is affected by */
	if (rm->af) {
		for (aff = rm->af; aff; aff = aff->next) {
			*buf2 = '\0';

			sprintf(buf, "TYPE: (%3dhr) &6%s&0 ", aff->duration + 1, affect_types[aff->type]);

			if (aff->modifier) {
				sprintf(buf2, "%+d to %s", aff->modifier, apply_types[(int) aff->location]);
				strcat(buf, buf2);
				}
			if (aff->bitvector) {
				if (*buf2)
					strcat(buf, ", sets ");
				else
					strcat(buf, "sets ");
				sprintbit(aff->bitvector, room_aff_bits, buf2, TRUE);
				strcat(buf, buf2);
				}
			if (aff->disc_bit) {
				if (*buf2)
					strcat(buf, ", sets ");
				else
					strcat(buf, "sets ");
				sprintbit(aff->disc_bit, dsc_bits, buf2, TRUE);
				strcat(buf, buf2);
				}
			send_to_char(strcat(buf, "\r\n"), ch);
			}
		}
	}


/* Gives detailed information on an object (j) to ch */
void do_stat_object(Creature ch, Object j) {
	extern const char *crops[];
	extern const char *wear_bits[];
	extern struct attack_hit_type attack_hit_text[];
	extern const char *item_types[];
	extern const char *extra_bits[];
	extern const int dam_type[];
	extern const char *drinks[];
	extern const char *container_bits[];

	int i, found;
	obj_vnum vnum = GET_OBJ_VNUM(j);
	Object j2;
	struct extra_descr_data *desc;

	msg_to_char(ch, "Name: '&3%s&0', Aliases: %s\r\n", GET_OBJ_DESC(j, ch, 1), j->name);
	msg_to_char(ch, "VNum: [&2%5d&0], RNum: [%5d], Type: &6%s&0\r\n", vnum, GET_OBJ_RNUM(j), item_types[(int) GET_OBJ_TYPE(j)]);
	msg_to_char(ch, "L-Des: %s\r\n", GET_OBJ_DESC(j, ch, 0));

	*buf = 0;
	if (j->ex_description) {
		sprintf(buf, "Extra descs:&6");
		for (desc = j->ex_description; desc; desc = desc->next) {
			strcat(buf, " ");
			strcat(buf, desc->keyword);
			}
		send_to_char(strcat(buf, "&0\r\n"), ch);
		}
	sprintbit(j->obj_flags.wear_flags, wear_bits, buf, TRUE);
	msg_to_char(ch, "Can be worn on: &2%s&0\r\n", buf);

	sprintbit(j->obj_flags.bitvector, affected_bits, buf, TRUE);
	msg_to_char(ch, "Set char bits : &3%s&0\r\n", buf);

	sprintbit(GET_OBJ_EXTRA(j), extra_bits, buf, TRUE);
	msg_to_char(ch, "Extra flags   : &2%s&0\r\n", buf);

	msg_to_char(ch, "Weight: %d, Value: %d, Cost/day: %d, Timer: %d\r\n", GET_OBJ_WEIGHT(j), GET_OBJ_COST(j), GET_OBJ_RENT(j), GET_OBJ_TIMER(j));

	strcpy(buf, "In room: ");
	if (j->in_room == NOWHERE)
		strcat(buf, "Nowhere");
	else {
		sprintf(buf2, "%d", GET_ROOM_VNUM(IN_ROOM(j)));
		strcat(buf, buf2);
		}

	/*
	 * NOTE: In order to make it this far, we must already be able to see the
	 *       character holding the object. Therefore, we do not need CAN_SEE().
	 */
	strcat(buf, ", In object: ");
	strcat(buf, j->in_obj ? GET_OBJ_DESC(j->in_obj, ch, 1) : "None");
	strcat(buf, ", Carried by: ");
	strcat(buf, j->carried_by ? GET_NAME(j->carried_by) : "Nobody");
	strcat(buf, ", Worn by: ");
	strcat(buf, j->worn_by ? GET_NAME(j->worn_by) : "Nobody");
	strcat(buf, "\r\n");
	send_to_char(buf, ch);

	switch (GET_OBJ_TYPE(j)) {
		case ITEM_WEAPON:
			if (GET_OBJ_VAL(j, 0) > 0)
				msg_to_char(ch, "Aggravated damage: %d points", GET_OBJ_VAL(j, 0));
			else if (GET_OBJ_VAL(j, 0) == -1)
				msg_to_char(ch, "Aggravated damage: Unlimited\r\n");

			msg_to_char(ch, "Damage: Strength");
			if (GET_OBJ_VAL(j, 1) != 0)
				msg_to_char(ch, " %s%d\r\n", GET_OBJ_VAL(j, 1) > 0 ? "+" : "", GET_OBJ_VAL(j, 1));
			else
				msg_to_char(ch, "\r\n");

			switch (dam_type[GET_OBJ_VAL(j, 2)]) {
				case DAM_BASHING:			sprintf(buf, "bashing");	break;
				case DAM_LETHAL:			sprintf(buf, "lethal");		break;
				case DAM_AGGRAVATED:		sprintf(buf, "aggravated");	break;
				}
			msg_to_char(ch, "Damage type: %s (%s)\r\n", attack_hit_text[GET_OBJ_VAL(j, 2)].singular, buf);
			break;
		case ITEM_WORN:
			if (CAN_WEAR(j, ITEM_WEAR_SHEATH))
				msg_to_char(ch, "Holds weapon type: %s\r\n", attack_hit_text[GET_OBJ_VAL(j, 2)].singular);
			break;
		case ITEM_CONTAINER:
			msg_to_char(ch, "Holds: %d pounds\r\n", GET_OBJ_VAL(j, 0));

			sprintbit(GET_OBJ_VAL(j, 1), container_bits, buf, TRUE);
			msg_to_char(ch, "Flags: %s\r\n", buf);
			break;
		case ITEM_DRINKCON:
			msg_to_char(ch, "Contains: %d/%d drinks of %s\r\n", GET_OBJ_VAL(j, 1), GET_OBJ_VAL(j, 0), drinks[GET_OBJ_VAL(j, 2)]);
			break;
		case ITEM_FOOD:
			msg_to_char(ch, "Fills for: %d hours\r\n", GET_OBJ_VAL(j, 0));
			if (OBJ_FLAGGED(j, ITEM_PLANTABLE))
				msg_to_char(ch, "Plants: %s\r\n", crops[GET_OBJ_VAL(j, 1)]);
			break;
		case ITEM_CORPSE:
			msg_to_char(ch, "Corpse of: ");

			if (real_mobile(GET_OBJ_VAL(j, 0)) != NOTHING)
				msg_to_char(ch, "%s\r\n", GET_MOB_NAME_BY_PROTO(real_mobile(GET_OBJ_VAL(j, 0))));
			else if (GET_OBJ_VAL(j, 0) >= 0)
				msg_to_char(ch, "nothing\r\n");
			else
				msg_to_char(ch, "%s\r\n", get_name_by_id(-1 * GET_OBJ_VAL(j, 0)) ? CAP(get_name_by_id(-1 * GET_OBJ_VAL(j, 0))) : "a player");

			msg_to_char(ch, "Size: %d cu\r\n", GET_OBJ_VAL(j, 1));

			break;
		case ITEM_SKIN:
			msg_to_char(ch, "Size: %d cu\r\n", GET_OBJ_VAL(j, 0));
			break;
		case ITEM_CART:
			msg_to_char(ch, "Holds: %d pounds\r\n", GET_OBJ_VAL(j, 0));
			msg_to_char(ch, "Animals required: %d\r\n", GET_OBJ_VAL(j, 1));
			if (GET_OBJ_VAL(j, 2))
				msg_to_char(ch, "Capable of firing.\r\n");
			break;
		case ITEM_SHIP:
			msg_to_char(ch, "Ship id: %d\r\n", GET_OBJ_VAL(j, 0));
			if (GET_OBJ_VAL(j, 1))
				msg_to_char(ch, "Resources required: %d\r\n", GET_OBJ_VAL(j, 1));
			msg_to_char(ch, "On deck: %d\r\n", GET_OBJ_VAL(j, 2));
			break;
		case ITEM_MISSILE_WEAPON:
			msg_to_char(ch, "Rate of fire: %d shot%s per round\r\n", GET_OBJ_VAL(j, 0), GET_OBJ_VAL(j, 0) != 1 ? "s" : "");
			msg_to_char(ch, "Damage: %d\r\n", GET_OBJ_VAL(j, 1));
			msg_to_char(ch, "Arrow type: %c\r\n", 'A' + GET_OBJ_VAL(j, 2));
			break;
		case ITEM_ARROW:
			if (GET_OBJ_VAL(j, 0) || GET_OBJ_VAL(j, 1))
				msg_to_char(ch, "Damage: %s%d %s\r\n", GET_OBJ_VAL(j, 1) >= 0 ? "+" : "", GET_OBJ_VAL(j, 1), GET_OBJ_VAL(j, 0) ? "(aggravated)" : "");
			msg_to_char(ch, "Arrow type: %c\r\n", 'A' + GET_OBJ_VAL(j, 2));
			break;
		case ITEM_INSTRUMENT:
			msg_to_char(ch, "Instrument type: %c\r\n", 'A' + GET_OBJ_VAL(j, 0));
			break;
		default:
			if (GET_OBJ_VAL(j, 0) || GET_OBJ_VAL(j, 1) || GET_OBJ_VAL(j, 2))
				msg_to_char(ch, "Values 0-2: [&2%d&0] [&2%d&0] [&2%d&0]\r\n", GET_OBJ_VAL(j, 0), GET_OBJ_VAL(j, 1), GET_OBJ_VAL(j, 2));
			break;
 		}

	/*
	 * I deleted the "equipment status" code from here because it seemed
	 * more or less useless and just takes up valuable screen space.
	 */

	if (j->contains) {
		sprintf(buf, "\r\nContents:&2");
		for (found = 0, j2 = j->contains; j2; j2 = j2->next_content) {
			sprintf(buf2, "%s %s", found++ ? "," : "", GET_OBJ_DESC(j2, ch, 1));
			strcat(buf, buf2);
			if (strlen(buf) >= 62) {
				if (j2->next_content)
					send_to_char(strcat(buf, ",\r\n"), ch);
				else
					send_to_char(strcat(buf, "\r\n"), ch);
				*buf = found = 0;
				}
			}

		if (*buf)
     		send_to_char(strcat(buf, "\r\n"), ch);
		send_to_char("&0", ch);
		}
	found = 0;
	send_to_char("Affections:", ch);
	for (i = 0; i < MAX_OBJ_AFFECT; i++)
		if (j->affected[i].modifier)
			msg_to_char(ch, "%s %+d to %s", found++ ? "," : "", j->affected[i].modifier, apply_types[(int) j->affected[i].location]);
	if (!found)
		send_to_char(" None", ch);

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


/* Sends ch information on the character or animal k */
void do_stat_character(Creature ch, Creature k) {
	extern int move_gain(Creature ch);
	void display_attributes(Creature ch, Creature to, bool real);

	extern struct attack_hit_type attack_hit_text[];
	extern const char *action_bits[];
	extern const char *player_bits[];
	extern const char *position_types[];
	extern const char *preference_bits[];
	extern const char *connected_types[];

	int i, i2, found = 0;
	Object j;
	struct follow_type *fol;
	struct affected_type *aff;

	sprinttype(GET_SEX(k), genders, buf);
	sprintf(buf2, " %s '%s'  IDNum: [%5ld], In room [%5d]\r\n", (!IS_NPC(k) ? "PC" : (!IS_MOB(k) ? "NPC" : "MOB")), GET_NAME(k), GET_IDNUM(k), GET_ROOM_VNUM(IN_ROOM(k)));
	send_to_char(strcat(buf, buf2), ch);

	if (IS_MOB(k)) {
		msg_to_char(ch, "Alias: %s, VNum: [%5d], RNum: [%5d]\r\n", k->player.name, GET_MOB_VNUM(k), GET_MOB_RNUM(k));
		msg_to_char(ch, "L-Des: %s", (k->player.long_descr ? k->player.long_descr : "<None>\r\n"));
		}

	if (!IS_NPC(k)) {
		msg_to_char(ch, "Title: %s&0\r\n", (k->player.title ? k->player.title : "<None>"));

		if (GET_EMAIL(k))
			msg_to_char(ch, "E-mail: %s\r\n", GET_EMAIL(k));
		msg_to_char(ch, "Level: [&6%d&0]\r\n", GET_LEVEL(k));

		strcpy(buf1, (char *) asctime(localtime(&(k->player.time.birth))));
		strcpy(buf2, (char *) asctime(localtime(&(k->player.time.logon))));
		buf1[10] = buf2[10] = '\0';

		msg_to_char(ch, "Created: [%s], Last Logon: [%s], Played [%dh %dm], Age [%d]\r\n", buf1, buf2, k->player.time.played / 3600, ((k->player.time.played % 3600) / 60), age(k)->year);
		}

	display_attributes(k, ch, FALSE);

	msg_to_char(ch, "Health Levels: [&2%d&0/&27&0]  Move pt: [&2%d&0/&2%d&0]\r\n", GET_DAMAGE(k), GET_MOVE(k), GET_MAX_MOVE(k));

	sprinttype(GET_POS(k), position_types, buf2);
	sprintf(buf, "Pos: %s, Fighting: %s", buf2, (FIGHTING(k) ? GET_NAME(FIGHTING(k)) : "Nobody"));

	if (IS_NPC(k)) {
		sprintf(buf + strlen(buf), ", Attack type: %s", attack_hit_text[MOB_ATTACK_TYPE(k)].singular);
		}
	if (k->desc) {
		sprinttype(STATE(k->desc), connected_types, buf2);
		strcat(buf, ", Connected: ");
		strcat(buf, buf2);
		}
	send_to_char(strcat(buf, "\r\n"), ch);

	sprintf(buf, "Idle Timer (in tics) [%d]\r\n", k->char_specials.timer);
	send_to_char(buf, ch);

	if (IS_NPC(k)) {
		sprintbit(MOB_FLAGS(k), action_bits, buf2, TRUE);
		msg_to_char(ch, "NPC flags: &6%s&0\r\n", buf2);
		}
	else {
		sprintbit(PLR_FLAGS(k), player_bits, buf2, TRUE);
		msg_to_char(ch, "PLR: &6%s&0\r\n", buf2);
		sprintbit(PRF_FLAGS(k), preference_bits, buf2, TRUE);
		msg_to_char(ch, "PRF: &6%s&0\r\n", buf2);
		}

	if (IS_MOB(k))
		msg_to_char(ch, "NPC Bare Hand Dam: %d\r\n", MOB_DAMAGE(k));

	sprintf(buf, "Carried: weight: %d, items: %d; ", IS_CARRYING_W(k), IS_CARRYING_N(k));
	for (i = 0, j = k->carrying; j; j = j->next_content, i++);
	sprintf(buf + strlen(buf), "Items in: inventory: %d, ", i);

	for (i = 0, i2 = 0; i < NUM_WEARS; i++)
		if (GET_EQ(k, i))
			i2++;
	sprintf(buf2, "eq: %d\r\n", i2);
	send_to_char(strcat(buf, buf2), ch);

	if (!IS_NPC(k))
		msg_to_char(ch, "Hunger: %d, Thirst: %d, Drunk: %d, Exhaust: %d\r\n", GET_COND(k, FULL), GET_COND(k, THIRST), GET_COND(k, DRUNK), GET_COND(k, TIRED));

	sprintf(buf, "Master is: %s, Followers are:", ((k->master) ? GET_NAME(k->master) : "<none>"));

	for (fol = k->followers; fol; fol = fol->next) {
		sprintf(buf2, "%s %s", found++ ? "," : "", PERS(fol->follower, ch, 1));
		strcat(buf, buf2);
		if (strlen(buf) >= 62) {
			if (fol->next)
				send_to_char(strcat(buf, ",\r\n"), ch);
			else
				send_to_char(strcat(buf, "\r\n"), ch);
			*buf = found = 0;
			}
		}

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

	/* Showing the bitvector */
	sprintbit(AFF_FLAGS(k), affected_bits, buf2, TRUE);
	msg_to_char(ch, "AFF: &6%s&0\r\n", buf2);

	/* Routine to show what spells a char is affected by */
	if (k->affected) {
		for (aff = k->affected; aff; aff = aff->next) {
			*buf2 = '\0';

			sprintf(buf, "TYPE: (%3dhr) &6%s&0 ", aff->duration + 1, affect_types[aff->type]);

			if (aff->modifier) {
				sprintf(buf2, "%+d to %s", aff->modifier, apply_types[(int) aff->location]);
				strcat(buf, buf2);
				}
			if (aff->bitvector) {
				if (*buf2)
					strcat(buf, ", sets ");
				else
					strcat(buf, "sets ");
				sprintbit(aff->bitvector, affected_bits, buf2, TRUE);
				strcat(buf, buf2);
				}
			if (aff->disc_bit) {
				if (*buf2)
					strcat(buf, ", sets ");
				else
					strcat(buf, "sets ");
				sprintbit(aff->disc_bit, dsc_bits, buf2, TRUE);
				strcat(buf, buf2);
				}
			send_to_char(strcat(buf, "\r\n"), ch);
			}
		}
	}


ACMD(do_stat) {
	Creature victim;
	Object obj;
	struct char_file_u tmp_store;
	int tmp;

	half_chop(argument, buf1, buf2);

	if (!*buf1) {
		send_to_char("Stats on who or what?\r\n", ch);
		return;
		}
	else if (is_abbrev(buf1, "room")) {
		do_stat_room(ch);
		}
	else if (is_abbrev(buf1, "mob")) {
		if (!*buf2)
			send_to_char("Stats on which mobile?\r\n", ch);
		else {
			if ((victim = get_char_vis(ch, buf2, FIND_CHAR_WORLD)) != NULL)
				do_stat_character(ch, victim);
			else
				send_to_char("No such mobile around.\r\n", ch);
			}
		}
	else if (is_abbrev(buf1, "player")) {
		if (!*buf2) {
			send_to_char("Stats on which player?\r\n", ch);
			}
		else {
			if ((victim = get_player_vis(ch, buf2, FIND_CHAR_WORLD)) != NULL)
				do_stat_character(ch, victim);
			else
				send_to_char("No such player around.\r\n", ch);
			}
		}
	else if (is_abbrev(buf1, "file")) {
		if (!*buf2) {
			send_to_char("Stats on which player?\r\n", ch);
			}
		else {
			CREATE(victim, struct char_data, 1);
			clear_char(victim);
			if (load_char(buf2, &tmp_store) > NOBODY) {
				store_to_char(&tmp_store, victim);
				victim->player.time.logon = tmp_store.last_logon;
				char_to_room(victim, 0);
				if (GET_LEVEL(victim) > GET_LEVEL(ch))
					send_to_char("Sorry, you can't do that.\r\n", ch);
				else
					do_stat_character(ch, victim);
				extract_char(victim);
				}
			else {
				send_to_char("There is no such player.\r\n", ch);
				free(victim);
				}
			}
		}
	else if (is_abbrev(buf1, "object")) {
		if (!*buf2)
			send_to_char("Stats on which object?\r\n", ch);
		else {
			if ((obj = get_obj_vis(ch, buf2)) != NULL)
				do_stat_object(ch, obj);
			else
				send_to_char("No such object around.\r\n", ch);
			}
		}
	else {
		if ((obj = get_object_in_equip_vis(ch, buf1, ch->equipment, &tmp)) != NULL)
			do_stat_object(ch, obj);
		else if ((obj = get_obj_in_list_vis(ch, buf1, ch->carrying)) != NULL)
			do_stat_object(ch, obj);
		else if ((victim = get_char_vis(ch, buf1, FIND_CHAR_ROOM)) != NULL)
			do_stat_character(ch, victim);
		else if ((obj = get_obj_in_list_vis(ch, buf1, world[ch->in_room].contents)) != NULL)
			do_stat_object(ch, obj);
		else if ((victim = get_char_vis(ch, buf1, FIND_CHAR_WORLD)) != NULL)
			do_stat_character(ch, victim);
		else if ((obj = get_obj_vis(ch, buf1)) != NULL)
			do_stat_object(ch, obj);
		else
			send_to_char("Nothing around by that name.\r\n", ch);
		}
	}


/* Stop a person from snooping (cannot be used on the government) */
void stop_snooping(Creature ch) {
	if (!ch->desc->snooping)
		send_to_char("You aren't snooping anyone.\r\n", ch);
	else {
		send_to_char("You stop snooping.\r\n", ch);
		ch->desc->snooping->snoop_by = NULL;
		ch->desc->snooping = NULL;
 		}
	}


ACMD(do_snoop) {
	Creature victim, tch;

	if (!ch->desc)
		return;

	one_argument(argument, arg);

	if (!*arg)
		stop_snooping(ch);
	else if (!(victim = get_char_vis(ch, arg, FIND_CHAR_WORLD)))
		send_to_char("No such person around.\r\n", ch);
	else if (!victim->desc)
		send_to_char("There's no link.. nothing to snoop.\r\n", ch);
	else if (victim == ch)
		stop_snooping(ch);
	else if (victim->desc->snoop_by)
		send_to_char("Busy already. \r\n", ch);
	else if (victim->desc->snooping == ch->desc)
		send_to_char("Don't be stupid.\r\n", ch);
	else {
		if (victim->desc->original)
			tch = victim->desc->original;
		else
			tch = victim;

		if (GET_LEVEL(tch) >= GET_LEVEL(ch)) {
			send_to_char("You can't.\r\n", ch);
			return;
			}
		send_to_char(OK, ch);

		if (ch->desc->snooping)
			ch->desc->snooping->snoop_by = NULL;

		ch->desc->snooping = victim->desc;
		victim->desc->snoop_by = ch->desc;
		}
	}


ACMD(do_switch) {
	Creature victim;

	one_argument(argument, arg);

	if (ch->desc->original)
		send_to_char("You're already switched.\r\n", ch);
	else if (!*arg)
		send_to_char("Switch with who?\r\n", ch);
	else if (!(victim = get_char_vis(ch, arg, FIND_CHAR_WORLD)))
		send_to_char("No such character.\r\n", ch);
	else if (ch == victim)
		send_to_char("Hee hee... we are jolly funny today, eh?\r\n", ch);
	else if (victim->desc)
		send_to_char("You can't do that, the body is already in use!\r\n", ch);
	else if ((GET_LEVEL(ch) < LVL_IMPL) && !IS_NPC(victim))
		send_to_char("You aren't holy enough to use a mortal's body.\r\n", ch);
	else {
		send_to_char(OK, ch);

		ch->desc->character = victim;
		ch->desc->original = ch;

		victim->desc = ch->desc;
		ch->desc = NULL;
		}
	}


ACMD(do_return) {
	if (ch->desc && ch->desc->original) {
		send_to_char("You return to your original body.\r\n", ch);

		/*
		 * If someone switched into your original body, disconnect them.
		 *   - JE 2/22/95
		 *
		 * Zmey: here we put someone switched in our body to disconnect state
		 * but we must also NULL his pointer to our character, otherwise
		 * close_socket() will damage our character's pointer to our descriptor
		 * (which is assigned below in this function). 12/17/99
		 */

		if (ch->desc->original->desc) {
			ch->desc->original->desc->character = NULL;
			STATE(ch->desc->original->desc) = CON_DISCONNECT;
			}

		/* Now our descriptor points to our original body. */
		ch->desc->character = ch->desc->original;
		ch->desc->original = NULL;

		/* And our body's pointer to descriptor now points to our descriptor. */
		ch->desc->character->desc = ch->desc;
		ch->desc = NULL;
		}
	}


ACMD(do_load) {
	Creature mob;
	Object obj;
	mob_vnum number;
	mob_rnum r_num;

	two_arguments(argument, buf, buf2);

	if (!*buf || !*buf2 || !isdigit(*buf2)) {
		send_to_char("Usage: load { obj | mob } <number>\r\n", ch);
		return;
		}
	if ((number = atoi(buf2)) < 0) {
		send_to_char("A NEGATIVE number??\r\n", ch);
		return;
		}
	if (is_abbrev(buf, "mob")) {
		if ((r_num = real_mobile(number)) < 0) {
			send_to_char("There is no monster with that number.\r\n", ch);
			return;
			}
		mob = read_mobile(r_num, REAL);
		char_to_room(mob, ch->in_room);

		act("$n makes a quaint, magical gesture with one hand.", TRUE, ch, 0, 0, TO_ROOM);
		act("$n has created $N!", FALSE, ch, 0, mob, TO_ROOM);
		act("You create $N.", FALSE, ch, 0, mob, TO_CHAR);
		}
	else if (is_abbrev(buf, "obj")) {
		if ((r_num = real_object(number)) < 0) {
			send_to_char("There is no object with that number.\r\n", ch);
			return;
			}
		obj = read_object(r_num, REAL);
		if (CAN_WEAR(obj, ITEM_WEAR_TAKE))
			obj_to_char(obj, ch);
		else
			obj_to_room(obj, ch->in_room);
		act("$n makes a strange magical gesture.", TRUE, ch, 0, 0, TO_ROOM);
		act("$n has created $p!", FALSE, ch, obj, 0, TO_ROOM);
		act("You create $p.", FALSE, ch, obj, 0, TO_CHAR);
		}
	else
		send_to_char("That'll have to be either 'obj' or 'mob'.\r\n", ch);
	}


ACMD(do_vstat) {
	Creature mob;
	Object obj;
	mob_vnum number;	/* or obj_vnum ... */
	mob_rnum r_num;		/* or obj_rnum ... */

	two_arguments(argument, buf, buf2);

	if (!*buf || !*buf2 || !isdigit(*buf2)) {
		send_to_char("Usage: vstat { obj | mob } <number>\r\n", ch);
		return;
		}
	if ((number = atoi(buf2)) < 0) {
		send_to_char("A NEGATIVE number??\r\n", ch);
		return;
		}
	if (is_abbrev(buf, "mob")) {
		if ((r_num = real_mobile(number)) < 0) {
			send_to_char("There is no monster with that number.\r\n", ch);
			return;
			}
		mob = read_mobile(r_num, REAL);
		char_to_room(mob, 0);
		do_stat_character(ch, mob);
		extract_char(mob);
		}
	else if (is_abbrev(buf, "obj")) {
		if ((r_num = real_object(number)) < 0) {
			send_to_char("There is no object with that number.\r\n", ch);
			return;
			}
		obj = read_object(r_num, REAL);
		do_stat_object(ch, obj);
		extract_obj(obj);
		}
	else
		send_to_char("That'll have to be either 'obj' or 'mob'.\r\n", ch);
	}


ACMD(do_purge) {
	Creature vict, next_v;
	Object obj;

	one_argument(argument, buf);

	if (*buf) {			/* argument supplied. destroy single object or char */
		if ((vict = get_char_vis(ch, buf, FIND_CHAR_ROOM)) != NULL) {
			if (!REAL_NPC(vict) && (GET_REAL_LEVEL(ch) <= GET_REAL_LEVEL(vict))) {
				send_to_char("Fuuuuuuuuu!\r\n", ch);
				return;
				}
			act("$n disintegrates $N.", FALSE, ch, 0, vict, TO_NOTVICT);

			if (!REAL_NPC(vict)) {
				syslog(GET_INVIS_LEV(ch), TRUE, "GC: %s has purged %s.", GET_NAME(ch), GET_NAME(vict));
				if (vict->desc) {
					SAVE_CHAR(vict);
					STATE(vict->desc) = CON_CLOSE;
					vict->desc->character = NULL;
					vict->desc = NULL;
					}
				}
			extract_char(vict);
			}
		else if ((obj = get_obj_in_list_vis(ch, buf, world[ch->in_room].contents)) != NULL) {
			act("$n destroys $p.", FALSE, ch, obj, 0, TO_ROOM);
			extract_obj(obj);
			}
		else {
			send_to_char("Nothing here by that name.\r\n", ch);
			return;
			}

		send_to_char(OK, ch);
		}
	else {			/* no argument. clean out the room */
		act("$n gestures... You are surrounded by scorching flames!", FALSE, ch, 0, 0, TO_ROOM);
		send_to_room("The world seems a little cleaner.\r\n", ch->in_room);

		for (vict = world[ch->in_room].people; vict; vict = next_v) {
			next_v = vict->next_in_room;
			if (REAL_NPC(vict))
				extract_char(vict);
			}

		while (world[ch->in_room].contents)
			extract_obj(world[ch->in_room].contents);
		}
	}


ACMD(do_advance) {
	void do_start(Creature ch);
	Creature victim;
	char *name = arg, *level = buf2;
	int newlevel, oldlevel;

	two_arguments(argument, name, level);

	if (*name) {
   		if (!(victim = get_char_vis(ch, name, FIND_CHAR_WORLD))) {
			send_to_char("That player is not here.\r\n", ch);
			return;
			}
		}
	else {
		send_to_char("Advance who?\r\n", ch);
		return;
		}

	if (GET_LEVEL(ch) <= GET_LEVEL(victim)) {
		send_to_char("Maybe that's not such a great idea.\r\n", ch);
		return;
		}
	if (IS_NPC(victim)) {
		send_to_char("NO!  Not on NPC's.\r\n", ch);
		return;
		}
	if (!*level || (newlevel = atoi(level)) <= 0) {
		send_to_char("That's not a level!\r\n", ch);
		return;
		}
	if (newlevel > LVL_IMPL) {
		sprintf(buf, "%d is the highest possible level.\r\n", LVL_IMPL);
		send_to_char(buf, ch);
		return;
		}
	if (newlevel > GET_LEVEL(ch)) {
		send_to_char("Yeah, right.\r\n", ch);
		return;
		}
	if (newlevel == GET_LEVEL(victim)) {
		send_to_char("They are already at that level.\r\n", ch);
		return;
		}
	oldlevel = GET_LEVEL(victim);
	if (newlevel < GET_LEVEL(victim)) {
		do_start(victim);
		GET_LEVEL(victim) = newlevel;
		GET_IMM_LEV(victim) = IS_IMMORTAL(victim) ? LVL_TOP - GET_LEVEL(victim) : -1;
		send_to_char("You are momentarily enveloped by darkness!\r\nYou feel somewhat diminished.\r\n", victim);
		}
	else {
		act("$n makes some strange gestures.\r\n"
			"A strange feeling comes upon you,\r\n"
			"Like a giant hand, light comes down\r\n"
			"from above, grabbing your body, that\r\n"
			"begins to pulse with colored lights\r\n"
			"from inside.\r\n\r\n"
			"Your head seems to be filled with demons\r\n"
			"from another plane as your body dissolves\r\n"
			"to the elements of time and space itself.\r\n"
			"Suddenly a silent explosion of light\r\n"
			"snaps you back to reality.\r\n\r\n"
			"You feel slightly different.", FALSE, ch, 0, victim, TO_VICT);
		}

	send_to_char(OK, ch);

	if (newlevel < oldlevel)
		syslog(GET_INVIS_LEV(ch), TRUE, "LVL: %s demoted %s from level %d to %d.", GET_NAME(ch), GET_NAME(victim), oldlevel, newlevel);
	else
		syslog(GET_INVIS_LEV(ch), TRUE, "LVL: %s has promoted %s to level %d (from %d)", GET_NAME(ch), GET_NAME(victim), newlevel, oldlevel);

	GET_LEVEL(victim) = newlevel;
	GET_IMM_LEV(victim) = IS_IMMORTAL(victim) ? LVL_TOP - GET_LEVEL(victim) : -1;
	SAVE_CHAR(victim);
	check_autowiz(ch);
	}


ACMD(do_restore) {
	Creature vict;
	int i;

	one_argument(argument, buf);
	if (!*buf)
		send_to_char("Whom do you wish to restore?\r\n", ch);
	else if (!(vict = get_char_vis(ch, buf, FIND_CHAR_WORLD)))
		send_to_char(NOPERSON, ch);
	else {
		GET_DAMAGE(vict) = GET_AGG_DAMAGE(vict) = 0;
		GET_MOVE(vict) = GET_MAX_MOVE(vict);

		if (GET_POS(vict) < POS_SLEEPING)
			GET_POS(vict) = POS_STANDING;

		if ((GET_LEVEL(ch) >= LVL_GOD) && (GET_LEVEL(vict) >= LVL_GOD)) {
			for (i = 0; i < NUM_CONDS; i++)
				GET_COND(vict, i) = -1;

			SET_BIT(PRF_FLAGS(vict), PRF_HOLYLIGHT);

			for (i = 0; i < NUM_LANGS; i++)
				SET_BIT(GET_LANGUAGES(vict), LANGUAGE_BIT(i));

			for (i = 0; i < NUM_ABILITIES; i++)
				vict->player_specials->saved.talents[i] = MAX(vict->player_specials->saved.talents[i], (IS_IMMORTAL(vict) ? att_max(vict) : 3));
			for (i = 0; i < NUM_ABILITIES; i++)
				vict->player_specials->saved.skills[i] = MAX(vict->player_specials->saved.skills[i], (IS_IMMORTAL(vict) ? att_max(vict) : 3));
			for (i = 0; i < NUM_ABILITIES; i++)
				vict->player_specials->saved.knowledges[i] = MAX(vict->player_specials->saved.knowledges[i], (IS_IMMORTAL(vict) ? att_max(vict) : 3));

			vict->real_abils.strength = MAX(vict->real_abils.strength, (IS_IMMORTAL(vict) ? att_max(vict) : 3));
			vict->real_abils.dexterity = MAX(vict->real_abils.dexterity, (IS_IMMORTAL(vict) ? att_max(vict) : 3));
			vict->real_abils.stamina = MAX(vict->real_abils.stamina, (IS_IMMORTAL(vict) ? att_max(vict) : 3));
			vict->real_abils.charisma = MAX(vict->real_abils.charisma, (IS_IMMORTAL(vict) ? att_max(vict) : 3));
			vict->real_abils.manipulation = MAX(vict->real_abils.manipulation, (IS_IMMORTAL(vict) ? att_max(vict) : 3));
			vict->real_abils.appearance = MAX(vict->real_abils.appearance, (IS_IMMORTAL(vict) ? att_max(vict) : 3));
			vict->real_abils.perception = MAX(vict->real_abils.perception, (IS_IMMORTAL(vict) ? att_max(vict) : 3));
			vict->real_abils.intelligence = MAX(vict->real_abils.intelligence, (IS_IMMORTAL(vict) ? att_max(vict) : 3));
			vict->real_abils.wits = MAX(vict->real_abils.wits, (IS_IMMORTAL(vict) ? att_max(vict) : 3));

			vict->points.max_willpower = vict->points.willpower = MAX(vict->points.max_willpower, (IS_IMMORTAL(vict) ? 10 : 5));
			vict->points.humanity = MAX(vict->points.humanity, (IS_IMMORTAL(vict) ? 10 : 5));

			/* Set the blood to max */
			if (IS_VAMPIRE(ch)){
				int bl;
				switch (GET_GENERATION(ch)) {
					case 1:		bl = 100;
					case 2:		bl = 100;
					case 3:		bl = 100;
					case 4:		bl = 50;
					case 5:		bl = 40;
					case 6:		bl = 30;
					case 7:		bl = 20;
					default:	bl = MAX(10, 10+13-GET_GENERATION(ch));
				}
				vict->points.blood = bl;
			}

			SET_BIT(PLR_FLAGS(vict), PLR_NOSLEEP);

			affect_total(vict);
			}
		update_pos(vict);
		send_to_char(OK, ch);
		act("You have been fully healed by $N!", FALSE, vict, 0, ch, TO_CHAR);
		}
	}


/* Immortal visible command, different than mortals' */
void perform_immort_vis(Creature ch) {
	if (GET_INVIS_LEV(ch) == 0 && !AFF_FLAGGED(ch, AFF_HIDE)) {
		send_to_char("You are already fully visible.\r\n", ch);
		return;
		}

	GET_INVIS_LEV(ch) = 0;
	appear(ch);
	send_to_char("You are now fully visible.\r\n", ch);
	}


/* Turns an immortal invisible */
void perform_immort_invis(Creature ch, int level) {
	Creature tch;

	if (IS_NPC(ch))
		return;

	for (tch = world[ch->in_room].people; tch; tch = tch->next_in_room) {
		if (tch == ch)
			continue;
		if (GET_LEVEL(tch) >= GET_INVIS_LEV(ch) && GET_LEVEL(tch) < level)
			act("You blink and suddenly realize that $n is gone.", FALSE, ch, 0, tch, TO_VICT);
		if (GET_LEVEL(tch) < GET_INVIS_LEV(ch) && GET_LEVEL(tch) >= level)
			act("You suddenly realize that $n is standing beside you.", FALSE, ch, 0, tch, TO_VICT);
		}

	GET_INVIS_LEV(ch) = level;
	sprintf(buf, "Your invisibility level is %d.\r\n", level);
	send_to_char(buf, ch);
	}


ACMD(do_invis) {
	int level;

	if (IS_NPC(ch)) {
		send_to_char("You can't do that!\r\n", ch);
		return;
		}

	one_argument(argument, arg);
	if (!*arg) {
		if (GET_INVIS_LEV(ch) > 0)
			perform_immort_vis(ch);
		else
			perform_immort_invis(ch, GET_LEVEL(ch));
		}
	else {
		level = atoi(arg);
		if (level > GET_LEVEL(ch))
			send_to_char("You can't go invisible above your own level.\r\n", ch);
		else if (level < 1)
			perform_immort_vis(ch);
		else
			perform_immort_invis(ch, level);
		}
	}


ACMD(do_gecho) {
	Descr pt;

	skip_spaces(&argument);
	delete_doubledollar(argument);

	if (PLR_FLAGGED(ch, PLR_MUTED))
		msg_to_char(ch, "You can't use gecho while muted.\r\n");
	else if (!*argument)
		send_to_char("That must be a mistake...\r\n", ch);
	else {
		sprintf(buf, "%s\r\n", argument);
		for (pt = descriptor_list; pt; pt = pt->next)
			if (STATE(pt) == CON_PLAYING && pt->character && pt->character != ch)
				send_to_char(buf, pt->character);
		if (PRF_FLAGGED(ch, PRF_NOREPEAT))
			send_to_char(OK, ch);
		else
			send_to_char(buf, ch);
		}
	}


ACMD(do_poofset) {
	char **msg;

	switch (subcmd) {
		case SCMD_POOFIN:    msg = &(POOFIN(ch));    break;
		case SCMD_POOFOUT:   msg = &(POOFOUT(ch));   break;
		default:    return;
		}

	skip_spaces(&argument);

	delete_doubledollar(argument);

	if (*msg)
		free(*msg);

	if (!*argument)
		*msg = NULL;
	else
		*msg = str_dup(argument);

	send_to_char(OK, ch);
	}


ACMD(do_dc) {
	Descr d;
	int num_to_dc;

	one_argument(argument, arg);
	if (!(num_to_dc = atoi(arg))) {
		send_to_char("Usage: DC <user number> (type USERS for a list)\r\n", ch);
		return;
		}
	for (d = descriptor_list; d && d->desc_num != num_to_dc; d = d->next);

	if (!d) {
		send_to_char("No such connection.\r\n", ch);
		return;
		}
	if (d->character && GET_LEVEL(d->character) >= GET_LEVEL(ch)) {
		if (!CAN_SEE(ch, d->character))
			send_to_char("No such connection.\r\n", ch);
		else
			send_to_char("Umm.. maybe that's not such a good idea...\r\n", ch);
		return;
		}

	/* We used to just close the socket here using close_socket(), but
	 * various people pointed out this could cause a crash if you're
	 * closing the person below you on the descriptor list.  Just setting
	 * to CON_CLOSE leaves things in a massively inconsistent state so I
	 * had to add this new flag to the descriptor. -je
	 *
	 * It is a much more logical extension for a CON_DISCONNECT to be used
	 * for in-game socket closes and CON_CLOSE for out of game closings.
	 * This will retain the stability of the close_me hack while being
	 * neater in appearance. -gg 12/1/97
	 *
	 * For those unlucky souls who actually manage to get disconnected
	 * by two different immortals in the same 1/10th of a second, we have
	 * the below 'if' check. -gg 12/17/99
	 */
	if (STATE(d) == CON_DISCONNECT || STATE(d) == CON_CLOSE)
		send_to_char("They're already being disconnected.\r\n", ch);
	else {
		/*
		 * Remember that we can disconnect people not in the game and
		 * that rather confuses the code when it expected there to be
		 * a character context.
		 */
		if (STATE(d) == CON_PLAYING)
			STATE(d) = CON_DISCONNECT;
		else
			STATE(d) = CON_CLOSE;

		sprintf(buf, "Connection #%d closed.\r\n", num_to_dc);
		send_to_char(buf, ch);
		log("Connection closed by %s.", GET_NAME(ch));
		}
	}


ACMD(do_wizlock) {
	extern int wizlock_level;
	extern char *wizlock_message;
	int value;
	const char *when;

	argument = one_argument(argument, arg);
	if (*arg) {
		value = atoi(arg);
		if (value < 0 || value > GET_LEVEL(ch)) {
			send_to_char("Invalid wizlock value.\r\n", ch);
			return;
			}
		if (wizlock_message) {
			free(wizlock_message);
			wizlock_message = NULL;
			}
		skip_spaces(&argument);
		if (*argument)
			wizlock_message = str_dup(strcat(argument, "\r\n"));
		wizlock_level = value;
		when = "now";
		}
	else
		when = "currently";

	switch (wizlock_level) {
		case 0:
			sprintf(buf, "The game is %s completely open.\r\n", when);
			wizlock_message = NULL;
			break;
		case 1:
			sprintf(buf, "The game is %s closed to new players.\r\n", when);
			break;
		default:
			sprintf(buf, "Only level %d and above may enter the game %s.\r\n", wizlock_level, when);
			break;
		}
	msg_to_char(ch, "%s%s%s", buf, wizlock_message ? wizlock_message : "", wizlock_message ? "\r\n" : "");
	}


ACMD(do_date) {
	extern time_t boot_time;
	char *tmstr;
	time_t mytime;
	int d, h, m;

	if (subcmd == SCMD_DATE)
		mytime = time(0);
	else
		mytime = boot_time;

	tmstr = (char *) asctime(localtime(&mytime));
	*(tmstr + strlen(tmstr) - 1) = '\0';

	if (subcmd == SCMD_DATE)
		sprintf(buf, "Current machine time: %s\r\n", tmstr);
	else {
		mytime = time(0) - boot_time;
		d = mytime / 86400;
		h = (mytime / 3600) % 24;
		m = (mytime / 60) % 60;

		sprintf(buf, "Up since %s: %d day%s, %d:%02d\r\n", tmstr, d, ((d == 1) ? "" : "s"), h, m);
		}

	send_to_char(buf, ch);
	}


ACMD(do_last) {
	extern const char *level_names[][2];

	struct char_file_u chdata;
	char status[10];

	one_argument(argument, arg);

	if (!*arg)
		send_to_char("For whom do you wish to search?\r\n", ch);
	else if (load_char(arg, &chdata) < 0)
		send_to_char("There is no such player.\r\n", ch);
	else if ((chdata.level > GET_LEVEL(ch)) && (GET_LEVEL(ch) < LVL_IMPL))
		send_to_char("You are not sufficiently godly for that!\r\n", ch);
	else {
		strcpy(status, level_names[(int) chdata.level][0]);
		msg_to_char(ch, "[%5ld] [%s] %-12s : %-18s : %-20s\r\n", chdata.char_specials_saved.idnum, status, chdata.name, chdata.host, ctime(&chdata.last_logon));
		}
	}


ACMD(do_force) {
	Descr i, next_desc;
	Creature vict, next_force;
	char to_force[MAX_INPUT_LENGTH + 2];

	half_chop(argument, arg, to_force);

	if (!*arg || !*to_force)
		send_to_char("Whom do you wish to force do what?\r\n", ch);
	else if ((GET_LEVEL(ch) < LVL_IMPL) || (str_cmp("all", arg) && str_cmp("room", arg))) {
		if (!(vict = get_char_vis(ch, arg, FIND_CHAR_WORLD)))
			send_to_char(NOPERSON, ch);
		else if (!REAL_NPC(vict) && GET_REAL_LEVEL(ch) <= GET_REAL_LEVEL(vict))
			send_to_char("No, no, no!\r\n", ch);
		else {
			send_to_char(OK, ch);
			sprintf(buf1, "$n has forced you to '%s'.", to_force);
			act(buf1, TRUE, ch, NULL, vict, TO_VICT);
			syslog(GET_INVIS_LEV(ch), TRUE, "GC: %s forced %s to %s", GET_NAME(ch), GET_NAME(vict), to_force);
			command_interpreter(vict, to_force);
			}
		}
	else if (!str_cmp("room", arg)) {
		send_to_char(OK, ch);
		syslog(GET_INVIS_LEV(ch), TRUE, "GC: %s forced room %d to %s", GET_NAME(ch), GET_ROOM_VNUM(IN_ROOM(ch)), to_force);

		for (vict = world[ch->in_room].people; vict; vict = next_force) {
			next_force = vict->next_in_room;
			if (!REAL_NPC(vict) && GET_REAL_LEVEL(vict) >= GET_REAL_LEVEL(ch))
				continue;
			sprintf(buf1, "$n has forced you to '%s'.", to_force);
			act(buf1, TRUE, ch, NULL, vict, TO_VICT);
			command_interpreter(vict, to_force);
			}
		}
	else { /* force all */
		send_to_char(OK, ch);
		syslog(GET_INVIS_LEV(ch), TRUE, "GC: %s forced all to %s", GET_NAME(ch), to_force);

		for (i = descriptor_list; i; i = next_desc) {
			next_desc = i->next;

			if (STATE(i) != CON_PLAYING || !(vict = i->character) || (!REAL_NPC(vict) && GET_REAL_LEVEL(vict) >= GET_REAL_LEVEL(ch)))
				continue;
			sprintf(buf1, "$n has forced you to '%s'.", to_force);
			act(buf1, TRUE, ch, NULL, vict, TO_VICT);
			command_interpreter(vict, to_force);
			}
		}
	}


/*
 *  General fn for wizcommands of the sort: cmd <player>
 */

ACMD(do_wizutil) {
	Creature vict;
	long result;

	one_argument(argument, arg);

	if (!*arg)
		send_to_char("Yes, but for whom?!?\r\n", ch);
	else if (!(vict = get_char_vis(ch, arg, FIND_CHAR_WORLD)))
		send_to_char("There is no such player.\r\n", ch);
	else if (IS_NPC(vict))
		send_to_char("You can't do that to a mob!\r\n", ch);
	else if (GET_LEVEL(vict) > GET_LEVEL(ch))
		send_to_char("Hmmm...you'd better not.\r\n", ch);
	else {
		switch (subcmd) {
			case SCMD_NOTITLE:
				result = PLR_TOG_CHK(vict, PLR_NOTITLE);
				syslog(GET_INVIS_LEV(ch), TRUE, "GC: Notitle %s for %s by %s.", ONOFF(result), GET_NAME(vict), GET_NAME(ch));
				msg_to_char(ch, "Notitle %s for %s.\r\n", ONOFF(result), GET_NAME(vict));
				break;
			case SCMD_MUTE:
				result = PLR_TOG_CHK(vict, PLR_MUTED);
				syslog(GET_INVIS_LEV(ch), TRUE, "GC: Mute %s for %s by %s.", ONOFF(result), GET_NAME(vict), GET_NAME(ch));
				msg_to_char(ch, "Mute %s for %s.\r\n", ONOFF(result), GET_NAME(vict));
				break;
			case SCMD_FREEZE:
				if (ch == vict) {
					send_to_char("Oh, yeah, THAT'S real smart...\r\n", ch);
					return;
					}
				if (PLR_FLAGGED(vict, PLR_FROZEN)) {
					send_to_char("Your victim is already pretty cold.\r\n", ch);
					return;
					}
				SET_BIT(PLR_FLAGS(vict), PLR_FROZEN);
				send_to_char("A bitter wind suddenly rises and drains every erg of heat from your body!\r\nYou feel frozen!\r\n", vict);
				send_to_char("Frozen.\r\n", ch);
				act("A sudden cold wind conjured from nowhere freezes $n!", FALSE, vict, 0, 0, TO_ROOM);
				syslog(GET_INVIS_LEV(ch), TRUE, "GC: %s frozen by %s.", GET_NAME(vict), GET_NAME(ch));
				break;
			case SCMD_THAW:
				if (!PLR_FLAGGED(vict, PLR_FROZEN)) {
					send_to_char("Sorry, your victim is not morbidly encased in ice at the moment.\r\n", ch);
					return;
					}
				syslog(GET_INVIS_LEV(ch), TRUE, "GC: %s un-frozen by %s.", GET_NAME(vict), GET_NAME(ch));
				REMOVE_BIT(PLR_FLAGS(vict), PLR_FROZEN);
				send_to_char("A fireball suddenly explodes in front of you, melting the ice!\r\nYou feel thawed.\r\n", vict);
				send_to_char("Thawed.\r\n", ch);
				act("A sudden fireball conjured from nowhere thaws $n!", FALSE, vict, 0, 0, TO_ROOM);
				break;
			default:
				log("SYSERR: Unknown subcmd %d passed to do_wizutil (%s)", subcmd, __FILE__);
				break;
			}
		SAVE_CHAR(vict);
		}
	}


ACMD(do_show) {
	extern int buf_switches, buf_largecount, buf_overflows;
	struct char_file_u vbuf;
	int i, j, k, l, con;		/* i, j, k to specifics? */
	char self = 0;
	Creature vict;
	Object obj;
	Descr d, nd;
	char field[MAX_INPUT_LENGTH], value[MAX_INPUT_LENGTH], birth[80];

	struct show_struct {
		const char *cmd;
		const char level;
		} fields[] = {
			{ "nothing",	0  },				/* 0 */
			{ "player",		LVL_START_IMM },
			{ "rent",		LVL_START_IMM },
			{ "stats",		LVL_GOD },
			{ "site",		LVL_ASST },
			{ "email",		LVL_ASST },		/* 5 */
			{ "commons",	LVL_ASST },
			{ "emails",		LVL_TOP },
			{ "players",	LVL_ASST },
			{ "\n", 0 }
			};

	skip_spaces(&argument);

	if (!*argument) {
		strcpy(buf, "Show options:\r\n");
		for (j = 0, i = 1; fields[i].level; i++)
			if (fields[i].level <= GET_LEVEL(ch))
				sprintf(buf + strlen(buf), "%-15s%s", fields[i].cmd, (!(++j % 5) ? "\r\n" : ""));
		strcat(buf, "\r\n");
		send_to_char(buf, ch);
		return;
		}

	strcpy(arg, two_arguments(argument, field, value));

	for (l = 0; *(fields[l].cmd) != '\n'; l++)
		if (!strncmp(field, fields[l].cmd, strlen(field)))
			break;

	if (GET_LEVEL(ch) < fields[l].level) {
		send_to_char("You are not godly enough for that!\r\n", ch);
		return;
		}
	if (!strcmp(value, "."))
		self = 1;
	buf[0] = '\0';
	switch (l) {
		case 1:			/* player */
			if (!*value) {
				send_to_char("A name would help.\r\n", ch);
				return;
				}

			if (load_char(value, &vbuf) < 0) {
				send_to_char("There is no such player.\r\n", ch);
     			return;
				}
			sprintf(buf, "Player: %-12s (%s) [%d]\r\n", vbuf.name, genders[(int) vbuf.sex], vbuf.level);
			strcpy(birth, ctime(&vbuf.birth));
			sprintf(buf + strlen(buf), "Started: %-20.16s  Last: %-20.16s  Played: %3dh %2dm\r\n", birth, ctime(&vbuf.last_logon), (int) (vbuf.played / 3600), (int) (vbuf.played / 60 % 60));
			send_to_char(buf, ch);
			break;
		case 2:
			if (!*value) {
				send_to_char("A name would help.\r\n", ch);
				return;
				}
			Crash_listrent(ch, value);
			break;
		case 3:
			i = j = k = con = 0;
			for (vict = character_list; vict; vict = vict->next) {
				if (IS_NPC(vict))
					j++;
				else if (CAN_SEE(ch, vict)) {
					i++;
					if (vict->desc)
						con++;
					}
				}
			for (obj = object_list; obj; obj = obj->next)
				k++;
			strcpy(buf, "Current stats:\r\n");
			sprintf(buf + strlen(buf), "  %6d players in game  %6d connected\r\n", i, con);
			sprintf(buf + strlen(buf), "  %6d registered\r\n", top_of_p_table + 1);
			sprintf(buf + strlen(buf), "  %6d mobiles          %6d prototypes\r\n", j, top_of_mobt + 1);
			sprintf(buf + strlen(buf), "  %6d objects          %6d prototypes\r\n", k, top_of_objt + 1);
			sprintf(buf + strlen(buf), "  %6d rooms            %6d zones\r\n", top_of_world + 1, top_of_zone_table + 1);
			sprintf(buf + strlen(buf), "  %6d large bufs\r\n", buf_largecount);
			sprintf(buf + strlen(buf), "  %6d buf switches     %6d overflows\r\n", buf_switches, buf_overflows);
			send_to_char(buf, ch);
			break;
		case 4:
			if (!*value) {
				msg_to_char(ch, "Locate players from what site?\r\n");
				return;
				}
			*buf = '\0';
			k = 0;
			for (j = 0; j <= top_of_p_table; j++) {
				load_char((player_table + j)->name, &vbuf);
				if (!IS_SET(vbuf.char_specials_saved.act, PLR_DELETED | PLR_SLAIN))
					if (str_str(vbuf.host, value))
						sprintf(buf, "%s %-15.15s %s", buf, vbuf.name, ((++k % 3)) ? "|" : "\r\n");
				}
			msg_to_char(ch, "Players from site %s:\r\n", value);
			if (*buf)
				msg_to_char(ch, buf);
			else
			msg_to_char(ch, " none");
			break;
		case 5:
			if (!*value) {
				msg_to_char(ch, "Locate players from what address?\r\n");
				return;
				}
			*buf = '\0';
			k = 0;
			for (j = 0; j <= top_of_p_table; j++) {
				load_char((player_table + j)->name, &vbuf);
				if (!IS_SET(vbuf.char_specials_saved.act, PLR_DELETED | PLR_SLAIN))
					if (str_str(vbuf.email, value))
						sprintf(buf, "%s %-15.15s %s", buf, vbuf.name, ((++k % 3)) ? "|" : "\r\n");
				}
			msg_to_char(ch, "Players from e-mail address %s:\r\n", value);
			if (*buf)
				msg_to_char(ch, buf);
			else
				msg_to_char(ch, " none");
			break;
		case 6:
			*buf = '\0';
			for (d = descriptor_list; d; d = d->next)
				for (nd = descriptor_list; nd; nd = nd->next)
					if (!str_cmp(d->host, nd->host) && d != nd && (!d->character || !PLR_FLAGGED(d->character, PLR_IPMASK))) {
						sprintf(buf + strlen(buf), "%s\r\n", d->character ? GET_NAME(d->character) : "<No Player>");
						break;
						}
			msg_to_char(ch, "Common sites:\r\n");
			if (*buf)
				msg_to_char(ch, buf);
			else
				msg_to_char(ch, "None.\r\n");
			break;
		case 7:
			*buf = '\0';
			k = 0;
			for (j = 0; j <= top_of_p_table; j++) {
				load_char((player_table + j)->name, &vbuf);
				if (!IS_SET(vbuf.char_specials_saved.act, PLR_DELETED | PLR_SLAIN))
					if (vbuf.email && *vbuf.email)
						sprintf(buf + strlen(buf), "%s\r\n", vbuf.email);
				}
			msg_to_char(ch, "Players' addresses:\r\n");
			if (*buf)
				msg_to_char(ch, buf);
			else
				msg_to_char(ch, " none");
			break;

		case 8:	/* players: show all players */
			*buf = '\0';

			for (d = descriptor_list; d; d = d->next) {
				if (STATE(d) != CON_PLAYING || !(vict = d->character))
					continue;
				if (!CAN_SEE(ch, vict))
					continue;

				sprintf(buf + strlen(buf), " %-20.20s &2%d&0/&2%d&0 &3%3d&0/&3%3d&0 &6%d&0", PERS(vict, vict, 1), GET_DAMAGE(vict), GET_AGG_DAMAGE(vict), GET_MOVE(vict), GET_MAX_MOVE(vict), GET_EXP_TODAY(vict));
				if (IS_VAMPIRE(vict))
					sprintf(buf + strlen(buf), " &1%2d&0", GET_BLOOD(vict));
				else if (IS_GHOUL(vict))
					sprintf(buf + strlen(buf), " &1%2d&0/&1%2d&0", GET_BLOOD(vict), GET_VAMP_BLOOD(vict));

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

			msg_to_char(ch, "Players:\r\n %-20.20s %-3.3s %-7.7s E %s\r\n %-20.20s %-3.3s %-7.7s - %s\r\n%s", "Name", "Dam", "Moves", "Blood", "----", "---", "-------", "-----", buf);

			break;

		default:
			send_to_char("Sorry, I don't understand that.\r\n", ch);
			break;
		}
	}


/***************** The do_set function ***********************************/

#define PC   1
#define NPC  2
#define BOTH 3

#define MISC	0
#define BINARY	1
#define NUMBER	2

#define SET_OR_REMOVE(flagset, flags) { \
	if (on) SET_BIT(flagset, flags); \
	else if (off) REMOVE_BIT(flagset, flags); }

#define RANGE(low, high) (value = MAX((low), MIN((high), (value))))

#define SET_CASE(str)		} else if (!str_cmp(str, set_fields[mode].cmd)) {
#define BEGIN_SET			if (0) {


/* The set options available */
struct set_struct {
	const char *cmd;
	const char level;
	const char pcnpc;
	const char type;
	} set_fields[] = {
		{ "defect",	LVL_ASST,	PC,	NUMBER },
		{ "invstart", 	LVL_ASST, 	PC, 	BINARY },
		{ "title",		LVL_ASST, 	PC, 	MISC },
		{ "maxmove", 	LVL_IMPL, 	BOTH, 	NUMBER },
		{ "damage",		LVL_IMPL, 	BOTH, 	NUMBER },
		{ "move",		LVL_IMPL, 	BOTH, 	NUMBER },
		{ "frozen",		LVL_FREEZE,	PC, 	BINARY },
		{ "drunk",		LVL_ASST, 	BOTH, 	MISC },
		{ "hunger",		LVL_ASST, 	BOTH, 	MISC },
		{ "thirst",		LVL_ASST, 	BOTH, 	MISC },
		{ "exhaust",	LVL_ASST, 	BOTH, 	MISC },
		{ "level",		LVL_IMPL, 	BOTH, 	NUMBER },
		{ "siteok",		LVL_ASST, 	PC, 	BINARY },
		{ "deleted", 	LVL_CIMPL, 	PC, 	BINARY },
		{ "slain",		LVL_CIMPL,	PC,		BINARY },
		{ "nowizlist", 	LVL_ASST, 	PC, 	BINARY },
		{ "loadroom", 	LVL_ASST, 	PC, 	MISC },
		{ "color",		LVL_CIMPL, 	PC, 	BINARY },
		{ "passwd",		LVL_IMPL, 	PC, 	MISC },
		{ "nodelete", 	LVL_CIMPL, 	PC, 	BINARY },
		{ "sex", 		LVL_ASST, 	BOTH, 	MISC },
		{ "age",		LVL_ASST,	BOTH,	NUMBER },
		{ "lastname",	LVL_ASST,	PC,		MISC },
		{ "muted",		LVL_MUTE,	PC, 	BINARY },
		{ "name",		LVL_TOP,	PC,		MISC },
		{ "ipmask",		LVL_TOP,	PC,		BINARY },
		{ "multiok",	LVL_TOP,	PC,		BINARY },
		{ "nosleep",	LVL_TOP,	PC,		BINARY },
		{ "pirate",		LVL_ASST, 	PC, 	BINARY },
		{ "breed",		LVL_IMPL,	PC,		NUMBER },
		{ "defect",		LVL_ASST,	PC,	NUMBER },

		{ "strength",	LVL_IMPL,	BOTH,	NUMBER },
		{ "dexterity",	LVL_IMPL,	BOTH,	NUMBER },
		{ "stamina",	LVL_IMPL,	BOTH,	NUMBER },
		{ "charisma",	LVL_IMPL,	BOTH,	NUMBER },
		{ "manipulation",LVL_IMPL,	BOTH,	NUMBER },
		{ "appearance",	LVL_IMPL,	BOTH,	NUMBER },
		{ "perception",	LVL_IMPL,	BOTH,	NUMBER },
		{ "intelligence",LVL_IMPL,	BOTH,	NUMBER },
		{ "wits",		LVL_IMPL,	BOTH,	NUMBER },

		{ "conscience",	LVL_IMPL,	BOTH,	NUMBER },
		{ "selfcontrol",LVL_IMPL,	BOTH,	NUMBER },
		{ "courage",	LVL_IMPL,	BOTH,	NUMBER },

		{ "humanity",	LVL_IMPL,	BOTH,	NUMBER },
		{ "willpower",	LVL_IMPL,	BOTH,	NUMBER },
		{ "maxwillpower",LVL_IMPL,	BOTH,	NUMBER },
		{ "generation",	LVL_TOP,	PC,		NUMBER },

		{ "acting",		LVL_ASST,	PC,		NUMBER },
		{ "alertness",	LVL_ASST,	PC,		NUMBER },
		{ "athletics",	LVL_ASST,	PC,		NUMBER },
		{ "brawl",		LVL_ASST,	PC,		NUMBER },
		{ "dodge",		LVL_ASST,	PC,		NUMBER },
		{ "empathy",	LVL_ASST,	PC,		NUMBER },
		{ "intimidation",	LVL_ASST,	PC,	NUMBER },
		{ "larceny",	LVL_ASST,	PC,		NUMBER },
		{ "leadership",	LVL_ASST,	PC,		NUMBER },
		{ "subterfuge",	LVL_ASST,	PC,		NUMBER },

		{ "animalken",	LVL_ASST,	PC,		NUMBER },
		{ "archery",	LVL_ASST,	PC,		NUMBER },
		{ "crafts",		LVL_ASST,	PC,		NUMBER },
		{ "etiquette",	LVL_ASST,	PC,		NUMBER },
		{ "herbalism",	LVL_ASST,	PC,		NUMBER },
		{ "melee",		LVL_ASST,	PC,		NUMBER },
		{ "music",		LVL_ASST,	PC,		NUMBER },
		{ "ride",		LVL_ASST,	PC,		NUMBER },
		{ "stealth",	LVL_ASST,	PC,		NUMBER },
		{ "survival",	LVL_ASST,	PC,		NUMBER },

		{ "academics",	LVL_ASST,	PC,		NUMBER },
		{ "hearthwisdom",	LVL_ASST,	PC,	NUMBER },
		{ "investigation",	LVL_ASST,	PC,	NUMBER },
		{ "law",		LVL_ASST,	PC,		NUMBER },
		{ "medicine",	LVL_ASST,	PC,		NUMBER },
		{ "occult",		LVL_ASST,	PC,		NUMBER },
		{ "politics",	LVL_ASST,	PC,		NUMBER },
		{ "science",	LVL_ASST,	PC,		NUMBER },
		{ "seneschal",	LVL_ASST,	PC,		NUMBER },

		{ "animalism",	LVL_IMPL,	PC,		NUMBER },
		{ "auspex",		LVL_IMPL,	PC,		NUMBER },
		{ "celerity",	LVL_IMPL,	PC,		NUMBER },
		{ "chimerstry",	LVL_IMPL,	PC,		NUMBER },
		{ "dementation",LVL_IMPL,	PC,		NUMBER },
		{ "dominate",	LVL_IMPL,	PC,		NUMBER },
		{ "fortitude",	LVL_IMPL,	PC,		NUMBER },
		{ "mortis",		LVL_IMPL,	PC,		NUMBER },
		{ "obfuscate",	LVL_IMPL,	PC,		NUMBER },
		{ "obtenebration",	LVL_IMPL,	PC,	NUMBER },
		{ "potence",	LVL_IMPL,	PC,		NUMBER },
		{ "presence",	LVL_IMPL,	PC,		NUMBER },
		{ "protean",	LVL_IMPL,	PC,		NUMBER },
		{ "quietus",	LVL_IMPL,	PC,		NUMBER },
		{ "serpentis",	LVL_IMPL,	PC,		NUMBER },
		{ "thaumaturgy",LVL_IMPL,	PC,		NUMBER },
		{ "vicissitude",LVL_IMPL,	PC,		NUMBER },

		{ "rego_vitae",	LVL_IMPL,	PC,		NUMBER },
		{ "creo_ignem",	LVL_IMPL,	PC,		NUMBER },
		{ "rego_motus",	LVL_IMPL,	PC,		NUMBER },
		{ "rego_tempestas",	LVL_IMPL,	PC,	NUMBER },
		{ "rego_aquam",	LVL_IMPL,	PC,		NUMBER },
		{ "rego_elementum",	LVL_IMPL,	PC,	NUMBER },
		{ "way_of_levinbolt",	LVL_IMPL,	PC,		NUMBER },
		{ "path_of_warding",	LVL_IMPL,	PC,		NUMBER },

		{ "\n", 0, BOTH, MISC }};


/* All setting is done here, for simplicity */
int perform_set(Creature ch, Creature vict, int mode, char *val_arg) {
	/* Externs */
	void set_title(Creature ch, char *title);
	extern int _parse_name(char *arg, char *name);
	extern int Valid_Name(char *newname);
	void delete_empire(int rnum);

	int i, nr, on = 0, off = 0, value = 0, emp;
	room_vnum rvnum;
	char output[MAX_STRING_LENGTH], oldname[MAX_INPUT_LENGTH], newname[MAX_INPUT_LENGTH];


	*output = '\0';

	/* Check to make sure all the levels are correct */
	if (GET_LEVEL(ch) != LVL_IMPL) {
		if (!IS_NPC(vict) && GET_LEVEL(ch) <= GET_LEVEL(vict) && vict != ch) {
			send_to_char("Maybe that's not such a great idea...\r\n", ch);
			return (0);
			}
		}
	if (GET_LEVEL(ch) < set_fields[mode].level) {
		send_to_char("You are not godly enough for that!\r\n", ch);
		return (0);
		}

	/* Make sure the PC/NPC is correct */
	if (IS_NPC(vict) && !(set_fields[mode].pcnpc & NPC)) {
		send_to_char("You can't do that to a beast!\r\n", ch);
		return (0);
		}
	else if (!IS_NPC(vict) && !(set_fields[mode].pcnpc & PC)) {
		send_to_char("That can only be done to a beast!\r\n", ch);
		return (0);
		}

	/* Find the value of the argument */
	if (set_fields[mode].type == BINARY) {
		if (!strcmp(val_arg, "on") || !strcmp(val_arg, "yes"))
			on = 1;
		else if (!strcmp(val_arg, "off") || !strcmp(val_arg, "no"))
			off = 1;
		if (!(on || off)) {
			send_to_char("Value must be 'on' or 'off'.\r\n", ch);
			return (0);
			}
		sprintf(output, "%s %s for %s.", set_fields[mode].cmd, ONOFF(on), GET_NAME(vict));
		}
	else if (set_fields[mode].type == NUMBER) {
		value = atoi(val_arg);
		sprintf(output, "%s's %s set to %d.", GET_NAME(vict), set_fields[mode].cmd, value);
		}
	else
		strcpy(output, "Okay.");  /* can't use OK macro here 'cause of \r\n */


	BEGIN_SET

	SET_CASE("defect")
		GET_DEFECT_TIMER(ch) = RANGE(0, 96);
	SET_CASE("invstart")
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_INVSTART);
	SET_CASE("title")
		set_title(vict, val_arg);
		sprintf(output, "%s's title is now: %s", GET_NAME(vict), GET_TITLE(vict));
	SET_CASE("maxmove")
		vict->points.max_move = RANGE(1, 200);
		affect_total(vict);
	SET_CASE("damage")
		vict->points.damage = RANGE(0, 7);
		affect_total(vict);
	SET_CASE("move")
		vict->points.move = RANGE(0, vict->points.max_move);
		affect_total(vict);

	SET_CASE("strength")
		vict->real_abils.strength = RANGE(1, att_max(vict));
		affect_total(vict);
	SET_CASE("dexterity")
		vict->real_abils.dexterity = RANGE(1, att_max(vict));
		affect_total(vict);
	SET_CASE("stamina")
		vict->real_abils.stamina = RANGE(1, att_max(vict));
		affect_total(vict);

	SET_CASE("charisma")
		vict->real_abils.charisma = RANGE(1, att_max(vict));
		affect_total(vict);
	SET_CASE("manipulation")
		vict->real_abils.manipulation = RANGE(1, att_max(vict));
		affect_total(vict);
	SET_CASE("appearance")
		vict->real_abils.appearance = RANGE(1, att_max(vict));
		affect_total(vict);

	SET_CASE("perception")
		vict->real_abils.perception = RANGE(1, att_max(vict));
		affect_total(vict);
	SET_CASE("intelligence")
		vict->real_abils.intelligence = RANGE(1, att_max(vict));
		affect_total(vict);
	SET_CASE("wits")
		vict->real_abils.wits = RANGE(1, att_max(vict));
		affect_total(vict);

	SET_CASE("conscience")
		vict->points.conscience = RANGE(1, 5);
		affect_total(vict);
	SET_CASE("selfcontrol")
		vict->points.self_control = RANGE(1, 5);
		affect_total(vict);
	SET_CASE("courage")
		vict->points.courage = RANGE(1, 5);
		affect_total(vict);
	SET_CASE("humanity")
		vict->points.humanity = RANGE(0, 10);
		affect_total(vict);
	SET_CASE("maxwillpower")
		vict->points.max_willpower = RANGE(0, 10);
		affect_total(vict);
	SET_CASE("willpower")
		vict->points.willpower = RANGE(0, 10);
		affect_total(vict);

	/* Set the Defect Timer useful for testing */
	SET_CASE("defect")
		GET_DEFECT_TIMER(vict) = RANGE(0, 96);

	SET_CASE("frozen")
		if (ch == vict && on) {
			send_to_char("Better not -- could be a long winter!\r\n", ch);
			return (0);
			}
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_FROZEN);
	SET_CASE("muted")
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_MUTED);
	SET_CASE("ipmask")
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_IPMASK);
	SET_CASE("multiok")
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_MULTIOK);
	SET_CASE("nosleep")
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NOSLEEP);
	SET_CASE("pirate")
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_PIRATE);
	SET_CASE("breed")
		if(IS_WEREWOLF(vict)){
			if(!str_cmp(val_arg, "homid")){
				GET_BREED(vict) = 0;
			} else if(!str_cmp(val_arg, "metis")){
				GET_BREED(vict) = 1;
			} else if(!str_cmp(val_arg, "homid")){
				GET_BREED(vict) = 2;
			} else {
				sprintf(output, "%s is not a valid option! Please use Homid, Metis, or Lupus\r\n", val_arg);
			}
		} else {
			send_to_char("Player is not a Werewolf!\r\n", ch);
			return (0);
		}
	SET_CASE("hunger")
		if (!str_cmp(val_arg, "off")) {
			GET_COND(vict, FULL) = -1;
			sprintf(output, "%s's hunger now off.", GET_NAME(vict));
			}
		else if (is_number(val_arg)) {
			value = atoi(val_arg);
			RANGE(0, 360);
			GET_COND(vict, FULL) = value;
			sprintf(output, "%s's hunger set to %d.", GET_NAME(vict), value);
			}
		else {
			send_to_char("Must be 'off' or a value from 0 to 24.\r\n", ch);
			return (0);
			}
	SET_CASE("drunk")
		if (!str_cmp(val_arg, "off")) {
			GET_COND(vict, DRUNK) = -1;
			sprintf(output, "%s's drunk now off.", GET_NAME(vict));
			}
		else if (is_number(val_arg)) {
			value = atoi(val_arg);
			RANGE(0, 360);
			GET_COND(vict, DRUNK) = value;
			sprintf(output, "%s's drunk set to %d.", GET_NAME(vict), value);
			}
		else {
			send_to_char("Must be 'off' or a value from 0 to 24.\r\n", ch);
			return (0);
			}
	SET_CASE("thirst")
		if (!str_cmp(val_arg, "off")) {
			GET_COND(vict, THIRST) = -1;
			sprintf(output, "%s's thirst now off.", GET_NAME(vict));
			}
		else if (is_number(val_arg)) {
			value = atoi(val_arg);
			RANGE(0, 360);
			GET_COND(vict, THIRST) = value;
			sprintf(output, "%s's thirst set to %d.", GET_NAME(vict), value);
			}
		else {
			send_to_char("Must be 'off' or a value from 0 to 24.\r\n", ch);
			return (0);
			}
	SET_CASE("exhaust")
		if (!str_cmp(val_arg, "off")) {
			GET_COND(vict, TIRED) = -1;
			sprintf(output, "%s's exhaust now off.", GET_NAME(vict));
			}
		else if (is_number(val_arg)) {
			value = atoi(val_arg);
			RANGE(0, 360);
			GET_COND(vict, TIRED) = value;
			sprintf(output, "%s's exhaust set to %d.", GET_NAME(vict), value);
			}
		else {
			send_to_char("Must be 'off' or a value from 0 to 24.\r\n", ch);
			return (0);
			}
	SET_CASE("level")
		if (value > GET_LEVEL(ch) || value > LVL_IMPL) {
			send_to_char("You can't do that.\r\n", ch);
			return (0);
			}
		RANGE(0, LVL_IMPL);
		vict->player.level = (byte) value;
		if (!IS_NPC(vict))
			GET_IMM_LEV(vict) = IS_IMMORTAL(vict) ? LVL_TOP - GET_LEVEL(vict) : -1;
		SAVE_CHAR(vict);
		check_autowiz(ch);
	SET_CASE("generation")
		RANGE(4, 13);
		GET_GENERATION(vict) = (byte) value;
		affect_total(vict);
	SET_CASE("siteok")
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_SITEOK);
	SET_CASE("deleted")
		if (on && GET_LOYALTY(vict)) {
			/* Check that empire */
			if ((emp = real_empire(GET_LOYALTY(vict))) != -1) {
				GET_LOYALTY(vict) = 0;
				GET_RANK(vict) = 0;
				empire[emp].members--;
				if (empire[emp].members == 0)
					delete_empire(emp);
				}
			}
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_DELETED);
	SET_CASE("slain")
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_SLAIN);
	SET_CASE("nowizlist")
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NOWIZLIST);
	SET_CASE("loadroom")
		if (!str_cmp(val_arg, "off")) {
			REMOVE_BIT(PLR_FLAGS(vict), PLR_LOADROOM);
			sprintf(output, "Loadroom for %s off.", GET_NAME(vict));
			}
		else if (is_number(val_arg)) {
			rvnum = atoi(val_arg);
			if (real_room(rvnum) != NOWHERE) {
				SET_BIT(PLR_FLAGS(vict), PLR_LOADROOM);
				GET_LOADROOM(vict) = rvnum;
				sprintf(output, "%s will enter at room #%d.", GET_NAME(vict),
				GET_LOADROOM(vict));
				}
			else {
				send_to_char("That room does not exist!\r\n", ch);
				return (0);
				}
			}
		else {
			send_to_char("Must be 'off' or a room's virtual number.\r\n", ch);
			return (0);
			}
	SET_CASE("color")
		SET_OR_REMOVE(PRF_FLAGS(vict), PRF_COLOR);
	SET_CASE("passwd")
		if (GET_IDNUM(ch) > 1) {
			send_to_char("Please don't use this command, yet.\r\n", ch);
			return (0);
			}
		if (GET_LEVEL(vict) >= LVL_IMPL) {
			send_to_char("You cannot change that.\r\n", ch);
			return (0);
			}
		strncpy(GET_PASSWD(vict), CRYPT(val_arg, GET_NAME(vict)), MAX_PWD_LENGTH);
		*(GET_PASSWD(vict) + MAX_PWD_LENGTH) = '\0';
		sprintf(output, "Password changed to '%s'.", val_arg);
	SET_CASE("nodelete")
		SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NODELETE);
	SET_CASE("sex")
		if ((i = search_block(val_arg, genders, FALSE)) < 0) {
			send_to_char("Must be 'male', 'female', or 'neutral'.\r\n", ch);
			return (0);
			}
		GET_SEX(vict) = i;
	SET_CASE("age")
		if (value < 2 || value > 95) {	/* Arbitrary limits. */
			send_to_char("Ages 2 to 95 accepted.\r\n", ch);
			return (0);
			}
		vict->player.time.birth = time(0) - ((value - 17) * SECS_PER_MUD_YEAR);
	SET_CASE("lastname")
		if (!str_cmp(val_arg, "off")) {
			if (GET_LASTNAME(vict) != NULL)
				free(GET_LASTNAME(vict));
			GET_LASTNAME(vict) = NULL;
    		sprintf(output, "%s's last name is off", GET_NAME(vict));
    		}
    	else {
			if (GET_LASTNAME(vict) != NULL)
				free(GET_LASTNAME(vict));
			GET_LASTNAME(vict) = str_dup(val_arg);
    		sprintf(output, "%s's last name is now: %s", GET_NAME(vict), GET_LASTNAME(vict));
    		}

	SET_CASE("acting")
		vict->player_specials->saved.talents[TALENT_ACTING] = RANGE(0, att_max(vict));
	SET_CASE("alertness")
		vict->player_specials->saved.talents[TALENT_ALERTNESS] = RANGE(0, att_max(vict));
	SET_CASE("athletics")
		vict->player_specials->saved.talents[TALENT_ATHLETICS] = RANGE(0, att_max(vict));
	SET_CASE("brawl")
		vict->player_specials->saved.talents[TALENT_BRAWL] = RANGE(0, att_max(vict));
	SET_CASE("dodge")
		vict->player_specials->saved.talents[TALENT_DODGE] = RANGE(0, att_max(vict));
	SET_CASE("empathy")
		vict->player_specials->saved.talents[TALENT_EMPATHY] = RANGE(0, att_max(vict));
	SET_CASE("intimidation")
		vict->player_specials->saved.talents[TALENT_INTIMIDATION] = RANGE(0, att_max(vict));
	SET_CASE("larceny")
		vict->player_specials->saved.talents[TALENT_LARCENY] = RANGE(0, att_max(vict));
	SET_CASE("leadership")
		vict->player_specials->saved.talents[TALENT_LEADERSHIP] = RANGE(0, att_max(vict));
	SET_CASE("subterfuge")
		vict->player_specials->saved.talents[TALENT_SUBTERFUGE] = RANGE(0, att_max(vict));
	SET_CASE("animalken")
		vict->player_specials->saved.skills[SKILL_ANIMAL_KEN] = RANGE(0, att_max(vict));
	SET_CASE("archery")
		vict->player_specials->saved.skills[SKILL_ARCHERY] = RANGE(0, att_max(vict));
	SET_CASE("crafts")
		vict->player_specials->saved.skills[SKILL_CRAFTS] = RANGE(0, att_max(vict));
	SET_CASE("etiquette")
		vict->player_specials->saved.skills[SKILL_ETIQUETTE] = RANGE(0, att_max(vict));
	SET_CASE("herbalism")
		vict->player_specials->saved.skills[SKILL_HERBALISM] = RANGE(0, att_max(vict));
	SET_CASE("melee")
		vict->player_specials->saved.skills[SKILL_MELEE] = RANGE(0, att_max(vict));
	SET_CASE("music")
		vict->player_specials->saved.skills[SKILL_MUSIC] = RANGE(0, att_max(vict));
	SET_CASE("ride")
		vict->player_specials->saved.skills[SKILL_RIDE] = RANGE(0, att_max(vict));
	SET_CASE("stealth")
		vict->player_specials->saved.skills[SKILL_STEALTH] = RANGE(0, att_max(vict));
	SET_CASE("survival")
		vict->player_specials->saved.skills[SKILL_SURVIVAL] = RANGE(0, att_max(vict));
	SET_CASE("academics")
		vict->player_specials->saved.knowledges[KNOWLEDGE_ACADEMICS] = RANGE(0, att_max(vict));
	SET_CASE("hearthwisdom")
		vict->player_specials->saved.knowledges[KNOWLEDGE_HEARTH_WISDOM] = RANGE(0, att_max(vict));
	SET_CASE("investigation")
		vict->player_specials->saved.knowledges[KNOWLEDGE_INVESTIGATION] = RANGE(0, att_max(vict));
	SET_CASE("law")
		vict->player_specials->saved.knowledges[KNOWLEDGE_LAW] = RANGE(0, att_max(vict));
	SET_CASE("medicine")
		vict->player_specials->saved.knowledges[KNOWLEDGE_MEDICINE] = RANGE(0, att_max(vict));
	SET_CASE("occult")
		vict->player_specials->saved.knowledges[KNOWLEDGE_OCCULT] = RANGE(0, att_max(vict));
	SET_CASE("politics")
		vict->player_specials->saved.knowledges[KNOWLEDGE_POLITICS] = RANGE(0, att_max(vict));
	SET_CASE("science")
		vict->player_specials->saved.knowledges[KNOWLEDGE_SCIENCE] = RANGE(0, att_max(vict));
	SET_CASE("seneschal")
		vict->player_specials->saved.knowledges[KNOWLEDGE_SENESCHAL] = RANGE(0, att_max(vict));

	SET_CASE("animalism")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_ANIMALISM) = value;
	SET_CASE("auspex")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_AUSPEX) = value;
	SET_CASE("celerity")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_CELERITY) = value;
	SET_CASE("chimerstry")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_CHIMERSTRY) = value;
	SET_CASE("dementation")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_DEMENTATION) = value;
	SET_CASE("dominate")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_DOMINATE) = value;
	SET_CASE("fortitude")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		if (affected_by_spell(vict, ATYPE_BESTOW_VIGOR))
			affect_from_char(vict, ATYPE_BESTOW_VIGOR);

		GET_REAL_DISC(vict, DISC_FORTITUDE) = value;
	SET_CASE("mortis")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_MORTIS) = value;
	SET_CASE("obfuscate")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_OBFUSCATE) = value;
	SET_CASE("obtenebration")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_OBTENEBRATION) = value;
	SET_CASE("potence")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_POTENCE) = value;
	SET_CASE("presence")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_PRESENCE) = value;
	SET_CASE("protean")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_PROTEAN) = value;
	SET_CASE("quietus")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_QUIETUS) = value;
	SET_CASE("serpentis")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_SERPENTIS) = value;
	SET_CASE("thaumaturgy")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > 5) {
			msg_to_char(ch, "%s has a maximum Thaumaturgy rating of 5.\r\n");
			return 0;
			}

		GET_REAL_DISC(vict, DISC_THAUMATURGY) = value;
		GET_REAL_PATH(vict, (int) GET_REAL_PRIMARY_PATH(vict)) = value;
	SET_CASE("vicissitude")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set disciplines for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > disc_max(vict)) {
			msg_to_char(ch, "%s has a maximum discipline rating of %d.\r\n", PERS(vict, vict, 1), disc_max(vict));
			return 0;
			}

		GET_REAL_DISC(vict, DISC_VICISSITUDE) = value;

	SET_CASE("rego_vitae")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set paths for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > 5) {
			msg_to_char(ch, "%s has a maximum Thaumaturgy rating of 5.\r\n");
			return 0;
			}

		GET_REAL_PATH(vict, PATH_REGO_VITAE) = value;
	SET_CASE("creo_ignem")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set paths for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > 5) {
			msg_to_char(ch, "%s has a maximum Thaumaturgy rating of 5.\r\n");
			return 0;
			}

		GET_REAL_PATH(vict, PATH_CREO_IGNEM) = value;
	SET_CASE("rego_motus")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set paths for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > 5) {
			msg_to_char(ch, "%s has a maximum Thaumaturgy rating of 5.\r\n");
			return 0;
			}

		GET_REAL_PATH(vict, PATH_REGO_MOTUS) = value;
	SET_CASE("rego_tempestas")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set paths for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > 5) {
			msg_to_char(ch, "%s has a maximum Thaumaturgy rating of 5.\r\n");
			return 0;
			}

		GET_REAL_PATH(vict, PATH_REGO_TEMPESTAS) = value;
	SET_CASE("rego_aquam")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set paths for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > 5) {
			msg_to_char(ch, "%s has a maximum Thaumaturgy rating of 5.\r\n");
			return 0;
			}

		GET_REAL_PATH(vict, PATH_REGO_AQUAM) = value;
	SET_CASE("rego_elementum")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set paths for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > 5) {
			msg_to_char(ch, "%s has a maximum Thaumaturgy rating of 5.\r\n");
			return 0;
			}

		GET_REAL_PATH(vict, PATH_REGO_ELEMENTUM) = value;
	SET_CASE("way_of_levinbolt")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set paths for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > 5) {
			msg_to_char(ch, "%s has a maximum Thaumaturgy rating of 5.\r\n");
			return 0;
			}

		GET_REAL_PATH(vict, PATH_WAY_OF_LEVINBOLT) = value;
	SET_CASE("path_of_warding")
		if (!IS_VAMPIRE(vict) && !IS_GHOUL(vict)) {
			msg_to_char(ch, "You can only set paths for vampires and ghouls.\r\n");
			return 0;
			}
		if (value > 5) {
			msg_to_char(ch, "%s has a maximum Thaumaturgy rating of 5.\r\n");
			return 0;
			}

		GET_REAL_PATH(vict, PATH_PATH_OF_WARDING) = value;


	SET_CASE("name")
		SAVE_CHAR(vict);
		one_argument(val_arg, buf);
		if (_parse_name(buf, newname) || fill_word(newname) || strlen(newname) > MAX_NAME_LENGTH || strlen(newname) < 2 || !Valid_Name(newname)) {
			msg_to_char(ch, "Invalid name.\r\n");
			return 0;
			}
		nr = NOBODY;
		for (i = 0; i <= top_of_p_table; i++) {
			if (!str_cmp(player_table[i].name, newname)) {
				msg_to_char(ch, "That name is already taken.\r\n", ch);
				return 0;
				}
			if (!str_cmp(player_table[i].name, GET_NAME(vict))) {
				if (nr >= 0) {
					msg_to_char(ch, "WARNING: possible pfile corruption, more than one entry with that name.\r\nName not changed.\r\n");
					return 0;
					}
				nr = i;
				}
			}
		if (nr == NOBODY) {
			msg_to_char(ch, "WARNING: That character does not have a record in the pfile.\r\nName not changed.\r\n");
			return 0;
			}
		strcpy(oldname, GET_NAME(vict));
		if (player_table[nr].name)
			free(player_table[nr].name);
		CREATE(player_table[nr].name, char, strlen(newname) + 1);
		for (i = 0; (*(player_table[nr].name + i) = *(newname + i)); i++);
		if (GET_NAME(vict))
			free(GET_NAME(vict));
		/* Replaced this line to prevent compiler warning */
		/* GET_NAME(vict) = strdup(CAP(newname)); */
		GET_PC_NAME(vict) = strdup(CAP(newname));
		get_filename(oldname, buf1, CRASH_FILE);
		get_filename(GET_PC_NAME(vict), buf2, CRASH_FILE);
		sprintf(buf, "rm -f %s", buf2);
		system(buf);
		rename(buf1, buf2);
		get_filename(oldname, buf1, ALIAS_FILE);
		get_filename(GET_PC_NAME(vict), buf2, ALIAS_FILE);
		sprintf(buf, "rm -f %s", buf2);
		system(buf);
		rename(buf1, buf2);
		get_filename(oldname, buf1, LORE_FILE);
		get_filename(GET_PC_NAME(vict), buf2, LORE_FILE);
		sprintf(buf, "rm -f %s", buf2);
		system(buf);
		rename(buf1, buf2);
		get_filename(oldname, buf1, REC_FILE);
		get_filename(GET_PC_NAME(vict), buf2, REC_FILE);
		sprintf(buf, "rm -f %s", buf2);
		system(buf);
		rename(buf1, buf2);

		SAVE_CHAR(vict);
		sprintf(output, "%s's name changed to %s.", oldname, GET_NAME(vict));

	} else {
			send_to_char("Can't set that!\r\n", ch);
			return (0);
			}

	if (*output) {
		strcat(output, "\r\n");
		send_to_char(CAP(output), ch);
		}
	return (1);
	}


ACMD(do_set) {
	Creature vict = NULL, cbuf = NULL;
	struct char_file_u tmp_store;
	char field[MAX_INPUT_LENGTH], name[MAX_INPUT_LENGTH], val_arg[MAX_INPUT_LENGTH];
	int mode, len, player_i = 0, retval;
	char is_file = 0, is_player = 0;

	half_chop(argument, name, buf);

	if (!strcmp(name, "file")) {
		is_file = 1;
		half_chop(buf, name, buf);
		}
	else if (!str_cmp(name, "player")) {
		is_player = 1;
		half_chop(buf, name, buf);
		}
	else if (!str_cmp(name, "mob"))
		half_chop(buf, name, buf);

	half_chop(buf, field, buf);
	strcpy(val_arg, buf);

	if (!*name || !*field) {
		send_to_char("Usage: set <victim> <field> <value>\r\n", ch);
		return;
		}

	/* find the target */
	if (!is_file) {
		if (is_player) {
			if (!(vict = get_player_vis(ch, name, FIND_CHAR_WORLD))) {
				send_to_char("There is no such player.\r\n", ch);
				return;
				}
			}
		else { /* is_mob */
			if (!(vict = get_char_vis(ch, name, FIND_CHAR_WORLD))) {
				send_to_char("There is no such creature.\r\n", ch);
				return;
				}
			}
		}
	else if (is_file) {
		/* try to load the player off disk */
		CREATE(cbuf, struct char_data, 1);
		clear_char(cbuf);
		if ((player_i = load_char(name, &tmp_store)) > NOBODY) {
			store_to_char(&tmp_store, cbuf);
			if (GET_LEVEL(cbuf) >= GET_LEVEL(ch)) {
				free_char(cbuf);
				send_to_char("Sorry, you can't do that.\r\n", ch);
				return;
				}
			vict = cbuf;
			}
		else {
			free(cbuf);
			send_to_char("There is no such player.\r\n", ch);
			return;
			}
		}

	/* find the command in the list */
	len = strlen(field);
	for (mode = 0; *(set_fields[mode].cmd) != '\n'; mode++)
		if (!strncmp(field, set_fields[mode].cmd, len))
			break;

	/* perform the set */
	retval = perform_set(ch, vict, mode, val_arg);

	/* save the character if a change was made */
	if (retval) {
		if (!is_file && !IS_NPC(vict))
			SAVE_CHAR(vict);
		if (is_file) {
			char_to_store(vict, &tmp_store);
			fseek(player_fl, (player_i) * sizeof(struct char_file_u), SEEK_SET);
			fwrite(&tmp_store, sizeof(struct char_file_u), 1, player_fl);
			send_to_char("Saved in file.\r\n", ch);
			}
		}

	/* free the memory if we allocated it earlier */
	if (is_file)
		free_char(cbuf);
	}


/*
 * do_reboot:
 *   This function allows an immortal to cause a reboot, or to set the timer for
 *   one.  It is also called by update_reboot() to cause the reboot itself, so
 *   it must be made to run WITHOUT (ch) if necessary.  Please don't remove this
 *   ability, or the mud will crash when it processes a timed reboot. -pc, 10/21/2k
 */
void process_reboot(Creature ch, char *argument, int subcmd) {
	ACMD(do_reboot);
	void update_reboot();
	extern const char *reboot_type[];
	int time = 0;

	strcpy(arg, argument);

	while (*arg) {
		half_chop(arg, buf, buf1);
		strcpy(arg, buf1);

		if (*buf == '+') {
			if (is_abbrev(buf + 1, "pause")) {
				reboot.pause = TRUE;
				reboot.die = FALSE;
				}
			else if (is_abbrev(buf + 1, "die")) {
				reboot.die = TRUE;
				reboot.pause = FALSE;
				}
			else {
				msg_to_char(ch, "Unknown reboot option '%s'.\r\n", buf);
				return;
				}
			}
		else if (*buf == '-') {
			if (is_abbrev(buf + 1, "pause"))
				reboot.pause = FALSE;
			else if (is_abbrev(buf + 1, "die"))
				reboot.die = FALSE;
			else {
				msg_to_char(ch, "Unknown reboot option '%s'.\r\n", buf);
				return;
				}
			}
		else if (isdigit(*buf)) {
			if ((time = atoi(buf)) == 0) {
				msg_to_char(ch, "Invalid amount of time!\r\n");
				return;
				}
			}
		}

	/* No time was given! */
	if (time == 0) {
		do_reboot(ch, "", 0, subcmd);
		return;
		}

	/* All good to set up the reboot: */
	reboot.time = time + 1;
	reboot.type = subcmd;

	*buf1 = '\0';
	if (reboot.pause)
		strcat(buf1, " +pause");
	else if (reboot.die)
		strcat(buf1, " +die");

	if (*buf1)
		sprintf(buf, " with options:%s", buf1);
	else
		*buf = '\0';

	msg_to_char(ch, "You have set the %s timer to %d%s.\r\n", reboot_type[subcmd], time, buf);
	update_reboot();
	}


ACMD(do_reboot) {
	extern int empire_shutdown;
	extern const char *reboot_strings[];
	extern int num_of_reboot_strings;
	extern FILE *player_fl;
	extern int mother_desc;
	extern ush_int port;
	void Crash_rentsave(Creature ch);
	FILE *fp = NULL;
	Descr d, d_next;

	if (subcmd == SCMD_REBOOT_DUMMY) {
		msg_to_char(ch, "You must type out 'reboot' or 'shutdown' in full.\r\n");
		return;
		}

	skip_spaces(&argument);

	if (*argument) {
		process_reboot(ch, argument, subcmd);
		return;
		}

	if (subcmd == SCMD_REBOOT && !(fp = fopen(REBOOT_FILE, "w"))) {
		if (ch)
			send_to_char("Reboot file not writeable, aborting.\r\n", ch);
		return;
		}

	if (subcmd == SCMD_REBOOT)
		sprintf(buf, "\r\n *** Rebooting ***\r\nPlease be patient, this will take a second.\r\n\r\n");
	else if (subcmd == SCMD_SHUTDOWN)
		sprintf(buf, "\r\n *** Shutting Down ***\r\nThe mud is shutting down, please reconnect later.\r\n\r\n");

	for (d = descriptor_list; d; d = d_next) {
		Creature och = d->character;
		d_next = d->next;

		if (!d->character || STATE(d) != CON_PLAYING) {
			write_to_descriptor(d->descriptor, buf);
			close_socket(d);
			continue;
			}

		if (subcmd == SCMD_REBOOT)
			fprintf(fp, "%d %s %s\n", d->descriptor, GET_NAME(och), d->host);

		write_to_descriptor(d->descriptor, buf);

		if (subcmd == SCMD_REBOOT)
			write_to_descriptor(d->descriptor, reboot_strings[number(1, num_of_reboot_strings)-1]);

		Crash_rentsave(och);
		SAVE_CHAR(och);
		extract_char(och);
		}

	if (subcmd == SCMD_REBOOT) {
		fprintf(fp, "-1\n");
		fclose(fp);
		}

	fclose(player_fl);

	zone_update(1);

	/* If this is a reboot, restart the mud! */
	if (subcmd == SCMD_REBOOT) {
		sprintf(buf, "%d", port);
		sprintf(buf2, "-C%d", mother_desc);
		chdir("..");

		execl("bin/empire", "empire", buf2, buf, (char *) NULL);

		/* If that failed we're still here? */
		perror("softreboot: execl");
		if (ch)
			send_to_char("Soft reboot failed!\r\n", ch);
		exit(1);
		}

	/* Otherwise it's a shutdown */
	else {
		empire_shutdown = 1;

		if (reboot.pause) {
			if (ch)
				log("GC: Shutdown-pause by %s.", GET_NAME(ch));
			else
				log("GC: Timed shutdown-pause.");

			touch(PAUSE_FILE);
			}
		else if (reboot.die) {
			if (ch)
				log("GC: Shutdown-die by %s.", GET_NAME(ch));
			else
				log("GC: Timed shutdown-die.");

			touch(KILLSCRIPT_FILE);
			}
		else if (ch)
			log("GC: Shutdown by %s.", GET_NAME(ch));
		else
			log("GC: Timed shutdown.");
		}
	}


ACMD(do_tedit) {
	int l, i;
	char field[MAX_INPUT_LENGTH];
	extern char *motd;
	extern char *imotd;
	extern char *info;

	struct editor_struct {
		char *cmd;
		int level;
		char *buffer;
		int  size;
		char *filename;
		} fields[] = {
			{ "motd",			LVL_GOD,	motd,		2400,	MOTD_FILE},
			{ "imotd",			LVL_GOD,	imotd,		2400,	IMOTD_FILE},
			{ "info",			LVL_GOD,	info,		8192,	INFO_FILE},

			{"\n",0,NULL,0,NULL}
		};

	if (ch->desc == NULL) {
		send_to_char("Get outta here you linkdead head!\r\n", ch);
		return;
		}

	half_chop(argument, field, buf);

	if (!*field) {
		strcpy(buf, "Files available to be edited:\r\n");
		i = 1;
		for (l = 0; *fields[l].cmd != '\n'; l++) {
			if (GET_LEVEL(ch) >= fields[l].level) {
				sprintf(buf, "%s%-11.11s", buf, fields[l].cmd);
				if (!(i % 7))
					strcat(buf, "\r\n");
				i++;
				}
			}

		if (--i % 7)
			strcat(buf, "\r\n");

		if (i == 0)
			strcat(buf, "None.\r\n");

		send_to_char(buf, ch);
		return;
		}
	for (l = 0; *(fields[l].cmd) != '\n'; l++)
		if (!strncmp(field, fields[l].cmd, strlen(field)))
			break;

	if (*fields[l].cmd == '\n') {
		send_to_char("Invalid text editor option.\r\n", ch);
		return;
		}

	if (GET_LEVEL(ch) < fields[l].level) {
		send_to_char("You are not godly enough for that!\r\n", ch);
		return;
		}

	switch (l) {
		case 0: ch->desc->str = &motd; break;
		case 1: ch->desc->str = &imotd; break;
		case 2: ch->desc->str = &info; break;
		default:
			send_to_char("Invalid text editor option.\r\n", ch);
			return;
		}

	/* set up editor stats */
	send_to_char("\x1B[H\x1B[J", ch);
	send_to_char("Edit file below: (/s saves, /h for help)\r\n", ch);
	ch->desc->backstr = NULL;
	if (fields[l].buffer) {
		send_to_char(fields[l].buffer, ch);
		ch->desc->backstr = str_dup(fields[l].buffer);
		}
	ch->desc->max_str = fields[l].size;
	ch->desc->mail_to = 0;
	ch->desc->storage = str_dup(fields[l].filename);
	act("$n begins editing a file.", TRUE, ch, 0, 0, TO_ROOM);
	SET_BIT(PLR_FLAGS(ch), PLR_WRITING);
	STATE(ch->desc) = CON_TEDIT;
	}


ACMD(do_fullsave) {
	syslog(0, FALSE, "Updating zone files...");

	skip_spaces(&argument);

	zone_update(1);

	send_to_char(OK, ch);
	}


ACMD(do_spawn) {
	Creature c;
	Descr d;
	int i, j, cn = 0, n, count;

	struct spawn_data {
		int num;
		int vnum[20];
		} spawn[] = {
	/* a. Field */
		{ 20,		{ SHEEP, DEER, BUCK, COW, CHICKEN, ROOSTER, DOG, PRARIE_DOG,
					  HORSE, WARHORSE, QUAIL, MULE, CAT, RABBIT, PIGEON,
					  EAGLE, HUMAN_MALE_1, HUMAN_MALE_2, HUMAN_FEMALE_1, HUMAN_FEMALE_2 }},
	/* b. 1-Forest */
		{ 16,		{ SMALL_WOLF, DEER, BUCK, COW, HORSE, WARHORSE,
					  QUAIL, MULE, CAT, RABBIT, PIGEON, EAGLE, HUMAN_MALE_1,
					  HUMAN_MALE_2, HUMAN_FEMALE_1, HUMAN_FEMALE_2 }},
	/* c. 2-Forest */
		{ 13,		{ BROWN_WOLF, SMALL_WOLF, DEER, BUCK, SQUIRREL,
					  QUAIL, CAT, RABBIT, EAGLE, HUMAN_MALE_1, HUMAN_MALE_2,
					  HUMAN_FEMALE_1, HUMAN_FEMALE_2 }},
	/* d. 3-Forest */
		{ 6,		{ SNARLING_WOLF, BROWN_WOLF, SMALL_WOLF, BUCK, SQUIRREL,
					  BEAR }},
	/* e. 4-Forest */
		{ 6,		{ SNARLING_WOLF, BROWN_WOLF, SMALL_WOLF, SQUIRREL, TIGER,
					  BEAR }},
	/* f. River */
		{ 1,		{ EAGLE }},
	/* g. Ocean */
		{ 0,		{ 0 }},
	/* h. Crop */
		{ 19,		{ SHEEP, DEER, BUCK, COW, CHICKEN, ROOSTER, PRARIE_DOG, HORSE,
					  WARHORSE, QUAIL, MULE, CAT, RABBIT, PIGEON, EAGLE,
					  HUMAN_MALE_1, HUMAN_MALE_2, HUMAN_FEMALE_1, HUMAN_FEMALE_2 }},
	/* i. Mountain */
		{ 3,		{ VULTURE, GOAT, EAGLE }},
	/* j. Road */
		{ 16,		{ SHEEP, DEER, BUCK, COW, CHICKEN, ROOSTER, DOG, WARHORSE,
					  VULTURE, MULE, CAT, RABBIT, PIGEON, EAGLE, HUMAN_MALE_1,
					  HUMAN_FEMALE_1, HUMAN_MALE_2, HUMAN_FEMALE_2 }},
	/* k. Building */
		{ 0,	{ 0 }},
	/* l. Inside */
		{ 0,	{ 0 }},
	/* m. Shrine */
		{ 0,	{ 0 }},
	/* n. Seeded */
		{ 19,		{ SHEEP, DEER, BUCK, COW, CHICKEN, ROOSTER, PRARIE_DOG, HORSE,
					  WARHORSE, QUAIL, MULE, CAT, RABBIT, PIGEON, EAGLE,
					  HUMAN_MALE_1, HUMAN_MALE_2, HUMAN_FEMALE_1, HUMAN_FEMALE_2 }},
	/* o. Well */
		{ 0,	{ 0 }},
	/* p. Fountain */
		{ 0,	{ 0 }},
	/* q. Multi */
		{ 0,	{ 0 }},
	/* r. Unused */
		{ 0,	{ 0 }},
	/* s. Tower of Souls */
		{ 0,	{ 0 }},
	/* t. Wasteland */
		{ 0,	{ 0 }},
	/* u. Desert */
		{ 2,	{ VULTURE, CAMEL }},
	/* v. Oasis */
		{ 2,	{ VULTURE, CAMEL }},
	/* w. Barrier */
		{ 0,	{ 0 }},
	/* x. Monument Open */
		{ 0,	{ 0 }},
	/* y. Monument Closed */
		{ 0,	{ 0 }}
		};

	for (c = character_list; c; c = c->next)
		if (IS_NPC(c)) {
			msg_to_char(ch, "You can't use spawn if any mobs exist.  Please purge them all first.\r\n");
			return;
			}

	/* Warn them about lag */
	for (d = descriptor_list; d; d = d->next)
		write_to_descriptor(d->descriptor, "Beginning animal spawn, this may cause some lag.\r\n");

	msg_to_char(ch, "Animals spawn complete.\r\n");

	/* Begin Spawn */
	for (i = 0, count = 0; i <= top_of_world && count <= 35000; i += number(2, 3)) {
		if (spawn[SECT(i)].num == 0 || !number(0, 2))
			continue;
		if (SECT(i) == SECT_FOREST_1 && world[i].type2)
			continue;
		if (mob_index[real_mobile((n = number(0, spawn[SECT(i)].num-1)))].number > 2000 * (SECT(i) == SECT_OCEAN ? 2 : 1))
			continue;
		char_to_room(read_mobile(spawn[SECT(i)].vnum[n], VIRTUAL), i);
		count++;
		}

	msg_to_char(ch, "Usage:\r\n");
	for (i = 0, j = 0; i < top_of_mobt; i++) {
		if (mob_index[i].number)
			msg_to_char(ch, "%2d: %5d   %s", mob_index[i].vnum, mob_index[i].number, !(++cn % 4) ? "\r\n" : "");
		j += mob_index[i].number;
		}
	msg_to_char(ch, "%sTotal: %d\r\n", !(cn % 4) ? "" : "\r\n", j);
	}


ACMD(do_purgemobs) {
	Creature c, nc;

	for (c = character_list; c; c = nc) {
		nc = c->next;
		if (REAL_NPC(c))
			extract_char(c);
		}
	msg_to_char(ch, "Done.\r\n");
	}


ACMD(do_purgeobjs) {
	room_rnum room;
	Object o, next_o;
	int count = 0;

	for (room = 0; room < MAP_SIZE; room++) {
		if (SECT(room) == SECT_BUILDING || SECT(room) == SECT_INSIDE || SECT(room) == SECT_MULTI || !world[room].contents)
			continue;

		for (o = world[room].contents; o; o = next_o) {
			next_o = o->next_content;
			if (!CAN_WEAR(o, ITEM_WEAR_TAKE))
				continue;
			extract_obj(o);
			count++;
			}
		}
	msg_to_char(ch, "Done.\r\n");
	}


/*
 * do_file
 *  by Haddixx <haddixx@megamed.com>
 * A neat little utility that looks up the last X lines of a given file.
 * I've made some minor improvements to it.. I can't just leave well-enough
 * alone.  Anyway, it's a useful toy and I'm sure EmpireMUD users will love
 * it.
 */
ACMD(do_file) {
	FILE *req_file;
 	int cur_line = 0, num_lines = 0, req_lines = 0, i, j, l;
	char field[MAX_INPUT_LENGTH], value[MAX_INPUT_LENGTH];

	struct file_struct {
		char *cmd;
		int level;
		char *file;
		} fields[] = {
			{ "none",		LVL_TOP+1,		"Does Nothing"			},
			{ "bug",		LVL_CIMPL,		"../lib/misc/bugs"		},
			{ "typo",		LVL_ASST,		"../lib/misc/typos"		},
			{ "ideas",		LVL_CIMPL,		"../lib/misc/ideas"		},
			{ "xnames",		LVL_IMPL,		"../lib/misc/xnames"	},
			{ "syslog",		LVL_IMPL,		"../syslog"				},
			{ "crash",		LVL_IMPL,		"../syslog.CRASH"		},
			{ "ban",		LVL_CIMPL,		"../log/ban"			},
			{ "godcmds",	LVL_CIMPL,		"../log/godcmds"		},
			{ "validation",	LVL_CIMPL,		"../log/validation"		},
			{ "death",		LVL_START_IMM,	"../log/rip"			},
			{ "badpw",		LVL_START_IMM,	"../log/badpw"			},
			{ "delete",		LVL_CIMPL,		"../log/delete"			},
			{ "newplayers",	LVL_START_IMM,	"../log/newplayers"		},
			{ "syserr",		LVL_CIMPL,		"../log/syserr"			},
			{ "level",		LVL_CIMPL,		"../log/levels"			},

			{ "\n", 0, "\n" }
		};

	skip_spaces(&argument);

	if (!*argument) {
		msg_to_char(ch, "USAGE: file <option> <num lines>\r\n\r\nFile options:\r\n");
		for (j = 0, i = 1; fields[i].level; i++)
			if (fields[i].level <= GET_LEVEL(ch))
				msg_to_char(ch, "%-15s%s\r\n", fields[i].cmd, fields[i].file);
		return;
		}

	strcpy(arg, two_arguments(argument, field, value));

	for (l = 0; *fields[l].cmd != '\n' && strncmp(field, fields[l].cmd, strlen(field)); l++);

	if (*fields[l].cmd == '\n') {
		msg_to_char(ch, "That is not a valid option!\r\n");
		return;
		}

	if (GET_LEVEL(ch) < fields[l].level) {
		msg_to_char(ch, "You are not godly enough to view that file!\r\n");
		return;
		}

	req_lines = (*value ? atoi(value) : 15);

	/* open the requested file */
	if (!(req_file = fopen(fields[l].file, "r"))) {
		syslog(GET_INVIS_LEV(ch), TRUE, "SYSERR: Error opening file %s using 'file' command.", fields[l].file);
		return;
		}

	/* count lines in requested file */
	get_line(req_file,buf);
	while (!feof(req_file)) {
		num_lines++;
		get_line(req_file,buf);
		}
	fclose(req_file);

	/* Limit # of lines printed to # requested or # of lines in file or 150 lines */
	req_lines = MIN(150, MIN(req_lines, num_lines));

	/* re-open */
	req_file = fopen(fields[l].file, "r");
	*buf2 = '\0';

	/* and print the requested lines */
	get_line(req_file, buf);
	while (!feof(req_file)) {
		cur_line++;
		if (cur_line > (num_lines - req_lines))
			sprintf(buf2,"%s%s\r\n",buf2, buf);
		get_line(req_file,buf);
		}
	page_string(ch->desc, buf2, 1);

	fclose(req_file);
	}


/* Command which gives experience points */
ACMD(do_reward) {
	Creature target;
	int exp;

	two_arguments(argument, buf, arg);

	if (!*buf || !*arg)
		msg_to_char(ch, "Reward whom, and how much experience?\r\n");
	else if (!(target = get_char_vis(ch, buf, FIND_CHAR_WORLD)))
		msg_to_char(ch, NOPERSON);
	else if (IS_NPC(target))
		msg_to_char(ch, "You can't reward an NPC.\r\n");
	else if (!IS_IMMORTAL(ch))
		msg_to_char(ch, "You can only reward mortals.\r\n");
	else if (!(exp = atoi(arg)))
		msg_to_char(ch, "Reward how much experience?\r\n");
	else if (exp + GET_EXP_TODAY(target) > 5 && GET_LEVEL(ch) < LVL_TOP)
		msg_to_char(ch, "You may not reward more than five experience points per day.  Your target has already received %d.\r\n", GET_EXP_TODAY(target));
	else if (exp < -5)
		msg_to_char(ch, "You may not take away more than 5 experience points.\r\n");
	else {
		if (exp > 0)
			GET_EXP_TODAY(target) = MIN(5, GET_EXP_TODAY(target) + exp);
		gain_experience(target, exp);
		sprintf(buf, "You reward %d experience points to $N, $E now has %d.", exp, GET_EXPERIENCE(target));
		act(buf, FALSE, ch, 0, target, TO_CHAR);
		if (ch != target) {
			if (exp > 0)
				msg_to_char(target, "You are rewarded %d experience points.  You now have %d.\r\n", exp, GET_EXPERIENCE(target));
			else
				msg_to_char(target, "You lose %d experience points.  You now have %d.\r\n", exp, GET_EXPERIENCE(target));
			}
		}
	}