circlemud_squared_0.5.153/cnf/
circlemud_squared_0.5.153/etc/
circlemud_squared_0.5.153/etc/etc/
circlemud_squared_0.5.153/etc/house/
circlemud_squared_0.5.153/etc/misc/
circlemud_squared_0.5.153/etc/plralias/A-E/
circlemud_squared_0.5.153/etc/plralias/F-J/
circlemud_squared_0.5.153/etc/plralias/K-O/
circlemud_squared_0.5.153/etc/plralias/P-T/
circlemud_squared_0.5.153/etc/plralias/U-Z/
circlemud_squared_0.5.153/etc/plralias/ZZZ/
circlemud_squared_0.5.153/etc/plrobjs/
circlemud_squared_0.5.153/etc/plrobjs/A-E/
circlemud_squared_0.5.153/etc/plrobjs/F-J/
circlemud_squared_0.5.153/etc/plrobjs/K-O/
circlemud_squared_0.5.153/etc/plrobjs/P-T/
circlemud_squared_0.5.153/etc/plrobjs/U-Z/
circlemud_squared_0.5.153/etc/plrobjs/ZZZ/
circlemud_squared_0.5.153/etc/text/
circlemud_squared_0.5.153/etc/text/help/
circlemud_squared_0.5.153/src/util/
circlemud_squared_0.5.153/src/util/worldconv/
/**
 * @file act_wizard.c
 * @ingroup common
 *
 * Player-level god commands and other goodies
 *
 * @author Part of CircleMUD
 *
 * @par Copyright:
 *   Copyright (C) 1993, 94 by the Trustees of the Johns Hopkins University<br>
 *   CircleMUD is based on DikuMUD, Copyright (C) 1990, 1991.
 *
 * @par
 *   All rights reserved.  See license.doc for complete information.
 *
 * @package cs
 * @version 1.0
 */

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

#include "utils.h"
#include "character.h"
#include "comm.h"
#include "command.h"
#include "constants.h"
#include "db.h"
#include "handler.h"
#include "house.h"
#include "interpreter.h"
#include "log.h"
#include "screen.h"
#include "spells.h"
#include "sstring.h"
#include "room.h"
#include "item.h"
#include "mobile.h"
#include "zone.h"

/*   external vars  */
extern FILE *player_fl;
extern attackHitType_t attack_hit_text[];
extern char *class_abbrevs[];
extern time_t boot_time;
extern int circle_shutdown, circle_reboot;
extern int circle_restrict;
extern int load_into_inventory;
extern int buf_switches, buf_largecount, buf_overflows;
extern int top_of_p_table;

/* for chars */
extern const char *pc_class_types[];

/* extern functions */
int level_exp(int chclass, int level);
void show_shops(charData_t *ch, char *value);
void hcontrol_list_houses(charData_t *ch);
void do_start(charData_t *ch);
void appear(charData_t *ch);
void roll_real_abils(charData_t *ch);
int parse_class(char arg);
void run_autowiz(void);

/* local functions */
int perform_set(charData_t *ch, charData_t *vict, int mode, char *val_arg);
void perform_immort_invis(charData_t *ch, int level);
roomData_t *find_target_room(charData_t *ch, char *rawroomstr);
void do_stat_room(charData_t *ch);
void do_stat_item(charData_t *ch, itemData_t *j);
void do_stat_character(charData_t *ch, charData_t *k);
void stop_snooping(charData_t *ch);
void perform_immort_vis(charData_t *ch);
size_t print_zone_to_buf(char *buf, size_t left, charData_t *ch, zoneData_t *zone);
void snoop_check(charData_t *ch);

/**
 * ECHO and EMOTE commands
 *
 * This command lets a user output text to the room
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_echo)
{
  skip_spaces(&argument);

  if (!*argument)
    send_to_char(ch, "Yes.. but what?\r\n");
  else {
    char buf[MAX_INPUT_LENGTH + 4];

    if (CMD_IS("emote"))
      snprintf(buf, sizeof(buf), "$n %s", argument);
    else
      strlcpy(buf, argument, sizeof(buf));

    act(buf, FALSE, ch, 0, 0, TO_ROOM);

    if (PRF_FLAGGED(ch, PRF_NOREPEAT))
      send_to_char(ch, "%s", OK);
    else
      act(buf, FALSE, ch, 0, 0, TO_CHAR);
  }
}

/**
 * SEND command
 *
 * This command lets a user send text to another user
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_send)
{
  char arg[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH];
  charData_t *vict;

  half_chop(argument, arg, buf);

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

/**
 * Find a room's based on room VNum or name
 *
 * take a string, and return an pointer.. used for goto, at, etc.
 *
 * @param ch Character looking for the room
 * @param rawroomstr String value to use in the search
 * @return pointer to room or NULL
 */
roomData_t *find_target_room(charData_t *ch, char *rawroomstr)
{
  roomData_t *location = NULL;
  char roomstr[MAX_INPUT_LENGTH];

  one_argument(rawroomstr, roomstr);

  if (!*roomstr) {
    send_to_char(ch, "You must supply a room id or name.\r\n");
    return (NULL);
  }

  if (strstr(rawroomstr, ":") != NULL || (isdigit(*roomstr) && !strchr(roomstr, '.'))) {
    if ((location = roomData_findForChar(ch, roomstr)) == NULL) {
      send_to_char(ch, "No room exists with that id.\r\n");
      return (NULL);
    }
  } else {
    charData_t *target_mob;
    itemData_t *target_item;
    char *mobobjstr = roomstr;
    int num;

    num = get_number(&mobobjstr);
    if ((target_mob = get_char_vis(ch, mobobjstr, &num, FIND_CHAR_WORLD)) != NULL) {
      if ((location = IN_ROOM(target_mob)) == NULL) {
        send_to_char(ch, "That character is currently lost.\r\n");
        return (NULL);
      }
    } else if ((target_item = get_item_vis(ch, mobobjstr, &num)) != NULL) {
      if (IN_ROOM(target_item) != NULL)
        location = IN_ROOM(target_item);
      else if (target_item->carriedBy && IN_ROOM(target_item->carriedBy) != NULL)
        location = IN_ROOM(target_item->carriedBy);
      else if (target_item->wornBy && IN_ROOM(target_item->wornBy) != NULL)
        location = IN_ROOM(target_item->wornBy);

      if (location == NULL) {
        send_to_char(ch, "That object is currently not in a room.\r\n");
        return (NULL);
      }
    }

    if (location == NULL) {
      send_to_char(ch, "Nothing exists by that name.\r\n");
      return (NULL);
    }
  }

  /* a location has been found -- if you're >= GRGOD, no restrictions. */
  if (GET_AUTH(ch) >= AUTH_WIZARD)
    return (location);

  if (ROOM_FLAGGED(location, ROOM_WIZROOM))
    send_to_char(ch, "You are not godly enough to use that room!\r\n");
  else if (ROOM_FLAGGED(location, ROOM_PRIVATE) && location->people && location->people->next_in_room)
    send_to_char(ch, "There's a private conversation going on in that room.\r\n");
  else if (ROOM_FLAGGED(location, ROOM_HOUSE) && !House_can_enter(ch, location))
    send_to_char(ch, "That's private property -- no trespassing!\r\n");
  else
    return (location);

  return (NULL);
}

/**
 * AT command
 *
 * This command lets a user perform a command in another room
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_at)
{
  char command[MAX_INPUT_LENGTH], buf[MAX_INPUT_LENGTH];
  roomData_t *location = NULL, *original_loc = NULL;

  half_chop(argument, buf, command);

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

  if ((location = find_target_room(ch, buf)) == NULL) {
    return;
  }

  /* a location has been found. */
  original_loc = IN_ROOM(ch);
  char_fromRoom(ch);
  char_toRoom(ch, location);
  command_interpreter(ch, command);

  /* check if the char is still there */
  if (IN_ROOM(ch) == location) {
    char_fromRoom(ch);
    char_toRoom(ch, original_loc);
  }
}

/**
 * GOTO command
 *
 * This command lets a user move to another room
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_goto)
{
  char buf[MAX_STRING_LENGTH];
  roomData_t *location = NULL;
  charData_t *victim = NULL;

  skip_spaces(&argument);
  if (!argument || !*argument) {
    send_to_char(ch, "Where is it you want to go?\r\n");
  }

  /* See if we can find a character named first, else see if it's a room */
  victim = get_char_vis(ch, argument, NULL, FIND_CHAR_WORLD);
  if (victim == NULL || victim->room == NULL) {
    if ((location = find_target_room(ch, argument)) == NULL) {
      return;
    }
  } else {
    location = victim->room;
  }

  snprintf(buf, sizeof(buf), "$n %s", POOFOUT(ch) ? POOFOUT(ch) : "disappears in a puff of smoke.");
  act(buf, TRUE, ch, 0, 0, TO_ROOM);

  char_fromRoom(ch);
  char_toRoom(ch, location);

  snprintf(buf, sizeof(buf), "$n %s", POOFIN(ch) ? POOFIN(ch) : "appears with an ear-splitting bang.");
  act(buf, TRUE, ch, 0, 0, TO_ROOM);

  look_at_room(ch, 0);
}

/**
 * TRANS command
 *
 * This command lets a user transfer a character to their location
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_trans)
{
  char buf[MAX_INPUT_LENGTH];
  descriptorData_t *i;
  charData_t *victim;

  one_argument(argument, buf);
  if (!*buf)
    send_to_char(ch, "Whom do you wish to transfer?\r\n");
  else if (str_cmp("all", buf)) {
    if (!(victim = get_char_vis(ch, buf, NULL, FIND_CHAR_WORLD)))
      send_to_char(ch, "%s", NOPERSON);
    else if (victim == ch)
      send_to_char(ch, "That doesn't make much sense, does it?\r\n");
    else {
      if ((GET_LEVEL(ch) < GET_LEVEL(victim)) && !IS_NPC(victim)) {
	send_to_char(ch, "Go transfer someone your own size.\r\n");
	return;
      }
      act("$n disappears in a mushroom cloud.", FALSE, victim, 0, 0, TO_ROOM);
      char_fromRoom(victim);
      char_toRoom(victim, IN_ROOM(ch));
      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, 0);
    }
  } else {			/* Trans All */
    if (GET_AUTH(ch) < AUTH_WIZARD) {
      send_to_char(ch, "I think not.\r\n");
      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_fromRoom(victim);
	char_toRoom(victim, IN_ROOM(ch));
	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, 0);
      }
    send_to_char(ch, "%s", OK);
  }
}

/**
 * TELEPORT command
 *
 * This command lets a user teleport another character from one room to another
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_teleport)
{
  char buf[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];
  charData_t *victim;
  roomData_t *target = NULL;

  two_arguments(argument, buf, buf2);

  if (!*buf)
    send_to_char(ch, "Whom do you wish to teleport?\r\n");
  else if (!(victim = get_char_vis(ch, buf, NULL, FIND_CHAR_WORLD)))
    send_to_char(ch, "%s", NOPERSON);
  else if (victim == ch)
    send_to_char(ch, "Use 'goto' to teleport yourself.\r\n");
  else if (GET_LEVEL(victim) >= GET_LEVEL(ch))
    send_to_char(ch, "Maybe you shouldn't do that.\r\n");
  else if (!*buf2)
    send_to_char(ch, "Where do you wish to send this person?\r\n");
  else if ((target = find_target_room(ch, buf2)) != NULL) {
    send_to_char(ch, "%s", OK);
    act("$n disappears in a puff of smoke.", FALSE, victim, 0, 0, TO_ROOM);
    char_fromRoom(victim);
    char_toRoom(victim, target);
    act("$n arrives from a puff of smoke.", FALSE, victim, 0, 0, TO_ROOM);
    act("$n has teleported you!", FALSE, ch, 0, (char *) victim, TO_VICT);
    look_at_room(victim, 0);
  }
}

/**
 * VNUM command
 *
 * This command lets a user search for an item, mob, or room by name
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_vnum)
{
  char buf[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];

  half_chop(argument, buf, buf2);

  if (!*buf || !*buf2 || (!is_abbrev(buf, "mob") && !is_abbrev(buf, "item") && !is_abbrev(buf, "room"))) {
    send_to_char(ch, "Usage: vnum { item | mob | room } <virtual>\r\n");
    return;
  }

  if (is_abbrev(buf, "mob"))
    if (!vnum_search(ch, MOBILES, buf2))
      send_to_char(ch, "No mobiles by that name.\r\n");

  if (is_abbrev(buf, "item"))
    if (!vnum_search(ch, ITEMPS, buf2))
      send_to_char(ch, "No items by that name.\r\n");

  if (is_abbrev(buf, "room"))
    if (!vnum_search(ch, ROOMS, buf2))
      send_to_char(ch, "No rooms by that name.\r\n");
}

/**
 * Display the detailed stats of the room the character is in.
 * 
 * @todo Change the multiple send_to_char() calls to a single buffer which can be paged
 *
 * @param ch Character to send the stats to
 * @return none
 */
void do_stat_room(charData_t *ch)
{
  char buf2[MAX_STRING_LENGTH];
  extraDescData_t *desc;
  roomData_t *rm = ch->room;
  int i, found, column;
  itemData_t *j;
  charData_t *k;

  send_to_char(ch, "Room name: %s%s%s\r\n", CCCYN(ch, C_NRM), rm->name, CCNRM(ch, C_NRM));

  sprinttype(rm->sectorType, sector_types, buf2, sizeof(buf2));
  send_to_char(ch, "VNum: [%s%s:%d%s], Type: %s\r\n",
	  CCGRN(ch, C_NRM), rm->zone->keyword, rm->number,
	  CCNRM(ch, C_NRM), buf2);

  sprintbit(rm->roomFlags, room_bits, buf2, sizeof(buf2));
  send_to_char(ch, "SpecProc: %s, Flags: %s\r\n", rm->func == NULL ? "None" : "Exists", buf2);

  send_to_char(ch, "Description:\r\n%s", rm->description ? rm->description : "  None.\r\n");

  if (rm->exDescription) {
    send_to_char(ch, "Extra descs:%s", CCCYN(ch, C_NRM));
    for (desc = rm->exDescription; desc; desc = desc->next)
      send_to_char(ch, " %s", desc->keyword);
    send_to_char(ch, "%s\r\n", CCNRM(ch, C_NRM));
  }

  send_to_char(ch, "Chars present:%s", CCYEL(ch, C_NRM));
  column = 14;	/* ^^^ strlen ^^^ */
  for (found = FALSE, k = rm->people; k; k = k->next_in_room) {
    if (!CAN_SEE(ch, k))
      continue;

    column += send_to_char(ch, "%s %s(%s)", found++ ? "," : "", GET_NAME(k),
		!IS_NPC(k) ? "PC" : (!IS_MOB(k) ? "NPC" : "MOB"));
    if (column >= 62) {
      send_to_char(ch, "%s\r\n", k->next_in_room ? "," : "");
      found = FALSE;
      column = 0;
    }
  }
  send_to_char(ch, "%s", CCNRM(ch, C_NRM));

  if (rm->contents) {
    send_to_char(ch, "Contents:%s", CCGRN(ch, C_NRM));
    column = 9;	/* ^^^ strlen ^^^ */

    for (found = 0, j = rm->contents; j; j = j->nextContent) {
      if (!CAN_SEE_ITEM(ch, j))
	continue;

      column += send_to_char(ch, "%s %s", found++ ? "," : "", j->shortDescription);
      if (column >= 62) {
	send_to_char(ch, "%s\r\n", j->nextContent ? "," : "");
	found = FALSE;
        column = 0;
      }
    }
    send_to_char(ch, "%s", CCNRM(ch, C_NRM));
  }

  for (i = 0; i < NUM_OF_DIRS; i++) {
    char buf1[128];

    if (!rm->dir[i])
      continue;

    if (rm->dir[i]->toRoom == NULL)
      snprintf(buf1, sizeof(buf1), " %sNONE%s", CCCYN(ch, C_NRM), CCNRM(ch, C_NRM));
    else
      snprintf(buf1, sizeof(buf1), "%s%s:%d%s", CCCYN(ch, C_NRM), rm->dir[i]->toRoom->zone->keyword, rm->dir[i]->toRoom->number, CCNRM(ch, C_NRM));

    sprintbit(rm->dir[i]->exitInfo, exit_bits, buf2, sizeof(buf2));

    send_to_char(ch, "Exit %s%-5s%s:  To: [%s], Key: [%s], Keywrd: %s, Type: %s\r\n%s",
	CCCYN(ch, C_NRM), dirs[i], CCNRM(ch, C_NRM), buf1, rm->dir[i]->keyString ? rm->dir[i]->keyString : "None",
	rm->dir[i]->keyword ? rm->dir[i]->keyword : "None", buf2,
	rm->dir[i]->generalDescription ? rm->dir[i]->generalDescription : "  No exit description.\r\n");
  }
}

/**
 * Display the detailed stats of an item to a character
 *
 * @todo Change the multiple send_to_char() calls to a single buffer which can be paged
 *
 * @param ch Character to send the stats to
 * @param j Item to stat
 * @return none
 */
void do_stat_item(charData_t *ch, itemData_t *j)
{
  int i, found;
  itemData_t *j2;
  extraDescData_t *desc;
  char buf[MAX_STRING_LENGTH];

  send_to_char(ch, "Name: '%s%s%s', Aliases: %s\r\n", CCYEL(ch, C_NRM),
	  j->shortDescription ? j->shortDescription : "<None>",
	  CCNRM(ch, C_NRM), j->name);

  sprinttype(GET_ITEM_TYPE(j), item_types, buf, sizeof(buf));
  send_to_char(ch, "Item: [%s%s:%d%s], Type: %s, SpecProc: %s\r\n",
	CCGRN(ch, C_NRM), j->zone->keyword, j->vnum, CCNRM(ch, C_NRM), buf,
	GET_ITEM_SPEC(j) ? "Exists" : "None");

  if (j->exDescription) {
    send_to_char(ch, "Extra descs:%s", CCCYN(ch, C_NRM));
    for (desc = j->exDescription; desc; desc = desc->next)
      send_to_char(ch, " %s", desc->keyword);
    send_to_char(ch, "%s\r\n", CCNRM(ch, C_NRM));
  }

  sprintbit(GET_ITEM_WEAR(j), wear_bits, buf, sizeof(buf));
  send_to_char(ch, "Can be worn on: %s\r\n", buf);

  sprintbit(GET_ITEM_AFFECT(j), affected_bits, buf, sizeof(buf));
  send_to_char(ch, "Set char bits : %s\r\n", buf);

  sprintbit(GET_ITEM_EXTRA(j), extra_bits, buf, sizeof(buf));
  send_to_char(ch, "Extra flags   : %s\r\n", buf);

  send_to_char(ch, "Weight: %d, Value: %d, Cost/day: %d, Timer: %d\r\n",
     GET_ITEM_WEIGHT(j), GET_ITEM_COST(j), GET_ITEM_RENT(j), GET_ITEM_TIMER(j));

  if (j->room) {
    send_to_char(ch, "In room: %s:%d (%s), ", j->room->zone->keyword, j->room->number, IN_ROOM(j) == NULL ? "Nowhere" : j->room->name);
  } else {
    send_to_char(ch, "In room: None, ");
  }

  /*
   * 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().
   */
  send_to_char(ch, "In object: %s, ", j->inObj ? j->inObj->shortDescription : "None");
  send_to_char(ch, "Carried by: %s, ", j->carriedBy ? GET_NAME(j->carriedBy) : "Nobody");
  send_to_char(ch, "Worn by: %s\r\n", j->wornBy ? GET_NAME(j->wornBy) : "Nobody");

  switch (GET_ITEM_TYPE(j)) {
  case ITEM_LIGHT:
    if (GET_ITEM_VAL(j, 2) == -1)
      send_to_char(ch, "Hours left: Infinite\r\n");
    else
      send_to_char(ch, "Hours left: [%d]\r\n", GET_ITEM_VAL(j, 2));
    break;
  case ITEM_SCROLL:
  case ITEM_POTION:
    send_to_char(ch, "Spells: (Level %d) %s, %s, %s\r\n", GET_ITEM_VAL(j, 0),
	    skill_name(GET_ITEM_VAL(j, 1)), skill_name(GET_ITEM_VAL(j, 2)),
	    skill_name(GET_ITEM_VAL(j, 3)));
    break;
  case ITEM_WAND:
  case ITEM_STAFF:
    send_to_char(ch, "Spell: %s at level %d, %d (of %d) charges remaining\r\n",
	    skill_name(GET_ITEM_VAL(j, 3)), GET_ITEM_VAL(j, 0),
	    GET_ITEM_VAL(j, 2), GET_ITEM_VAL(j, 1));
    break;
  case ITEM_WEAPON:
    send_to_char(ch, "Todam: %dd%d, Message type: %d\r\n",
	    GET_ITEM_VAL(j, 1), GET_ITEM_VAL(j, 2), GET_ITEM_VAL(j, 3));
    break;
  case ITEM_ARMOR:
    send_to_char(ch, "AC-apply: [%d]\r\n", GET_ITEM_VAL(j, 0));
    break;
  case ITEM_TRAP:
    send_to_char(ch, "Spell: %d, - Hitpoints: %d\r\n", GET_ITEM_VAL(j, 0), GET_ITEM_VAL(j, 1));
    break;
  case ITEM_CONTAINER:
    sprintbit(GET_ITEM_VAL(j, 1), container_bits, buf, sizeof(buf));
    send_to_char(ch, "Weight capacity: %d, Lock Type: %s, Key Num: %d, Corpse: %s\r\n",
	    GET_ITEM_VAL(j, 0), buf, GET_ITEM_VAL(j, 2),
	    YESNO(GET_ITEM_VAL(j, 3)));
    break;
  case ITEM_DRINKCON:
  case ITEM_FOUNTAIN:
    sprinttype(GET_ITEM_VAL(j, 2), drinks, buf, sizeof(buf));
    send_to_char(ch, "Capacity: %d, Contains: %d, Poisoned: %s, Liquid: %s\r\n",
	    GET_ITEM_VAL(j, 0), GET_ITEM_VAL(j, 1), YESNO(GET_ITEM_VAL(j, 3)), buf);
    break;
  case ITEM_NOTE:
    send_to_char(ch, "Tongue: %d\r\n", GET_ITEM_VAL(j, 0));
    break;
  case ITEM_KEY:
    /* Nothing */
    break;
  case ITEM_FOOD:
    send_to_char(ch, "Makes full: %d, Poisoned: %s\r\n", GET_ITEM_VAL(j, 0), YESNO(GET_ITEM_VAL(j, 3)));
    break;
  case ITEM_MONEY:
    send_to_char(ch, "Coins: %d\r\n", GET_ITEM_VAL(j, 0));
    break;
  default:
    send_to_char(ch, "Values 0-3: [%d] [%d] [%d] [%d]\r\n",
	    GET_ITEM_VAL(j, 0), GET_ITEM_VAL(j, 1),
	    GET_ITEM_VAL(j, 2), GET_ITEM_VAL(j, 3));
    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) {
    int column;

    send_to_char(ch, "\r\nContents:%s", CCGRN(ch, C_NRM));
    column = 9;	/* ^^^ strlen ^^^ */

    for (found = 0, j2 = j->contains; j2; j2 = j2->nextContent) {
      column += send_to_char(ch, "%s %s", found++ ? "," : "", j2->shortDescription);
      if (column >= 62) {
	send_to_char(ch, "%s\r\n", j2->nextContent ? "," : "");
	found = FALSE;
        column = 0;
      }
    }
    send_to_char(ch, "%s", CCNRM(ch, C_NRM));
  }

  found = FALSE;
  send_to_char(ch, "Affections:");
  for (i = 0; i < MAX_ITEM_AFFECT; i++)
    if (j->affected[i].modifier) {
      sprinttype(j->affected[i].location, apply_types, buf, sizeof(buf));
      send_to_char(ch, "%s %+d to %s", found++ ? "," : "", j->affected[i].modifier, buf);
    }
  if (!found)
    send_to_char(ch, " None");

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

/**
 * Display the detailed stats of a character to a character
 *
 * @todo Change the multiple send_to_char() calls to a single buffer which can be paged
 *
 * @param ch Character to send the stats to
 * @param k Character to stat
 * @return none
 */
void do_stat_character(charData_t *ch, charData_t *k)
{
  char buf[MAX_STRING_LENGTH];
  int i, i2, column, found = FALSE;
  itemData_t *j;
  followData_t *fol;
  effectData_t *aff;

  sprinttype(GET_SEX(k), genders, buf, sizeof(buf));

  if (!IS_NPC(k)) {
    send_to_char(ch, "%s %s '%s'  IDNum: [%5ld], In room: ", buf, "PC", GET_NAME(k), GET_IDNUM(k));
  } else if (!IS_MOB(k)) {
    send_to_char(ch, "%s %s '%s'  IDNum: [%5ld], In room: ", buf, "NPC", GET_NAME(k), GET_IDNUM(k));
  } else {
    send_to_char(ch, "%s %s '%s'  IDNum: [%s:%d], In room: ", buf, "MOB", GET_NAME(k), (k)->zone->keyword, (k)->vnum);
  }

  if (IN_ROOM(k)) {
    send_to_char(ch, "[%s:%d]\r\n", IN_ROOM(k)->zone->keyword, IN_ROOM(k)->number);
  } else {
    send_to_char(ch, "None.\r\n");
  }

  if (IS_MOB(k))
    send_to_char(ch, "Alias: %s\r\n", k->player.name);

  sprinttype(GET_AUTH(k), auth_types, buf, sizeof(buf));
  send_to_char(ch, "Auth: %s, Title: %s\r\n", buf, k->player.title ? k->player.title : "<None>");

  send_to_char(ch, "L-Des: %s", k->player.long_descr ? k->player.long_descr : "<None>\r\n");

  sprinttype(k->player.chclass, IS_NPC(k) ? npc_class_types : pc_class_types, buf, sizeof(buf));
  send_to_char(ch, "%sClass: %s, Lev: [%s%2d%s], XP: [%s%7d%s], Align: [%4d]\r\n",
	IS_NPC(k) ? "Monster " : "", buf, CCYEL(ch, C_NRM), GET_LEVEL(k), CCNRM(ch, C_NRM),
	CCYEL(ch, C_NRM), GET_EXP(k), CCNRM(ch, C_NRM), GET_ALIGNMENT(k));

  if (!IS_NPC(k)) {
    char buf1[64], buf2[64];

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

    send_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);

    send_to_char(ch, "Hometown: [%d], Speaks: [%d/%d/%d], (STL[%d]/per[%d]/NSTL[%d])\r\n",
	 k->player.hometown, GET_TALK(k, 0), GET_TALK(k, 1), GET_TALK(k, 2),
	    GET_PRACTICES(k), int_app[GET_INT(k)].learn,
	    wis_app[GET_WIS(k)].bonus);
  }
  send_to_char(ch, "Str: [%s%d/%d%s]  Int: [%s%d%s]  Wis: [%s%d%s]  "
	  "Dex: [%s%d%s]  Con: [%s%d%s]  Cha: [%s%d%s]\r\n",
	  CCCYN(ch, C_NRM), GET_STR(k), GET_ADD(k), CCNRM(ch, C_NRM),
	  CCCYN(ch, C_NRM), GET_INT(k), CCNRM(ch, C_NRM),
	  CCCYN(ch, C_NRM), GET_WIS(k), CCNRM(ch, C_NRM),
	  CCCYN(ch, C_NRM), GET_DEX(k), CCNRM(ch, C_NRM),
	  CCCYN(ch, C_NRM), GET_CON(k), CCNRM(ch, C_NRM),
	  CCCYN(ch, C_NRM), GET_CHA(k), CCNRM(ch, C_NRM));

  send_to_char(ch, "Hit p.:[%s%d/%d+%d%s]  Mana p.:[%s%d/%d+%d%s]  Move p.:[%s%d/%d+%d%s]\r\n",
	  CCGRN(ch, C_NRM), GET_HIT(k), GET_MAX_HIT(k), hit_gain(k), CCNRM(ch, C_NRM),
	  CCGRN(ch, C_NRM), GET_MANA(k), GET_MAX_MANA(k), mana_gain(k), CCNRM(ch, C_NRM),
	  CCGRN(ch, C_NRM), GET_MOVE(k), GET_MAX_MOVE(k), move_gain(k), CCNRM(ch, C_NRM));

  send_to_char(ch, "Coins: [%9d], Bank: [%9d] (Total: %d)\r\n",
	  GET_GOLD(k), GET_BANK_GOLD(k), GET_GOLD(k) + GET_BANK_GOLD(k));

  send_to_char(ch, "AC: [%d%+d/10], Hitroll: [%2d], Damroll: [%2d], Saving throws: [%d/%d/%d/%d/%d]\r\n",
	  GET_AC(k), dex_app[GET_DEX(k)].defensive, k->points.hitroll,
	  k->points.damroll, GET_SAVE(k, 0), GET_SAVE(k, 1), GET_SAVE(k, 2),
	  GET_SAVE(k, 3), GET_SAVE(k, 4));

  sprinttype(GET_POS(k), position_types, buf, sizeof(buf));
  send_to_char(ch, "Pos: %s, Fighting: %s", buf, FIGHTING(k) ? GET_NAME(FIGHTING(k)) : "Nobody");

  if (IS_NPC(k))
    send_to_char(ch, ", Attack type: %s", attack_hit_text[(int) k->mob_specials.attack_type].singular);

  if (k->desc) {
    sprinttype(STATE(k->desc), connected_types, buf, sizeof(buf));
    send_to_char(ch, ", Connected: %s", buf);
  }

  if (IS_NPC(k)) {
    sprinttype(k->mob_specials.default_pos, position_types, buf, sizeof(buf));
    send_to_char(ch, ", Default position: %s\r\n", buf);
    sprintbit(MOB_FLAGS(k), action_bits, buf, sizeof(buf));
    send_to_char(ch, "NPC flags: %s%s%s\r\n", CCCYN(ch, C_NRM), buf, CCNRM(ch, C_NRM));
  } else {
    send_to_char(ch, ", Idle Timer (in tics) [%d]\r\n", k->char_specials.timer);

    sprintbit(PLR_FLAGS(k), player_bits, buf, sizeof(buf));
    send_to_char(ch, "PLR: %s%s%s\r\n", CCCYN(ch, C_NRM), buf, CCNRM(ch, C_NRM));

    sprintbit(PRF_FLAGS(k), preference_bits, buf, sizeof(buf));
    send_to_char(ch, "PRF: %s%s%s\r\n", CCGRN(ch, C_NRM), buf, CCNRM(ch, C_NRM));
  }

  if (IS_MOB(k))
    send_to_char(ch, "Mob Spec-Proc: %s, NPC Bare Hand Dam: %dd%d\r\n",
	    (GET_MOB_SPEC(k) ? "Exists" : "None"),
	    k->mob_specials.damnodice, k->mob_specials.damsizedice);

  for (i = 0, j = k->carrying; j; j = j->nextContent, i++);
  send_to_char(ch, "Carried: weight: %d, items: %d; Items in: inventory: %d, ", IS_CARRYING_W(k), IS_CARRYING_N(k), i);

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

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

  column = send_to_char(ch, "Master is: %s, Followers are:", k->master ? GET_NAME(k->master) : "<none>");
  if (!k->followers)
    send_to_char(ch, " <none>\r\n");
  else {
    for (fol = k->followers; fol; fol = fol->next) {
      column += send_to_char(ch, "%s %s", found++ ? "," : "", PERS(fol->follower, ch));
      if (column >= 62) {
        send_to_char(ch, "%s\r\n", fol->next ? "," : "");
        found = FALSE;
        column = 0;
      }
    }
    if (column != 0)
      send_to_char(ch, "\r\n");
  }

  /* Showing the bitvector */
  sprintbit(AFF_FLAGS(k), affected_bits, buf, sizeof(buf));
  send_to_char(ch, "AFF: %s%s%s\r\n", CCYEL(ch, C_NRM), buf, CCNRM(ch, C_NRM));

  /* Routine to show what spells a char is affected by */
  if (k->affected) {
    for (aff = k->affected; aff; aff = aff->next) {
      send_to_char(ch, "SPL: (%3dhr) %s%-21s%s ", aff->duration + 1, CCCYN(ch, C_NRM), skill_name(aff->type), CCNRM(ch, C_NRM));

      if (aff->modifier)
	send_to_char(ch, "%+d to %s", aff->modifier, apply_types[(int) aff->location]);

      if (aff->bitvector) {
	if (aff->modifier)
	  send_to_char(ch, ", ");

	sprintbit(aff->bitvector, affected_bits, buf, sizeof(buf));
        send_to_char(ch, "sets %s", buf);
      }
      send_to_char(ch, "\r\n");
    }
  }
}

/**
 * STAT command
 *
 * This command lets a user see detailed information on a target
 *
 * @sa do_stat_character
 * @sa do_stat_item
 * @sa do_stat_room
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_stat)
{
  char buf1[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];
  charData_t *victim;
  itemData_t *item;
  pfileElement_t tmp_store;

  half_chop(argument, buf1, buf2);

  if (!*buf1) {
    send_to_char(ch, "Stats on who or what?\r\n");
    return;
  } else if (is_abbrev(buf1, "room")) {
    do_stat_room(ch);
  } else if (is_abbrev(buf1, "mob")) {
    if (!*buf2)
      send_to_char(ch, "Stats on which mobile?\r\n");
    else {
      if ((victim = get_char_vis(ch, buf2, NULL, FIND_CHAR_WORLD)) != NULL)
	do_stat_character(ch, victim);
      else
	send_to_char(ch, "No such mobile around.\r\n");
    }
  } else if (is_abbrev(buf1, "player")) {
    if (!*buf2) {
      send_to_char(ch, "Stats on which player?\r\n");
    } else {
      if ((victim = get_player_vis(ch, buf2, NULL, FIND_CHAR_WORLD)) != NULL)
	do_stat_character(ch, victim);
      else
	send_to_char(ch, "No such player around.\r\n");
    }
  } else if (is_abbrev(buf1, "file")) {
    if (!*buf2)
      send_to_char(ch, "Stats on which player?\r\n");
    else if ((victim = get_player_vis(ch, buf2, NULL, FIND_CHAR_WORLD)) != NULL)
	do_stat_character(ch, victim);
    else {
      CREATE(victim, charData_t, 1);
      clear_char(victim);
      if (load_char(buf2, &tmp_store) >= 0) {
	store_to_char(&tmp_store, victim);
	victim->player.time.logon = tmp_store.last_logon;
	char_toRoom(victim, 0);
	if (GET_LEVEL(victim) > GET_LEVEL(ch))
	  send_to_char(ch, "Sorry, you can't do that.\r\n");
	else
	  do_stat_character(ch, victim);
	char_extractFinal(victim);
      } else {
	send_to_char(ch, "There is no such player.\r\n");
	free(victim);
      }
    }
  } else if (is_abbrev(buf1, "item")) {
    if (!*buf2)
      send_to_char(ch, "Stats on which item?\r\n");
    else {
      if ((item = get_item_vis(ch, buf2, NULL)) != NULL)
	do_stat_item(ch, item);
      else
	send_to_char(ch, "No such item around.\r\n");
    }
  } else {
    char *name = buf1;
    int number = get_number(&name);

    if ((item = get_item_in_equip_vis(ch, name, &number, ch->equipment)) != NULL)
      do_stat_item(ch, item);
    else if ((item = get_item_in_list_vis(ch, name, &number, ch->carrying)) != NULL)
      do_stat_item(ch, item);
    else if ((victim = get_char_vis(ch, name, &number, FIND_CHAR_ROOM)) != NULL)
      do_stat_character(ch, victim);
    else if ((item = get_item_in_list_vis(ch, name, &number, ch->room->contents)) != NULL)
      do_stat_item(ch, item);
    else if ((victim = get_char_vis(ch, name, &number, FIND_CHAR_WORLD)) != NULL)
      do_stat_character(ch, victim);
    else if ((item = get_item_vis(ch, name, &number)) != NULL)
      do_stat_item(ch, item);
    else
      send_to_char(ch, "Nothing around by that name.\r\n");
  }
}

/**
 * SHUTDOWN command
 *
 * This command lets a user shutdown or reboot the mud
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_shutdown)
{
  char arg[MAX_INPUT_LENGTH];

  if (CMD_IS("shutdow")) {
    send_to_char(ch, "If you want to shut something down, say so!\r\n");
    return;
  }
  one_argument(argument, arg);

  if (!*arg) {
    log("(GC) Shutdown by %s.", GET_NAME(ch));
    send_to_all("Shutting down.\r\n");
    circle_shutdown = 1;
  } else if (!str_cmp(arg, "reboot")) {
    log("(GC) Reboot by %s.", GET_NAME(ch));
    send_to_all("Rebooting.. come back in a minute or two.\r\n");
    touch(FASTBOOT_FILE);
    circle_shutdown = circle_reboot = 1;
  } else if (!str_cmp(arg, "die")) {
    log("(GC) Shutdown by %s.", GET_NAME(ch));
    send_to_all("Shutting down for maintenance.\r\n");
    touch(KILLSCRIPT_FILE);
    circle_shutdown = 1;
  } else if (!str_cmp(arg, "pause")) {
    log("(GC) Shutdown by %s.", GET_NAME(ch));
    send_to_all("Shutting down for maintenance.\r\n");
    touch(PAUSE_FILE);
    circle_shutdown = 1;
  } else
    send_to_char(ch, "Unknown shutdown option.\r\n");
}

/**
 * Verify that a character snooping or being snooped is still valid
 *
 * This short routine is to ensure that characters that happen
 * to be snooping (or snooped) and get advanced/demoted will
 * not be snooping/snooped someone of a higher/lower level (and
 * thus, not entitled to be snooping.
 *
 * @param ch Character to check
 * @return none
 */
void snoop_check(charData_t *ch)
{
  if (!ch || !ch->desc)
    return;
  if (ch->desc->snooping &&
     (GET_LEVEL(ch->desc->snooping->character) >= GET_LEVEL(ch))) {
    ch->desc->snooping->snoop_by = NULL;
    ch->desc->snooping = NULL;
  }

  if (ch->desc->snoop_by &&
     (GET_LEVEL(ch) >= GET_LEVEL(ch->desc->snoop_by->character))) {
    ch->desc->snoop_by->snooping = NULL;
    ch->desc->snoop_by = NULL;
  }
}

/**
 * Stop a character's snooping
 *
 * @param ch Character to stop snooping
 * @return none
 */
void stop_snooping(charData_t *ch)
{
  if (!ch->desc->snooping)
    send_to_char(ch, "You aren't snooping anyone.\r\n");
  else {
    send_to_char(ch, "You stop snooping.\r\n");
    ch->desc->snooping->snoop_by = NULL;
    ch->desc->snooping = NULL;
  }
}

/**
 * SNOOP command
 *
 * This command lets a user snoop another
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_snoop)
{
  char arg[MAX_INPUT_LENGTH];
  charData_t *victim, *tch;

  if (!ch->desc)
    return;

  one_argument(argument, arg);

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

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

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

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

/**
 * SWITCH command
 *
 * This command lets a user switch into the body of another character
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_switch)
{
  char arg[MAX_INPUT_LENGTH];
  charData_t *victim;

  one_argument(argument, arg);

  if (ch->desc->original)
    send_to_char(ch, "You're already switched.\r\n");
  else if (!*arg)
    send_to_char(ch, "Switch with who?\r\n");
  else if (!(victim = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD)))
    send_to_char(ch, "No such character.\r\n");
  else if (ch == victim)
    send_to_char(ch, "Hee hee... we are jolly funny today, eh?\r\n");
  else if (victim->desc)
    send_to_char(ch, "You can't do that, the body is already in use!\r\n");
  else if (GET_AUTH(ch) < AUTH_OWNER && !IS_NPC(victim))
    send_to_char(ch, "You aren't holy enough to use a mortal's body.\r\n");
  else if (GET_AUTH(ch) < AUTH_WIZARD && ROOM_FLAGGED(IN_ROOM(victim), ROOM_WIZROOM))
    send_to_char(ch, "You are not godly enough to use that room!\r\n");
  else if (GET_AUTH(ch) < AUTH_WIZARD && ROOM_FLAGGED(IN_ROOM(victim), ROOM_HOUSE)
		&& !House_can_enter(ch, IN_ROOM(victim)))
    send_to_char(ch, "That's private property -- no trespassing!\r\n");
  else {
    send_to_char(ch, "%s", OK);

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

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

/**
 * RETURN command
 *
 * This command lets a user return to their own character
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_return)
{
  if (ch->desc && ch->desc->original) {
    send_to_char(ch, "You return to your original body.\r\n");

    /*
     * 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;
  }
}

/**
 * LOAD command
 *
 * This command lets a user load an item or mobile by VNum
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_load)
{
  char buf[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];

  two_arguments(argument, buf, buf2);

  if (!*buf || !*buf2) {
    send_to_char(ch, "Usage: load { item | mob } <virtual>\r\n");
    return;
  }

  if (is_abbrev(buf, "mob")) {
    charData_t *mob = NULL, *mobProto = NULL;

    if ((mobProto = charData_findMobilePrototypeForChar(ch, buf2)) == NULL) {
      send_to_char(ch, "That mobile '%s' can't be found.\r\n", buf2);
      return;
    }
    mob = read_mobile(mobProto);
    char_toRoom(mob, IN_ROOM(ch));

    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, "item")) {
    itemData_t *item = NULL, *itemProto = NULL;

    if ((itemProto = itemData_findForChar(ch, buf2)) == NULL) {
      send_to_char(ch, "There is no item with that number.\r\n");
      return;
    }
    item = read_item(itemProto);
    if (load_into_inventory)
      itemData_toChar(item, ch);
    else
      itemData_toRoom(item, IN_ROOM(ch));
    act("$n makes a strange magical gesture.", TRUE, ch, 0, 0, TO_ROOM);
    act("$n has created $p!", FALSE, ch, item, 0, TO_ROOM);
    act("You create $p.", FALSE, ch, item, 0, TO_CHAR);
  } else
    send_to_char(ch, "That'll have to be either 'item' or 'mob'.\r\n");
}

/**
 * VSTAT command
 *
 * This command lets a user see detailed information on a target by vnum
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_vstat)
{
  char buf[MAX_INPUT_LENGTH], buf2[MAX_INPUT_LENGTH];

  two_arguments(argument, buf, buf2);

  if (!*buf || !*buf2) {
    send_to_char(ch, "Usage: vstat { item | mob | room} <virtual>\r\n");
    return;
  }

  if (is_abbrev(buf, "mob")) {
    charData_t *mob = NULL, *mobProto = NULL;

    if ((mobProto = charData_findMobilePrototypeForChar(ch, buf2)) == NULL) {
      send_to_char(ch, "There is no monster with that virtual name.\r\n");
      return;
    }
    mob = read_mobile(mobProto);
    char_toRoom(mob, NULL);
    do_stat_character(ch, mob);
    char_extract(mob);
  } else if (is_abbrev(buf, "item")) {
    itemData_t *item = NULL, *itemProto = NULL;

    if ((itemProto = itemData_findForChar(ch, buf2)) == NULL) {
      send_to_char(ch, "There is no item with that virtual name.\r\n");
      return;
    }
    item = read_item(itemProto);
    do_stat_item(ch, item);
    itemData_extract(item);
  } else if (is_abbrev(buf, "room")) {
    roomData_t *room = NULL, *origRoom = NULL;

    if ((room = roomData_findForChar(ch, buf2)) == NULL) {
      send_to_char(ch, "There is no room with that virtual name.\r\n");
      return;
    }
    
    origRoom = ch->room;
    char_fromRoom(ch);
    char_toRoom(ch, room);
    do_stat_room(ch);
    char_fromRoom(ch);
    char_toRoom(ch, origRoom);
  } else
    send_to_char(ch, "That'll have to be either 'item', 'mob', or 'room'.\r\n");
}

/**
 * PURGE command
 *
 * This command lets a user remove a target, or all mobiles and objects
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_purge)
{
  char buf[MAX_INPUT_LENGTH];
  charData_t *vict;
  itemData_t *obj;

  one_argument(argument, buf);

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

      if (!IS_NPC(vict)) {
	mudlog(BRF, MAX(AUTH_WIZARD, GET_INVIS_AUTH(ch)), TRUE, "(GC) %s has purged %s.", GET_NAME(ch), GET_NAME(vict));
	if (vict->desc) {
	  STATE(vict->desc) = CON_CLOSE;
	  vict->desc->character = NULL;
	  vict->desc = NULL;
	}
      }
      char_extract(vict);
    } else if ((obj = get_item_in_list_vis(ch, buf, NULL, ch->room->contents)) != NULL) {
      act("$n destroys $p.", FALSE, ch, obj, 0, TO_ROOM);
      itemData_extract(obj);
    } else {
      send_to_char(ch, "Nothing here by that name.\r\n");
      return;
    }

    send_to_char(ch, "%s", OK);
  } else {			/* no argument. clean out the room */
    int i;

    act("$n gestures... You are surrounded by scorching flames!",
	FALSE, ch, 0, 0, TO_ROOM);
    send_to_room(IN_ROOM(ch), "The world seems a little cleaner.\r\n");

    for (vict = ch->room->people; vict; vict = vict->next_in_room) {
      if (!IS_NPC(vict))
        continue;

      /* Dump inventory. */
      while (vict->carrying)
        itemData_extract(vict->carrying);

      /* Dump equipment. */
      for (i = 0; i < NUM_WEARS; i++)
        if (GET_EQ(vict, i))
          itemData_extract(GET_EQ(vict, i));

      /* Dump character. */
      char_extract(vict);
    }

    /* Clear the ground. */
    while (ch->room->contents)
      itemData_extract(ch->room->contents);
  }
}

/**
 * Text values for syslog levels
 */
const char *logtypes[] = {
  "off", "brief", "normal", "complete", "\n"
};

/**
 * SYSLOG command
 *
 * This command lets a user set their syslog value
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_syslog)
{
  char arg[MAX_INPUT_LENGTH];
  int tp;

  one_argument(argument, arg);
  if (!*arg) {
    send_to_char(ch, "Your syslog is currently %s.\r\n",
	logtypes[(PRF_FLAGGED(ch, PRF_LOG1) ? 1 : 0) + (PRF_FLAGGED(ch, PRF_LOG2) ? 2 : 0)]);
    return;
  }
  if (((tp = search_block(arg, logtypes, FALSE)) == -1)) {
    send_to_char(ch, "Usage: syslog { Off | Brief | Normal | Complete }\r\n");
    return;
  }
  REMOVE_BIT(PRF_FLAGS(ch), PRF_LOG1 | PRF_LOG2);
  SET_BIT(PRF_FLAGS(ch), (PRF_LOG1 * (tp & 1)) | (PRF_LOG2 * (tp & 2) >> 1));

  send_to_char(ch, "Your syslog is now %s.\r\n", logtypes[tp]);
}

/**
 * ADVANCE command
 *
 * This command lets a user raise or lower another character's level
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_advance)
{
  charData_t *victim;
  char name[MAX_INPUT_LENGTH], level[MAX_INPUT_LENGTH];
  int newlevel, oldlevel;

  two_arguments(argument, name, level);

  if (*name) {
    if (!(victim = get_char_vis(ch, name, NULL, FIND_CHAR_WORLD))) {
      send_to_char(ch, "That player is not here.\r\n");
      return;
    }
  } else {
    send_to_char(ch, "Advance who?\r\n");
    return;
  }
  if (IS_NPC(victim)) {
    send_to_char(ch, "NO!  Not on NPC's.\r\n");
    return;
  }
  if (!*level || (newlevel = atoi(level)) <= 0) {
    send_to_char(ch, "That's not a level!\r\n");
    return;
  }
  if (newlevel > NUM_LEVELS) {
    send_to_char(ch, "%d is the highest possible level.\r\n", NUM_LEVELS);
    return;
  }
  if (newlevel == GET_LEVEL(victim)) {
    send_to_char(ch, "They are already at that level.\r\n");
    return;
  }
  oldlevel = GET_LEVEL(victim);
  if (newlevel < GET_LEVEL(victim)) {
    do_start(victim);
    GET_LEVEL(victim) = newlevel;
    send_to_char(victim, "You are momentarily enveloped by darkness!\r\n"
                         "You feel somewhat diminished.\r\n");
  } 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(ch, "%s", OK);

  if (newlevel < oldlevel)
    mudlog(NRM, AUTH_OWNER, TRUE, "(GC) %s demoted %s from level %d to %d.",
		GET_NAME(ch), GET_NAME(victim), oldlevel, newlevel);
  else
    mudlog(NRM, AUTH_OWNER, TRUE, "(GC) %s has advanced %s to level %d (from %d)",
		GET_NAME(ch), GET_NAME(victim), newlevel, oldlevel);

  gain_exp_regardless(victim,
	 level_exp(GET_CLASS(victim), newlevel) - GET_EXP(victim));
  save_char(victim);
}

/**
 * The AUTHORIZE command.
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_authorize)
{
  charData_t *victim;
  char name[MAX_INPUT_LENGTH], auth[MAX_INPUT_LENGTH];
  int newauth, oldauth;

  two_arguments(argument, name, auth);

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

  if (GET_AUTH(ch) <= GET_AUTH(victim)) {
    send_to_char(ch, "Maybe that's not such a great idea.\r\n");
    return;
  }
  if (IS_NPC(victim)) {
    send_to_char(ch, "NO!  Not on NPC's.\r\n");
    return;
  }
  if (!*auth || (newauth = search_block(auth, auth_types, FALSE)) < 0) {
    send_to_char(ch, "That's not an authorization level!\r\n");
    return;
  }
  if (newauth > GET_AUTH(ch)) {
    send_to_char(ch, "Yeah, right.\r\n");
    return;
  }
  if (newauth == GET_AUTH(victim)) {
    send_to_char(ch, "They are already at that authorization level.\r\n");
    return;
  }
  oldauth = GET_AUTH(victim);
  if (newauth < GET_AUTH(victim)) {
    GET_AUTH(victim) = newauth;
    send_to_char(victim, "You are momentarily enveloped by darkness!\r\n"
                         "You feel somewhat diminished.\r\n");
  } else {
    GET_AUTH(victim) = newauth;
    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(ch, "%s", OK);

  if (newauth < oldauth) {
    mudlog(NRM, MAX(AUTH_WIZARD, GET_INVIS_AUTH(ch)), TRUE, "(GC) %s demoted %s from authorization level %s to %s.",
      GET_NAME(ch), GET_NAME(victim),
      auth_types[oldauth], auth_types[newauth]);
  } else {
    mudlog(NRM, MAX(AUTH_WIZARD, GET_INVIS_AUTH(ch)), TRUE, "(GC) %s has advanced %s to authorization level %s from %s.",
      GET_NAME(ch), GET_NAME(victim),
      auth_types[newauth], auth_types[oldauth]);
  }
  if (oldauth >= AUTH_WIZARD && newauth < AUTH_WIZARD) {
    /* If they are no longer an immortal, let's remove some of the
     * nice immortal only flags, shall we?
     */
    REMOVE_BIT(PRF_FLAGS(victim), PRF_LOG1 | PRF_LOG2);
    REMOVE_BIT(PRF_FLAGS(victim), PRF_NOHASSLE | PRF_HOLYLIGHT | PRF_ROOMFLAGS);
    run_autowiz();
  }
  if (oldauth < AUTH_WIZARD && newauth >= AUTH_WIZARD) {
    /* If they are now an immortal, let's set some of the nice immortal only
     * flags, shall we?
     */
    SET_BIT(PRF_FLAGS(victim), PRF_LOG1 | PRF_LOG2);
    SET_BIT(PRF_FLAGS(victim), PRF_NOHASSLE | PRF_HOLYLIGHT | PRF_ROOMFLAGS);
    run_autowiz();
  }
  save_char(victim);
}

/**
 * RESTORE command
 *
 * This command lets a user restore Hit Points, Mana Points, and Move Points
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_restore)
{
  char buf[MAX_INPUT_LENGTH];
  charData_t *vict;
  int i;

  one_argument(argument, buf);
  if (!*buf)
    send_to_char(ch, "Whom do you wish to restore?\r\n");
  else if (!(vict = get_char_vis(ch, buf, NULL, FIND_CHAR_WORLD)))
    send_to_char(ch, "%s", NOPERSON);
  else if (!IS_NPC(vict) && ch != vict && GET_LEVEL(vict) >= GET_LEVEL(ch))
    send_to_char(ch, "They don't need your help.\r\n");
  else {
    GET_HIT(vict) = GET_MAX_HIT(vict);
    GET_MANA(vict) = GET_MAX_MANA(vict);
    GET_MOVE(vict) = GET_MAX_MOVE(vict);

    if (!IS_NPC(vict) && GET_AUTH(ch) >= AUTH_OWNER) {
      if (GET_AUTH(vict) >= AUTH_WIZARD)
        for (i = 1; i <= MAX_SKILLS; i++)
          SET_SKILL(vict, i, 100);

      if (GET_AUTH(vict) >= AUTH_OWNER) {
	vict->real_abils.str_add = 100;
	vict->real_abils.intel = 25;
	vict->real_abils.wis = 25;
	vict->real_abils.dex = 25;
	vict->real_abils.str = 25;
	vict->real_abils.con = 25;
	vict->real_abils.cha = 25;
      }
    }
    update_pos(vict);
    effectData_total(vict);
    send_to_char(ch, "%s", OK);
    act("You have been fully healed by $N!", FALSE, vict, 0, ch, TO_CHAR);
  }
}

/**
 * Set a character as visible
 *
 * @sa perform_immort_invis
 * @sa AFF_INVISIBLE
 *
 * @param ch Character to set
 * @return none
 */
void perform_immort_vis(charData_t *ch)
{
  if (GET_INVIS_AUTH(ch) == AUTH_NONE && !AFF_FLAGGED(ch, AFF_HIDE | AFF_INVISIBLE)) {
    send_to_char(ch, "You are already fully visible.\r\n");
    return;
  }
  GET_INVIS_AUTH(ch) = AUTH_NONE;
  appear(ch);
  send_to_char(ch, "You are now fully visible.\r\n");
}

/**
 * Set a character as invisible
 *
 * @sa perform_immort_vis
 * @sa AFF_INVISIBLE
 *
 * @param ch Character to set
 * @param auth Invis authorization level to set
 * @return none
 */
void perform_immort_invis(charData_t *ch, int auth)
{
  char buf[MAX_STRING_LENGTH];
  charData_t *tch;

  for (tch = ch->room->people; tch; tch = tch->next_in_room) {
    if (tch == ch)
      continue;
    if (GET_AUTH(tch) >= GET_INVIS_AUTH(ch) && GET_AUTH(tch) < auth)
      act("You blink and suddenly realize that $n is gone.", FALSE, ch, 0,
	  tch, TO_VICT);
    if (GET_AUTH(tch) < GET_INVIS_AUTH(ch) && GET_AUTH(tch) >= auth)
      act("You suddenly realize that $n is standing beside you.", FALSE, ch, 0,
	  tch, TO_VICT);
  }
  /* Set the authorization level. */
  GET_INVIS_AUTH(ch) = auth;
  /* Print the name of the authorization level to the buffer. */
  sprinttype(auth, auth_types, buf, sizeof(buf));
  /* Send the message to the player. */
  send_to_char(ch, "Your invisibility level is %s.\r\n", buf);
}
  
/**
 * INVIS command
 *
 * This command lets a user become invisible/visible
 *
 * @sa perform_immort_invis
 * @sa perform_immort_vis
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_invis)
{
  char arg[MAX_INPUT_LENGTH];
  int auth;

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

  one_argument(argument, arg);
  if (!*arg) {
    if (GET_INVIS_AUTH(ch) > AUTH_NONE)
      perform_immort_vis(ch);
    else
      perform_immort_invis(ch, GET_LEVEL(ch));
  } else {
    /* Lookup the authorization level. */
    auth = search_block(arg, auth_types, FALSE);
    if (auth > GET_AUTH(ch)) {
      send_to_char(ch, "You can't go invisible above your own authorization level.\r\n");
    } else if (auth <= 0) {
      perform_immort_vis(ch);
    } else {
      perform_immort_invis(ch, auth);
    }
  }
}

/**
 * GECHO command
 *
 * This command lets a user send text to all connected players
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_gecho)
{
  descriptorData_t *pt;

  skip_spaces(&argument);
  delete_doubledollar(argument);

  if (!*argument)
    send_to_char(ch, "That must be a mistake...\r\n");
  else {
    for (pt = descriptor_list; pt; pt = pt->next)
      if (STATE(pt) == CON_PLAYING && pt->character && pt->character != ch)
	send_to_char(pt->character, "%s\r\n", argument);

    if (PRF_FLAGGED(ch, PRF_NOREPEAT))
      send_to_char(ch, "%s", OK);
    else
      send_to_char(ch, "%s\r\n", argument);
  }
}

/**
 * POOFIN and POOFOUT commands
 *
 * This command lets a user set their poofin and poofout messages
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_poofset)
{
  char **msg;

  if (CMD_IS("poofin"))       msg = &(POOFIN(ch));
  else if (CMD_IS("poofout")) msg = &(POOFOUT(ch));
  else                                        return;

  skip_spaces(&argument);

  if (*msg)
    free(*msg);

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

  send_to_char(ch, "%s", OK);
}

/**
 * DC command
 *
 * This command lets a user disconnect a socket connection
 *
 * @author Jeremy Elson
 * @author George Greer
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_dc)
{
  char arg[MAX_INPUT_LENGTH];
  descriptorData_t *d;
  int num_to_dc;

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

  if (!d) {
    send_to_char(ch, "No such connection.\r\n");
    return;
  }
  if (d->character && GET_LEVEL(d->character) >= GET_LEVEL(ch)) {
    if (!CAN_SEE(ch, d->character))
      send_to_char(ch, "No such connection.\r\n");
    else
      send_to_char(ch, "Umm.. maybe that's not such a good idea...\r\n");
    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(ch, "They're already being disconnected.\r\n");
  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;

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

/**
 * WIZLOCK command
 *
 * This command lets a user set the conditions that the mud will allow connections under.
 * Completely open, Closed to new players, Only level # and up.
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_wizlock)
{
  char arg[MAX_INPUT_LENGTH];
  int value;
  const char *when;

  one_argument(argument, arg);
  if (*arg) {
    value = atoi(arg);
    if (value < 0 || value > GET_LEVEL(ch)) {
      send_to_char(ch, "Invalid wizlock value.\r\n");
      return;
    }
    circle_restrict = value;
    when = "now";
  } else
    when = "currently";

  switch (circle_restrict) {
  case 0:
    send_to_char(ch, "The game is %s completely open.\r\n", when);
    break;
  case 1:
    send_to_char(ch, "The game is %s closed to new players.\r\n", when);
    break;
  default:
    send_to_char(ch, "Only level %d and above may enter the game %s.\r\n", circle_restrict, when);
    break;
  }
}

/**
 * DATE and UPTIME commands
 *
 * This command lets a user see the date on the server, or how long the mud has been running
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_date)
{
  char *tmstr;
  time_t mytime;
  int d, h, m;

  if (CMD_IS("date"))
    mytime = time(0);
  else
    mytime = boot_time;

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

  if (CMD_IS("date"))
    send_to_char(ch, "Current machine time: %s\r\n", tmstr);
  else {
    mytime = time(0) - boot_time;
    d = mytime / 86400;
    h = (mytime / 3600) % 24;
    m = (mytime / 60) % 60;

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

/**
 * LAST command
 *
 * This command lets a user see the last time a character was logged on.
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_last)
{
  char arg[MAX_INPUT_LENGTH];
  pfileElement_t chdata;

  one_argument(argument, arg);
  if (!*arg) {
    send_to_char(ch, "For whom do you wish to search?\r\n");
    return;
  }
  if (load_char(arg, &chdata) < 0) {
    send_to_char(ch, "There is no such player.\r\n");
    return;
  }
  if (chdata.auth > GET_AUTH(ch) && GET_AUTH(ch) < AUTH_OWNER) {
    send_to_char(ch, "You are not sufficiently godly for that!\r\n");
    return;
  }
  send_to_char(ch, "[%5ld] [%2d %s] [%s] %-12s : %-18s : %-20s\r\n",
	  chdata.char_specials_saved.idnum, chdata.level,
          auth_types[(int) chdata.auth], class_abbrevs[(int) chdata.chclass],
          chdata.name, chdata.host, ctime(&chdata.last_logon));
}

/**
 * FORCE command
 *
 * This command lets a user force a character or mobile to perform a command
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_force)
{
  descriptorData_t *i, *next_desc;
  charData_t *vict, *next_force;
  char arg[MAX_INPUT_LENGTH], to_force[MAX_INPUT_LENGTH], buf1[MAX_INPUT_LENGTH + 32];

  half_chop(argument, arg, to_force);

  snprintf(buf1, sizeof(buf1), "$n has forced you to '%s'.", to_force);

  if (!*arg || !*to_force)
    send_to_char(ch, "Whom do you wish to force do what?\r\n");
  else if (GET_AUTH(ch) < AUTH_WIZARD ||
          (str_cmp("all", arg) != 0 && str_cmp("room", arg) != 0)) {
    if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD)))
      send_to_char(ch, "%s", NOPERSON);
    else if (!IS_NPC(vict) && GET_AUTH(ch) <= GET_AUTH(vict))
      send_to_char(ch, "No, no, no!\r\n");
    else {
      send_to_char(ch, "%s", OK);
      act(buf1, TRUE, ch, NULL, vict, TO_VICT);
      mudlog(NRM, MAX(AUTH_WIZARD, GET_INVIS_AUTH(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(ch, "%s", OK);
    mudlog(NRM, MAX(AUTH_WIZARD, GET_INVIS_AUTH(ch)), TRUE, "(GC) %s forced room %s:%d to %s",
		GET_NAME(ch), IN_ROOM(ch)->zone->keyword, IN_ROOM(ch)->number, to_force);

    for (vict = ch->room->people; vict; vict = next_force) {
      next_force = vict->next_in_room;
      if (!IS_NPC(vict) && GET_LEVEL(vict) >= GET_LEVEL(ch))
	continue;
      act(buf1, TRUE, ch, NULL, vict, TO_VICT);
      command_interpreter(vict, to_force);
    }
  } else { /* force all */
    send_to_char(ch, "%s", OK);
    mudlog(NRM, MAX(AUTH_WIZARD, GET_INVIS_AUTH(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) || (!IS_NPC(vict) && GET_LEVEL(vict) >= GET_LEVEL(ch)))
	continue;
      act(buf1, TRUE, ch, NULL, vict, TO_VICT);
      command_interpreter(vict, to_force);
    }
  }
}

/**
 * WIZNET command
 *
 * This command lets a user communicate on the wizard's channel
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_wiznet)
{
  char buf1[MAX_INPUT_LENGTH + MAX_NAME_LENGTH + 32],
	buf2[MAX_INPUT_LENGTH + MAX_NAME_LENGTH + 32];
  descriptorData_t *d;
  char emote = FALSE;
  char any = FALSE;
  int auth = AUTH_WIZARD;

  skip_spaces(&argument);
  delete_doubledollar(argument);

  if (!*argument) {
    send_to_char(ch, "Usage: wiznet <text> | #<auth-level> <text> | *<emotetext> |\r\n        wiznet @<level> *<emotetext> | wiz @\r\n");
    return;
  }
  switch (*argument) {
  case '*':
    emote = TRUE;
  case '#':
    one_argument(argument + 1, buf1);
    /* Look up the authorization level name. */
    auth = search_block(buf1, auth_types, TRUE);
    /* Check for legal authorization levels. */
    if (auth != -1) {
      if (auth > GET_AUTH(ch)) {
        send_to_char(ch, "You can't wizline above your own auth level.\r\n");
        return;
      }
    } else if (emote)
      argument++;
    break;

  case '@':
    send_to_char(ch, "God channel status:\r\n");
    for (any = 0, d = descriptor_list; d; d = d->next) {
      if (STATE(d) != CON_PLAYING || GET_AUTH(d->character) < AUTH_WIZARD)
        continue;
      if (!CAN_SEE(ch, d->character))
        continue;

      send_to_char(ch, "  %-*s%s%s%s\r\n", MAX_NAME_LENGTH, GET_NAME(d->character),
		PLR_FLAGGED(d->character, PLR_WRITING) ? " (Writing)" : "",
		PLR_FLAGGED(d->character, PLR_MAILING) ? " (Writing mail)" : "",
		PRF_FLAGGED(d->character, PRF_NOWIZ) ? " (Offline)" : "");
    }
    return;

  case '\\':
    ++argument;
    break;
  default:
    break;
  }
  if (PRF_FLAGGED(ch, PRF_NOWIZ)) {
    send_to_char(ch, "You are offline!\r\n");
    return;
  }
  skip_spaces(&argument);

  if (!*argument) {
    send_to_char(ch, "Don't bother the gods like that!\r\n");
    return;
  }
  if (auth > AUTH_WIZARD) {
    snprintf(buf1, sizeof(buf1), "%s: <%s> %s%s\r\n", GET_NAME(ch), auth_types[auth], emote ? "<--- " : "", argument);
    snprintf(buf2, sizeof(buf1), "Someone: <%s> %s%s\r\n", auth_types[auth], emote ? "<--- " : "", argument);
  } else {
    snprintf(buf1, sizeof(buf1), "%s: %s%s\r\n", GET_NAME(ch), emote ? "<--- " : "", argument);
    snprintf(buf2, sizeof(buf1), "Someone: %s%s\r\n", emote ? "<--- " : "", argument);
  }

  for (d = descriptor_list; d; d = d->next) {
    if (STATE(d) == CON_PLAYING && GET_AUTH(d->character) >= auth &&
       (!PRF_FLAGGED(d->character, PRF_NOWIZ)) &&
       (!PLR_FLAGGED(d->character, PLR_WRITING | PLR_MAILING))
	&& (d != ch->desc || !(PRF_FLAGGED(d->character, PRF_NOREPEAT)))) {
      send_to_char(d->character, "%s", CCCYN(d->character, C_NRM));
      if (CAN_SEE(d->character, ch))
	send_to_char(d->character, "%s", buf1);
      else
	send_to_char(d->character, "%s", buf2);
      send_to_char(d->character, "%s", CCNRM(d->character, C_NRM));
    }
  }

  if (PRF_FLAGGED(ch, PRF_NOREPEAT))
    send_to_char(ch, "%s", OK);
}

/** 
 * ZRESET command
 * 
 * This command lets a user reset a zone, forcing it to run through it's zone commands.
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */ 
ACMD(do_zreset) {
  char arg[MAX_INPUT_LENGTH];

  one_argument(argument, arg);
  if (strcasecmp(arg, "all") == 0 || *arg == '*') {
    /* Reset all zones */
    /* Declare a hashMapIterator for the zones hashMap */
    hashMapIterator_t *iter = hashMapIterator_create(zones);
    if (iter == NULL) {
      log("zreset:: hashMapIterator 'iter' is NULL.");
    }

    /* Loop over all the zones in the hashMap */
    while (iter && hashMapIterator_getValue(iter)) {
      zoneData_t *zone = (zoneData_t *)hashMapIterator_getValue(iter);
      if (zone) {
        log("Call to reset %s : %s", zone->keyword, zone->name);
        zoneData_reset(zone);
      }
      zone = NULL;
      /* Advance the iterator */
      hashMapIterator_next(iter);
    }
    hashMapIterator_free(iter);

    /* Log/display complete */
    send_to_char(ch, "Reset world.\r\n");
    mudlog(NRM, MAX(AUTH_OWNER, GET_INVIS_AUTH(ch)), TRUE, "(GC) %s reset entire world.", GET_NAME(ch));
  } else {
    /* Declare a zone pointer, and see we have a zone named this */
    zoneData_t *zone = zoneData_find(arg);

    if (zone) {
      /* Found a zone, reset it */
      zoneData_reset(zone);

      /* Log/display complete */
      send_to_char(ch, "Reset zone '%s'.\r\n", zone->name);
      mudlog(NRM, MAX(AUTH_WIZARD, GET_INVIS_AUTH(ch)), TRUE, "(GC) %s reset zone '%s'", GET_NAME(ch), zone->name);
    } else {
      /* Not found, reset zone ch is currently in */
      /** @todo Add in default resetting for zone ch currently in */
      send_to_char(ch, "User input '%s'\r\n", arg);
      send_to_char(ch, "This part not implemented... Damn it, Drathus!\r\n");
    }
  }
}

/**
 * REROLL, FREEZE, THAW, PARDON, NOTITLE, SQUELCH, UNAFFECT commands
 *
 * General fn for wizcommands of the sort: cmd <player>
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_wizutil)
{
  char arg[MAX_INPUT_LENGTH];
  charData_t *vict;
  long result;

  one_argument(argument, arg);

  if (!*arg)
    send_to_char(ch, "Yes, but for whom?!?\r\n");
  else if (!(vict = get_char_vis(ch, arg, NULL, FIND_CHAR_WORLD)))
    send_to_char(ch, "There is no such player.\r\n");
  else if (IS_NPC(vict))
    send_to_char(ch, "You can't do that to a mob!\r\n");
  else if (GET_LEVEL(vict) > GET_LEVEL(ch))
    send_to_char(ch, "Hmmm...you'd better not.\r\n");
  else {
    if (CMD_IS("reroll")) {
      send_to_char(ch, "Rerolled...\r\n");
      roll_real_abils(vict);
      log("(GC) %s has rerolled %s.", GET_NAME(ch), GET_NAME(vict));
      send_to_char(ch, "New stats: Str %d/%d, Int %d, Wis %d, Dex %d, Con %d, Cha %d\r\n",
	      GET_STR(vict), GET_ADD(vict), GET_INT(vict), GET_WIS(vict),
	      GET_DEX(vict), GET_CON(vict), GET_CHA(vict));
    } else if (CMD_IS("pardon")) {
      if (!PLR_FLAGGED(vict, PLR_THIEF | PLR_KILLER)) {
	send_to_char(ch, "Your victim is not flagged.\r\n");
	return;
      }
      REMOVE_BIT(PLR_FLAGS(vict), PLR_THIEF | PLR_KILLER);
      send_to_char(ch, "Pardoned.\r\n");
      send_to_char(vict, "You have been pardoned by the Gods!\r\n");
      mudlog(BRF, MAX(AUTH_WIZARD, GET_INVIS_AUTH(ch)), TRUE, "(GC) %s pardoned by %s", GET_NAME(vict), GET_NAME(ch));
    } else if (CMD_IS("notitle")) {
      result = PLR_TOG_CHK(vict, PLR_NOTITLE);
      mudlog(NRM, MAX(AUTH_WIZARD, GET_INVIS_AUTH(ch)), TRUE, "(GC) Notitle %s for %s by %s.",
		ONOFF(result), GET_NAME(vict), GET_NAME(ch));
      send_to_char(ch, "(GC) Notitle %s for %s by %s.\r\n", ONOFF(result), GET_NAME(vict), GET_NAME(ch));
    } else if (CMD_IS("mute")) {
      result = PLR_TOG_CHK(vict, PLR_NOSHOUT);
      mudlog(BRF, MAX(AUTH_WIZARD, GET_INVIS_AUTH(ch)), TRUE, "(GC) Squelch %s for %s by %s.",
		ONOFF(result), GET_NAME(vict), GET_NAME(ch));
      send_to_char(ch, "(GC) Squelch %s for %s by %s.\r\n", ONOFF(result), GET_NAME(vict), GET_NAME(ch));
    } else if (CMD_IS("freeze")) {
      if (ch == vict) {
	send_to_char(ch, "Oh, yeah, THAT'S real smart...\r\n");
	return;
      }
      if (PLR_FLAGGED(vict, PLR_FROZEN)) {
	send_to_char(ch, "Your victim is already pretty cold.\r\n");
	return;
      }
      SET_BIT(PLR_FLAGS(vict), PLR_FROZEN);
      GET_FREEZE_AUTH(vict) = GET_AUTH(ch);
      send_to_char(vict, "A bitter wind suddenly rises and drains every erg of heat from your body!\r\nYou feel frozen!\r\n");
      send_to_char(ch, "Frozen.\r\n");
      act("A sudden cold wind conjured from nowhere freezes $n!", FALSE, vict, 0, 0, TO_ROOM);
      mudlog(BRF, MAX(AUTH_WIZARD, GET_INVIS_AUTH(ch)), TRUE, "(GC) %s frozen by %s.", GET_NAME(vict), GET_NAME(ch));
    } else if (CMD_IS("thaw")) {
      if (!PLR_FLAGGED(vict, PLR_FROZEN)) {
	send_to_char(ch, "Sorry, your victim is not morbidly encased in ice at the moment.\r\n");
	return;
      }
      if (GET_FREEZE_AUTH(vict) > GET_AUTH(ch)) {
        char buf[MAX_STRING_LENGTH];
        /* Print the authorization level to the buffer. */
        sprinttype(GET_FREEZE_AUTH(vict), auth_types, buf, sizeof(buf));
	send_to_char(ch, "Sorry, a %s froze %s... you can't unfreeze %s.\r\n",
		buf, GET_NAME(vict), HMHR(vict));
	return;
      }
      mudlog(BRF, MAX(AUTH_WIZARD, GET_INVIS_AUTH(ch)), TRUE, "(GC) %s un-frozen by %s.", GET_NAME(vict), GET_NAME(ch));
      REMOVE_BIT(PLR_FLAGS(vict), PLR_FROZEN);
      send_to_char(vict, "A fireball suddenly explodes in front of you, melting the ice!\r\nYou feel thawed.\r\n");
      send_to_char(ch, "Thawed.\r\n");
      act("A sudden fireball conjured from nowhere thaws $n!", FALSE, vict, 0, 0, TO_ROOM);
    } else if (CMD_IS("unaffect")) {
      if (vict->affected) {
	while (vict->affected)
	  effectData_remove(vict, vict->affected);
	send_to_char(vict, "There is a brief flash of light!\r\nYou feel slightly different.\r\n");
	send_to_char(ch, "All spells removed.\r\n");
      } else {
	send_to_char(ch, "Your victim does not have any affections!\r\n");
	return;
      }
    } else {
      log("SYSERR: Unknown command '%s' passed to do_wizutil (%s)", CMD_NAME, __FILE__);
    }
    save_char(vict);
  }
}

/**
 * Add a zone's information to a buffer
 *
 * single zone printing function used by "SHOW ZONE" so it's not repeated in
 * the code multiple times.
 * 
 * Originally coded by Jeremy Elson, 4/6/93.
 *
 * Recoded on 12/2/06 for the new CircleMUD^2 world system
 *
 * @param buf Buffer to add zone information to
 * @param left Size remaining in buffer
 * @param zone Zone to add
 */
size_t print_zone_to_buf(char *buf, size_t left, charData_t *ch, zoneData_t *zone) {

  return snprintf(buf + strlen(buf), left, " %20s %s:%s %-35s %s-%s Age%s:%s %3d%s/%s%3d\r\n",
                  zone->keyword,
                  CCCYN(ch, C_NRM),
                  CCNRM(ch, C_NRM),
                  zone->name,
                  CCCYN(ch, C_NRM),
                  CCNRM(ch, C_NRM),
                  CCCYN(ch, C_NRM),
                  CCNRM(ch, C_NRM),
                  zone->age,
                  CCCYN(ch, C_NRM),
                  CCNRM(ch, C_NRM),
                  zone->lifespan
                 );
}

/**
 * SHOW command
 *
 * This command lets a user see listings of various in game data.
 * zones, players, rent, stats, death traps, godrooms, shops,
 * houses, and snooping
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_show)
{
  pfileElement_t vbuf;
  int i, j, numPlayers, numMobs, numItems, l, con;
  byte self = FALSE;
  charData_t *vict;
  itemData_t *obj;
  descriptorData_t *d;
  char field[MAX_INPUT_LENGTH], value[MAX_INPUT_LENGTH],
	arg[MAX_INPUT_LENGTH], buf[MAX_STRING_LENGTH];

  struct show_struct {
    const char *cmd;
    const byte auth;
  } fields[] = {
    { "nothing",	0  },				/* 0 */
    { "zones",		AUTH_WIZARD },			/* 1 */
    { "player",		AUTH_WIZARD },
    { "rent",		AUTH_WIZARD },
    { "stats",		AUTH_WIZARD },
    { "death",		AUTH_WIZARD },			/* 5 */
    { "wizrooms",	AUTH_WIZARD },
    { "shops",		AUTH_WIZARD },
    { "houses",		AUTH_WIZARD },
    { "snoop",		AUTH_OWNER },			/* 9 */
    { "\n", 0 }
  };

  skip_spaces(&argument);

  if (!*argument) {
    send_to_char(ch, "Show options:\r\n");
    for (j = 0, i = 1; strcmp(fields[i].cmd, "\n") != 0; i++)
      if (fields[i].auth <= GET_AUTH(ch))
	send_to_char(ch, "%-15s%s", fields[i].cmd, (!(++j % 5) ? "\r\n" : ""));
    send_to_char(ch, "\r\n");
    return;
  }

  strcpy(arg, two_arguments(argument, field, value));	/* strcpy: OK (argument <= MAX_INPUT_LENGTH == arg) */

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

  if (GET_AUTH(ch) < fields[l].auth) {
    send_to_char(ch, "You are not godly enough for that!\r\n");
    return;
  }
  if (!strcmp(value, "."))
    self = TRUE;
  buf[0] = '\0';

  switch (l) {
  /* show zone */
  case 1:
    if (self) {
      print_zone_to_buf(buf, sizeof(buf), ch, ch->room->zone);
    } else if (value && *value) {
      zoneData_t *zone = zoneData_find(value);
      if (zone) {
        print_zone_to_buf(buf, sizeof(buf), ch, zone);
      } else {
        send_to_char(ch, "Unable to find a zone '%s'.\r\n", value);
        return;
      }
    } else {
      hashMapIterator_t *iter = hashMapIterator_create(zones);
      while (iter && hashMapIterator_getValue(iter)) {
        zoneData_t *zone = (zoneData_t *)hashMapIterator_getValue(iter);
        if (zone) {
          print_zone_to_buf(buf, sizeof(buf), ch, zone);
        }
        zone = NULL;
        hashMapIterator_next(iter);
      }
    }
    page_string(ch->desc, buf, TRUE);
    break;
  /* show player */
  case 2:
    if (!*value) {
      send_to_char(ch, "A name would help.\r\n");
      return;
    }

    if (load_char(value, &vbuf) < 0) {
      send_to_char(ch, "There is no such player.\r\n");
      return;
    }

    send_to_char(ch, "Player: %-12s (%s) [%2d %s]\r\n", vbuf.name,
	genders[(int) vbuf.sex], vbuf.level, class_abbrevs[(int) vbuf.chclass]);
    send_to_char(ch, "Au: %-8d  Bal: %-8d  Exp: %-8d  Align: %-5d  Lessons: %-3d\r\n",
	vbuf.points.gold, vbuf.points.bank_gold, vbuf.points.exp,
	vbuf.char_specials_saved.alignment, vbuf.player_specials_saved.spells_to_learn);
    /* ctime() uses static buffer: do not combine. */
    send_to_char(ch, "Started: %-20.16s  ", ctime(&vbuf.birth));
    send_to_char(ch, "Last: %-20.16s  Played: %3dh %2dm\r\n", ctime(&vbuf.last_logon), vbuf.played / 3600, vbuf.played / 60 % 60);
    break;

  /* show rent */
  case 3:
    if (!*value) {
      send_to_char(ch, "A name would help.\r\n");
      return;
    }
    Crash_listrent(ch, value);
    break;

  /* show stats */
  case 4:
    numPlayers = 0;
    numMobs = 0;
    numItems = 0;
    con = 0;
    for (vict = character_list; vict; vict = vict->next) {
      if (IS_NPC(vict))
	numMobs++;
      else if (CAN_SEE(ch, vict)) {
	numPlayers++;
	if (vict->desc)
	  con++;
      }
    }
    for (obj = object_list; obj; obj = obj->next)
      numItems++;
    send_to_char(ch,
	"Current stats:\r\n"
        " %s%7d%s player%s registered, %s%d%s in game and %s%d%s connected\r\n"
        " %s%7d%s zones containing  %s%7d%s rooms\r\n"
        "                           %s%7d%s item prototypes, %s%d%s in game.\r\n"
        "                           %s%7d%s mobile prototypes, %s%d%s in game.\r\n"
        "\r\n"
	" %s%7u%s strings           %s%7u%s virtual strings\r\n"
	" %s%7u%s string bytes      %s%7u%s virtual string bytes\r\n"
	" %s%7u%s max strings       %s%7u%s max virtual strings\r\n"
	" %s%7u%s max string bytes  %s%7u%s max virtual string bytes\r\n"
        "\r\n"
	" %s%7d%s large bufs, %s%d%s buf switches, %s%d%s overflows\r\n",
	CCCYN(ch, C_NRM), top_of_p_table + 1, CCNRM(ch, C_NRM), (top_of_p_table + 1 == 1 ? "" : "s"),
        CCCYN(ch, C_NRM), numPlayers, CCNRM(ch, C_NRM), 
        CCCYN(ch, C_NRM), con, CCNRM(ch, C_NRM),
        CCCYN(ch, C_NRM), numPrototypes(ZONES), CCNRM(ch, C_NRM), 
        CCCYN(ch, C_NRM), numPrototypes(ROOMS), CCNRM(ch, C_NRM),
        CCCYN(ch, C_NRM), numPrototypes(ITEMPS), CCNRM(ch, C_NRM),
	CCCYN(ch, C_NRM), numItems, CCNRM(ch, C_NRM),
        CCCYN(ch, C_NRM), numPrototypes(MOBILES), CCNRM(ch, C_NRM),
	CCCYN(ch, C_NRM), numMobs, CCNRM(ch, C_NRM), 
	CCCYN(ch, C_NRM), g_realStringCount, CCNRM(ch, C_NRM),
        CCCYN(ch, C_NRM), g_virtualStringCount, CCNRM(ch, C_NRM),
	CCCYN(ch, C_NRM), g_realStringBytes, CCNRM(ch, C_NRM),
        CCCYN(ch, C_NRM), g_virtualStringBytes, CCNRM(ch, C_NRM),
	CCCYN(ch, C_NRM), g_maxRealStringCount, CCNRM(ch, C_NRM),
        CCCYN(ch, C_NRM), g_maxVirtualStringCount, CCNRM(ch, C_NRM),
	CCCYN(ch, C_NRM), g_maxRealStringBytes, CCNRM(ch, C_NRM),
        CCCYN(ch, C_NRM), g_maxVirtualStringBytes, CCNRM(ch, C_NRM),
	CCCYN(ch, C_NRM), buf_largecount, CCNRM(ch, C_NRM),
	CCCYN(ch, C_NRM), buf_switches, CCNRM(ch, C_NRM),
        CCCYN(ch, C_NRM), buf_overflows, CCNRM(ch, C_NRM)
	);
    break;

  /* show death */
  case 5:
    world_listToPlayer(ch, DEATHTRAPS);
    break;

  /* show wizrooms */
  case 6:
    world_listToPlayer(ch, WIZROOMS);
    break;

  /* show shops */
  case 7:
    world_listToPlayer(ch, SHOPS);
    break;

  /* show houses */
  case 8:
    hcontrol_list_houses(ch);
    break;

  /* show snoop */
  case 9:
    i = 0;
    send_to_char(ch, "People currently snooping:\r\n--------------------------\r\n");
    for (d = descriptor_list; d; d = d->next) {
      if (d->snooping == NULL || d->character == NULL)
	continue;
      if (STATE(d) != CON_PLAYING || GET_LEVEL(ch) < GET_LEVEL(d->character))
	continue;
      if (!CAN_SEE(ch, d->character) || IN_ROOM(d->character) == NULL)
	continue;
      i++;
      send_to_char(ch, "%-10s - snooped by %s.\r\n", GET_NAME(d->snooping->character), GET_NAME(d->character));
    }
    if (i == 0)
      send_to_char(ch, "No one is currently snooping.\r\n");
    break;

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


/***************** The do_set function ***********************************/
#define PC                           1  /**< Target is PC                    */
#define NPC                          2  /**< Target is NPC                   */
#define BOTH                         3  /**< Target is PC or NPC             */

#define MISC                         0  /**< Value is text                   */
#define BINARY                       1  /**< Value is 'on' or 'off'          */
#define NUMBER                       2  /**< Value is numeric                */

#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))))


/**
 * The set options available
 * @{
 */
struct set_struct {
  const char *cmd;                     /**< Text value of set field         */
  const char  auth;                    /**< Auth required for set field     */
  const char  pcnpc;                   /**< PC/NPC target type              */
  const char  type;                    /**< Value type                      */
} set_fields[] = {
  { "brief",		AUTH_WIZARD, 	PC, 	BINARY },  /* 0 */
  { "invstart", 	AUTH_WIZARD, 	PC, 	BINARY },  /* 1 */
  { "title",		AUTH_WIZARD, 	PC, 	MISC },
  { "nosummon", 	AUTH_OWNER, 	PC, 	BINARY },
  { "maxhit",		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "maxmana", 		AUTH_OWNER, 	BOTH, 	NUMBER },  /* 5 */
  { "maxmove", 		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "hit", 		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "mana",		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "move",		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "align",		AUTH_WIZARD, 	BOTH, 	NUMBER },  /* 10 */
  { "str",		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "stradd",		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "int", 		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "wis", 		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "dex", 		AUTH_OWNER, 	BOTH, 	NUMBER },  /* 15 */
  { "con", 		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "cha",		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "ac", 		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "gold",		AUTH_WIZARD, 	BOTH, 	NUMBER },
  { "bank",		AUTH_WIZARD, 	PC, 	NUMBER },  /* 20 */
  { "exp", 		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "hitroll",	 	AUTH_OWNER, 	BOTH, 	NUMBER },
  { "damroll", 		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "invis",		AUTH_OWNER, 	PC, 	NUMBER },
  { "nohassle", 	AUTH_OWNER, 	PC, 	BINARY },  /* 25 */
  { "frozen",		AUTH_FREEZE, 	PC, 	BINARY },
  { "practices", 	AUTH_OWNER, 	PC, 	NUMBER },
  { "lessons", 		AUTH_OWNER, 	PC, 	NUMBER },
  { "drunk",		AUTH_OWNER, 	BOTH, 	MISC },
  { "hunger",		AUTH_OWNER, 	BOTH, 	MISC },    /* 30 */
  { "thirst",		AUTH_OWNER, 	BOTH, 	MISC },
  { "killer",		AUTH_WIZARD, 	PC, 	BINARY },
  { "thief",		AUTH_WIZARD, 	PC, 	BINARY },
  { "level",		AUTH_OWNER, 	BOTH, 	NUMBER },
  { "room",		AUTH_OWNER, 	BOTH, 	NUMBER },  /* 35 */
  { "roomflag", 	AUTH_OWNER, 	PC, 	BINARY },
  { "siteok",		AUTH_OWNER, 	PC, 	BINARY },
  { "deleted", 		AUTH_OWNER, 	PC, 	BINARY },
  { "class",		AUTH_OWNER, 	BOTH, 	MISC },
  { "nowizlist", 	AUTH_WIZARD, 	PC, 	BINARY },  /* 40 */
  { "quest",		AUTH_WIZARD, 	PC, 	BINARY },
  { "loadroom", 	AUTH_OWNER, 	PC, 	MISC },
  { "color",		AUTH_WIZARD, 	PC, 	BINARY },
  { "idnum",		AUTH_OWNER, 	PC, 	NUMBER },
  { "passwd",		AUTH_OWNER, 	PC, 	MISC },    /* 45 */
  { "nodelete", 	AUTH_WIZARD, 	PC, 	BINARY },
  { "sex", 		AUTH_OWNER, 	BOTH, 	MISC },
  { "age",		AUTH_OWNER,	BOTH,	NUMBER },
  { "height",		AUTH_WIZARD,	BOTH,	NUMBER },
  { "weight",		AUTH_WIZARD,	BOTH,	NUMBER },  /* 50 */
  { "\n", 0, BOTH, MISC }
};
/** @} */

/**
 * Perform a set option
 *
 * This is the raw function that do_set calls
 *
 * @todo Convert to bool
 *
 * @param ch Character performing the SET
 * @param vict Character being SET
 * @param mode Numeric value of the SET option in the set_fields[] array
 * @param val_arg Argument specified by Character performing the SET
 * @return 1 or 0
 */
int perform_set(charData_t *ch, charData_t *vict, int mode, char *val_arg)
{
  int i, on = 0, off = 0, value = 0;
  roomData_t *room = NULL;

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

  /* Make sure the PC/NPC is correct */
  if (IS_NPC(vict) && !(set_fields[mode].pcnpc & NPC)) {
    send_to_char(ch, "You can't do that to a beast!\r\n");
    return (0);
  } else if (!IS_NPC(vict) && !(set_fields[mode].pcnpc & PC)) {
    send_to_char(ch, "That can only be done to a beast!\r\n");
    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(ch, "Value must be 'on' or 'off'.\r\n");
      return (0);
    }
    send_to_char(ch, "%s %s for %s.\r\n", set_fields[mode].cmd, ONOFF(on), GET_NAME(vict));
  } else if (set_fields[mode].type == NUMBER) {
    value = atoi(val_arg);
    send_to_char(ch, "%s's %s set to %d.\r\n", GET_NAME(vict), set_fields[mode].cmd, value);
  } else
    send_to_char(ch, "%s", OK);

  switch (mode) {
  case 0:
    SET_OR_REMOVE(PRF_FLAGS(vict), PRF_BRIEF);
    break;
  case 1:
    SET_OR_REMOVE(PLR_FLAGS(vict), PLR_INVSTART);
    break;
  case 2:
    set_title(vict, val_arg);
    send_to_char(ch, "%s's title is now: %s\r\n", GET_NAME(vict), GET_TITLE(vict));
    break;
  case 3:
    SET_OR_REMOVE(PRF_FLAGS(vict), PRF_SUMMONABLE);
    send_to_char(ch, "Nosummon %s for %s.\r\n", ONOFF(!on), GET_NAME(vict));
    break;
  case 4:
    vict->points.max_hit = RANGE(1, 5000);
    effectData_total(vict);
    break;
  case 5:
    vict->points.max_mana = RANGE(1, 5000);
    effectData_total(vict);
    break;
  case 6:
    vict->points.max_move = RANGE(1, 5000);
    effectData_total(vict);
    break;
  case 7:
    vict->points.hit = RANGE(-9, vict->points.max_hit);
    effectData_total(vict);
    break;
  case 8:
    vict->points.mana = RANGE(0, vict->points.max_mana);
    effectData_total(vict);
    break;
  case 9:
    vict->points.move = RANGE(0, vict->points.max_move);
    effectData_total(vict);
    break;
  case 10:
    GET_ALIGNMENT(vict) = RANGE(-1000, 1000);
    effectData_total(vict);
    break;
  case 11:
    if (IS_NPC(vict) || GET_AUTH(vict) >= AUTH_OWNER)
      RANGE(3, 25);
    else
      RANGE(3, 18);
    vict->real_abils.str = value;
    vict->real_abils.str_add = 0;
    effectData_total(vict);
    break;
  case 12:
    vict->real_abils.str_add = RANGE(0, 100);
    if (value > 0)
      vict->real_abils.str = 18;
    effectData_total(vict);
    break;
  case 13:
    if (IS_NPC(vict) || GET_AUTH(vict) >= AUTH_OWNER)
      RANGE(3, 25);
    else
      RANGE(3, 18);
    vict->real_abils.intel = value;
    effectData_total(vict);
    break;
  case 14:
    if (IS_NPC(vict) || GET_AUTH(vict) >= AUTH_OWNER)
      RANGE(3, 25);
    else
      RANGE(3, 18);
    vict->real_abils.wis = value;
    effectData_total(vict);
    break;
  case 15:
    if (IS_NPC(vict) || GET_AUTH(vict) >= AUTH_OWNER)
      RANGE(3, 25);
    else
      RANGE(3, 18);
    vict->real_abils.dex = value;
    effectData_total(vict);
    break;
  case 16:
    if (IS_NPC(vict) || GET_AUTH(vict) >= AUTH_OWNER)
      RANGE(3, 25);
    else
      RANGE(3, 18);
    vict->real_abils.con = value;
    effectData_total(vict);
    break;
  case 17:
    if (IS_NPC(vict) || GET_AUTH(vict) >= AUTH_OWNER)
      RANGE(3, 25);
    else
      RANGE(3, 18);
    vict->real_abils.cha = value;
    effectData_total(vict);
    break;
  case 18:
    vict->points.armor = RANGE(-100, 100);
    effectData_total(vict);
    break;
  case 19:
    GET_GOLD(vict) = RANGE(0, 100000000);
    break;
  case 20:
    GET_BANK_GOLD(vict) = RANGE(0, 100000000);
    break;
  case 21:
    vict->points.exp = RANGE(0, 50000000);
    break;
  case 22:
    vict->points.hitroll = RANGE(-20, 20);
    effectData_total(vict);
    break;
  case 23:
    vict->points.damroll = RANGE(-20, 20);
    effectData_total(vict);
    break;
  case 24:
    if (GET_AUTH(ch) < AUTH_OWNER && ch != vict) {
      send_to_char(ch, "You aren't godly enough for that!\r\n");
      return (0);
    }
    GET_INVIS_AUTH(vict) = RANGE(0, GET_LEVEL(vict));
    break;
  case 25:
    if (GET_AUTH(ch) < AUTH_OWNER && ch != vict) {
      send_to_char(ch, "You aren't godly enough for that!\r\n");
      return (0);
    }
    SET_OR_REMOVE(PRF_FLAGS(vict), PRF_NOHASSLE);
    break;
  case 26:
    if (ch == vict && on) {
      send_to_char(ch, "Better not -- could be a long winter!\r\n");
      return (0);
    }
    SET_OR_REMOVE(PLR_FLAGS(vict), PLR_FROZEN);
    break;
  case 27:
  case 28:
    GET_PRACTICES(vict) = RANGE(0, 100);
    break;
  case 29:
  case 30:
  case 31:
    if (!str_cmp(val_arg, "off")) {
      GET_COND(vict, (mode - 29)) = -1; /* warning: magic number here */
      send_to_char(ch, "%s's %s now off.\r\n", GET_NAME(vict), set_fields[mode].cmd);
    } else if (isInteger(val_arg, FALSE)) {
      value = atoi(val_arg);
      RANGE(0, 24);
      GET_COND(vict, (mode - 29)) = value; /* and here too */
      send_to_char(ch, "%s's %s set to %d.\r\n", GET_NAME(vict), set_fields[mode].cmd, value);
    } else {
      send_to_char(ch, "Must be 'off' or a value from 0 to 24.\r\n");
      return (0);
    }
    break;
  case 32:
    SET_OR_REMOVE(PLR_FLAGS(vict), PLR_KILLER);
    break;
  case 33:
    SET_OR_REMOVE(PLR_FLAGS(vict), PLR_THIEF);
    break;
  case 34:
    if (value < 1 || value > NUM_LEVELS) {
      send_to_char(ch, "You can't do that.\r\n");
      return (0);
    }
    RANGE(1, NUM_LEVELS);
    vict->player.level = value;
    break;
  case 35:
    if ((room = roomData_find(val_arg)) == NULL) {
      send_to_char(ch, "Unable to find that room.\r\n");
      return (0);
    }
    if (IN_ROOM(vict) != NULL)	/* Another Eric Green special. */
      char_fromRoom(vict);
    char_toRoom(vict, room);
    break;
  case 36:
    SET_OR_REMOVE(PRF_FLAGS(vict), PRF_ROOMFLAGS);
    break;
  case 37:
    SET_OR_REMOVE(PLR_FLAGS(vict), PLR_SITEOK);
    break;
  case 38:
    SET_OR_REMOVE(PLR_FLAGS(vict), PLR_DELETED);
    break;
  case 39:
    if ((i = parse_class(*val_arg)) == CLASS_UNDEFINED) {
      send_to_char(ch, "That is not a class.\r\n");
      return (0);
    }
    GET_CLASS(vict) = i;
    break;
  case 40:
    SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NOWIZLIST);
    break;
  case 41:
    SET_OR_REMOVE(PRF_FLAGS(vict), PRF_QUEST);
    break;
  case 42:
    send_to_char(ch, "Sorry, this is pending pfile recode.\r\n");
/*
 * Recoded, but we can't use it until pfiles are in DAO
 *
    if (!str_cmp(val_arg, "off")) {
      REMOVE_BIT(PLR_FLAGS(vict), PLR_LOADROOM);
    } else {
      if ((room = roomData_find(val_arg)) == NULL) {
        send_to_char(ch, "That room does not exist!\r\n");
        return (0);
      } else {
        SET_BIT(PLR_FLAGS(vict), PLR_LOADROOM);
        GET_LOADROOM(vict) = room;
        send_to_char(ch, "%s will enter at room %s:%d.", GET_NAME(vict), room->zone->keyword, room->vnum);
      }
    }
 */
    break;
  case 43:
    SET_OR_REMOVE(PRF_FLAGS(vict), (PRF_COLOR_1 | PRF_COLOR_2));
    break;
  case 44:
    if (GET_IDNUM(ch) != 1 || !IS_NPC(vict))
      return (0);
    GET_IDNUM(vict) = value;
    break;
  case 45:
    if (GET_IDNUM(ch) > 1) {
      send_to_char(ch, "Please don't use this command, yet.\r\n");
      return (0);
    }
    if (GET_AUTH(vict) >= AUTH_OWNER) {
      send_to_char(ch, "You cannot change that.\r\n");
      return (0);
    }
    strncpy(GET_PASSWD(vict), CRYPT(val_arg, GET_NAME(vict)), MAX_PWD_LENGTH);	/* strncpy: OK (G_P:MAX_PWD_LENGTH) */
    *(GET_PASSWD(vict) + MAX_PWD_LENGTH) = '\0';
    send_to_char(ch, "Password changed to '%s'.\r\n", val_arg);
    break;
  case 46:
    SET_OR_REMOVE(PLR_FLAGS(vict), PLR_NODELETE);
    break;
  case 47:
    if ((i = search_block(val_arg, genders, FALSE)) < 0) {
      send_to_char(ch, "Must be 'male', 'female', or 'neutral'.\r\n");
      return (0);
    }
    GET_SEX(vict) = i;
    break;
  case 48:	/* set age */
    if (value < 2 || value > 200) {	/* Arbitrary limits. */
      send_to_char(ch, "Ages 2 to 200 accepted.\r\n");
      return (0);
    }
    /*
     * NOTE: May not display the exact age specified due to the integer
     * division used elsewhere in the code.  Seems to only happen for
     * some values below the starting age (17) anyway. -gg 5/27/98
     */
    vict->player.time.birth = time(0) - ((value - 17) * SECS_PER_MUD_YEAR);
    break;

  case 49:	/* Blame/Thank Rick Glover. :) */
    GET_HEIGHT(vict) = value;
    effectData_total(vict);
    break;

  case 50:
    GET_WEIGHT(vict) = value;
    effectData_total(vict);
    break;

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

  return (1);
}

/**
 * SET command
 *
 * This command lets a user set data on another character
 *
 * @sa perform_set
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_set)
{
  charData_t *vict = NULL, *cbuf = NULL;
  pfileElement_t tmp_store;
  char field[MAX_INPUT_LENGTH], name[MAX_INPUT_LENGTH], buf[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);

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

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

  /* 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(pfileElement_t), SEEK_SET);
      fwrite(&tmp_store, sizeof(pfileElement_t), 1, player_fl);
      send_to_char(ch, "Saved in file.\r\n");
    }
  }

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

/**
 * SLOWNS command
 *
 * This command lets a user toggle the Slow-NS setting.  If on the
 * mud won't resolve IP addresses to hostnames for users.
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_slowns) {
  extern int nameserver_is_slow;

  if ((nameserver_is_slow = !nameserver_is_slow))
    send_to_char(ch, "Nameserver_is_slow changed to YES; sitenames will no longer be resolved.\r\n");
  else
    send_to_char(ch, "Nameserver_is_slow changed to NO; IP addresses will now be resolved.\r\n");
}

/**
 * TRACKTHRU command
 *
 * This command lets a user toggle if mobiles can track through
 * closed doors.
 *
 * @param ch the character performing the command
 * @param argument the additional text passed after the command
 * @param cmd the command object that was performed
 * @return none
 */
ACMD(do_trackthru) {
  extern int track_through_doors;

  if ((track_through_doors = !track_through_doors))
    send_to_char(ch, "Will now track through doors.\r\n");
  else
    send_to_char(ch, "Will no longer track through doors.\r\n");
}