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

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

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


extern struct player_index_element *player_table;
extern int top_of_p_table;
extern int max_bad_pws;

/* external functions */
void echo_on(Descr d);
void echo_off(Descr d);
void do_start(Creature ch);
int isbanned(char *hostname);
int Valid_Name(char *newname);


/* prototypes for all do_x functions, sorted by letter */

/* A Block */
ACMD(do_advance);
ACMD(do_autowiz);
ACMD(do_attach);
ACMD(do_abandon);
ACMD(do_authorize);
ACMD(do_afk);
ACMD(do_affects);
ACMD(do_alias);
ACMD(do_assist);
ACMD(do_assemble);
ACMD(do_at);

/* B Block */
ACMD(do_board);
ACMD(do_blow);
ACMD(do_bathe);
ACMD(do_boost);
ACMD(do_bite);
ACMD(do_balance);
ACMD(do_bake);
ACMD(do_build);
ACMD(do_ban);
ACMD(do_bash);

/* C Block */
ACMD(do_chgleader);
ACMD(do_chip);
ACMD(do_catapult);
ACMD(do_create);
ACMD(do_cede);
ACMD(do_confirm);
ACMD(do_claim);
ACMD(do_craft);
ACMD(do_chop);
ACMD(do_commands);
ACMD(do_credits);

/* D Block */
ACMD(do_date);
ACMD(do_discipline);
ACMD(do_draw);
ACMD(do_disembark);
ACMD(do_deposit);
ACMD(do_douse);
ACMD(do_designate);
ACMD(do_defect);
ACMD(do_demote);
ACMD(do_dismantle);
ACMD(do_dismount);
ACMD(do_dig);
ACMD(do_dc);
ACMD(do_diagnose);
ACMD(do_display);
ACMD(do_drink);
ACMD(do_drop);
ACMD(do_diplomacy);

/* E Block */
ACMD(do_eat);
ACMD(do_extract);
ACMD(do_experience);
ACMD(do_excavate);
ACMD(do_embrace);
ACMD(do_execute);
ACMD(do_esay);
ACMD(do_edelete);
ACMD(do_empires);
ACMD(do_expell);
ACMD(do_enroll);
ACMD(do_echo);
ACMD(do_equipment);
ACMD(do_examine);
ACMD(do_exit);
ACMD(do_exits);

/* F Block */
ACMD(do_flee);
ACMD(do_feed);
ACMD(do_file);
ACMD(do_forge);
ACMD(do_fire);
ACMD(do_fullsave);
ACMD(do_follow);
ACMD(do_force);
ACMD(do_form);
ACMD(do_fish);

/* G Block */
ACMD(do_gecho);
ACMD(do_gather);
ACMD(do_gen_door);
ACMD(do_gen_ps);
ACMD(do_gen_tog);
ACMD(do_gen_write);
ACMD(do_get);
ACMD(do_give);
ACMD(do_goto);
ACMD(do_grab);

/* H Block */
ACMD(do_help);
ACMD(do_harness);
ACMD(do_herd);
ACMD(do_history);
ACMD(do_harvest);
ACMD(do_hide);
ACMD(do_hit);

/* I Block */
ACMD(do_info);
ACMD(do_infiltrate);
ACMD(do_insult);
ACMD(do_inventory);
ACMD(do_invis);

/* K Block */
ACMD(do_kick);

/* L Block */
ACMD(do_last);
ACMD(do_light);
ACMD(do_lead);
ACMD(do_lay);
ACMD(do_load);
ACMD(do_load_boat);
ACMD(do_look);

/* M Block */
ACMD(do_move);
ACMD(do_milk);
ACMD(do_melt);
ACMD(do_mill);
ACMD(do_mold);
ACMD(do_mine);
ACMD(do_mount);
ACMD(do_messages);
ACMD(do_mail);
ACMD(do_manufacture);

/* O Block */
ACMD(do_olc);
ACMD(do_offer);
ACMD(do_order);

/* P Block */
ACMD(do_page);
ACMD(do_path);
ACMD(do_play);
ACMD(do_pick);
ACMD(do_pan);
ACMD(do_purgevnum);
ACMD(do_purgeobjs);
ACMD(do_party);
ACMD(do_promote);
ACMD(do_plant);
ACMD(do_psay);
ACMD(do_pledge);
ACMD(do_purgemobs);
ACMD(do_pub_comm);
ACMD(do_prompt);
ACMD(do_poofset);
ACMD(do_pour);
ACMD(do_purge);
ACMD(do_put);
ACMD(do_publicize);

/* Q Block */
ACMD(do_quit);

/* R Block */
ACMD(do_reload);
ACMD(do_rise);
ACMD(do_reward);
ACMD(do_retrieve);
ACMD(do_roster);
ACMD(do_read);
ACMD(do_respond);
ACMD(do_random);
ACMD(do_remove);
ACMD(do_reply);
ACMD(do_report);
ACMD(do_rescue);
ACMD(do_reboot);
ACMD(do_rest);
ACMD(do_restore);
ACMD(do_return);

/* S Block */
ACMD(do_save);
ACMD(do_sap);
ACMD(do_shift);
ACMD(do_scrape);
ACMD(do_stake);
ACMD(do_speak);
ACMD(do_slit);
ACMD(do_seal);
ACMD(do_search);
ACMD(do_swap);
ACMD(do_sheath);
ACMD(do_shoot);
ACMD(do_sail);
ACMD(do_sacrifice);
ACMD(do_sew);
ACMD(do_slay);
ACMD(do_spawn);
ACMD(do_socials);
ACMD(do_skin);
ACMD(do_say);
ACMD(do_score);
ACMD(do_send);
ACMD(do_set);
ACMD(do_show);
ACMD(do_sit);
ACMD(do_sleep);
ACMD(do_sneak);
ACMD(do_snoop);
ACMD(do_spec_comm);
ACMD(do_split);
ACMD(do_stand);
ACMD(do_store);
ACMD(do_struggle);
ACMD(do_stat);
ACMD(do_steal);
ACMD(do_switch);

/* T Block */
ACMD(do_teleport);
ACMD(do_teach);
ACMD(do_tie);
ACMD(do_transport);
ACMD(do_throw);
ACMD(do_tedit);
ACMD(do_tell);
ACMD(do_time);
ACMD(do_title);
ACMD(do_track);
ACMD(do_trans);

/* U Block */
ACMD(do_unban);
ACMD(do_unload_boat);
ACMD(do_unpublicize);
ACMD(do_upgrade);
ACMD(do_unparty);
ACMD(do_users);

/* V Block */
ACMD(do_visible);
ACMD(do_vc);
ACMD(do_vcsay);
ACMD(do_vampire_heal);
ACMD(do_vnum);
ACMD(do_vstat);

/* W Block */
ACMD(do_wake);
ACMD(do_withdraw);
ACMD(do_wear);
ACMD(do_weather);
ACMD(do_where);
ACMD(do_who);
ACMD(do_whois);
ACMD(do_wield);
ACMD(do_wizlock);
ACMD(do_wizutil);
ACMD(do_write);


/* This is the Master Command List(tm).

 * You can put new commands in, take commands out, change the order
 * they appear in, etc.  You can adjust the "priority" of commands
 * simply by changing the order they appear in the command list.
 * (For example, if you want "as" to mean "assist" instead of "ask",
 * just put "assist" above "ask" in the Master Command List(tm).
 *
 * In general, utility commands such as "at" should have high priority;
 * infrequently used and dangerously destructive commands should have low
 * priority.
 */

cpp_extern const struct command_info cmd_info[] = {
	{ "RESERVED", 0, 0, 0, 0, 0, 0 },	/* this must be first -- for specprocs */

	/* directions come before other commands to preserve abbrevs */
	{ "north"		, POS_STANDING	, do_move		, 0				, NORTH			, CTYPE_MOVE	, 0					},
	{ "east"		, POS_STANDING	, do_move		, 0				, EAST			, CTYPE_MOVE	, 0					},
	{ "south"		, POS_STANDING	, do_move		, 0				, SOUTH			, CTYPE_MOVE	, 0					},
	{ "west"		, POS_STANDING	, do_move		, 0				, WEST			, CTYPE_MOVE	, 0					},
	{ "northeast"	, POS_STANDING	, do_move		, 0				, NORTHEAST		, CTYPE_MOVE	, 0					},
	{ "northwest"	, POS_STANDING	, do_move		, 0				, NORTHWEST		, CTYPE_MOVE	, 0					},
	{ "southeast"	, POS_STANDING	, do_move		, 0				, SOUTHEAST		, CTYPE_MOVE	, 0					},
	{ "southwest"	, POS_STANDING	, do_move		, 0				, SOUTHWEST		, CTYPE_MOVE	, 0					},
	{ "ne"			, POS_STANDING	, do_move		, 0				, NORTHEAST		, CTYPE_MOVE	, 0					},
	{ "nw"			, POS_STANDING	, do_move		, 0				, NORTHWEST		, CTYPE_MOVE	, 0					},
	{ "se"			, POS_STANDING	, do_move		, 0				, SOUTHEAST		, CTYPE_MOVE	, 0					},
	{ "sw"			, POS_STANDING	, do_move		, 0				, SOUTHWEST		, CTYPE_MOVE	, 0					},
	{ "up"			, POS_STANDING	, do_move		, 0				, UP			, CTYPE_MOVE	, 0					},
	{ "down"		, POS_STANDING	, do_move		, 0				, DOWN			, CTYPE_MOVE	, 0					},

	/* now, the main list */
	{ "at"			, POS_DEAD		, do_at			, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},
	{ "advance"		, POS_DEAD		, do_advance	, LVL_TOP		, 0				, CTYPE_IMMORTAL, 0					},
	{ "alias"		, POS_DEAD		, do_alias		, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "abandon"		, POS_DEAD		, do_abandon	, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "affects"		, POS_DEAD		, do_affects	, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "afk"			, POS_DEAD		, do_afk		, 0				, 0				, CTYPE_COMM	, 0					},
	{ "assemble"	, POS_STANDING	, do_assemble	, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "assist"		, POS_FIGHTING	, do_assist		, 0				, 0				, CTYPE_COMBAT	, 0					},
	{ "ask"			, POS_RESTING	, do_spec_comm	, 0				, SCMD_ASK		, CTYPE_COMM	, 0					},
	{ "attach"		, POS_SITTING	, do_attach		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "authorize"	, POS_DEAD		, do_authorize	, LVL_TOP		, 0				, CTYPE_IMMORTAL, 0					},
	{ "autoexecute"	, POS_DEAD		, do_gen_tog	, 0				, SCMD_AUTOKILL	, CTYPE_COMBAT	, 0					},
	{ "autokill"	, POS_DEAD		, do_gen_tog	, 0				, SCMD_AUTOKILL	, CTYPE_COMBAT	, 0					},
	{ "autowiz"		, POS_DEAD		, do_autowiz	, LVL_CIMPL		, 0				, CTYPE_IMMORTAL, 0					},

	{ "build"		, POS_STANDING	, do_build		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "bake"		, POS_STANDING	, do_bake		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "ban"			, POS_DEAD		, do_ban		, LVL_TOP		, 0				, CTYPE_IMMORTAL, 0					},
	{ "bash"		, POS_FIGHTING	, do_bash		, 0				, 0				, CTYPE_COMBAT	, 0					},
	{ "bathe"		, POS_STANDING	, do_bathe		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "bite"		, POS_STANDING	, do_bite		, 0				, 0				, CTYPE_COMBAT	, CMD_VAMPIRE_ONLY	},
	{ "blow"		, POS_STANDING	, do_blow		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "board"		, POS_STANDING	, do_board		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "boatload"	, POS_STANDING	, do_load_boat	, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "boost"		, POS_RESTING	, do_boost		, 0				, 0				, CTYPE_UTIL	, CMD_VAMPIRE_ONLY | CMD_GHOUL_ONLY	},
	{ "boatunload"	, POS_STANDING	, do_unload_boat, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "brief"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_BRIEF	, CTYPE_UTIL	, 0					},
	{ "bug"			, POS_DEAD		, do_gen_write	, 0				, SCMD_BUG		, CTYPE_COMM	, 0					},

	{ "chop"		, POS_STANDING	, do_chop		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "catapult"	, POS_STANDING	, do_catapult	, LVL_APPROVED	, 0				, CTYPE_COMBAT	, 0					},
	{ "cede"		, POS_DEAD		, do_cede		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "chgleader"		, POS_DEAD		, do_chgleader		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "chip"		, POS_STANDING	, do_chip		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "claim"		, POS_DEAD		, do_claim		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "clear"		, POS_DEAD		, do_gen_ps		, 0				, SCMD_CLEAR	, CTYPE_UTIL	, 0					},
	{ "close"		, POS_SITTING	, do_gen_door	, 0				, SCMD_CLOSE	, CTYPE_MOVE	, 0					},
	{ "cls"			, POS_DEAD		, do_gen_ps		, 0				, SCMD_CLEAR	, CTYPE_UTIL	, 0					},
	{ "color"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_COLOR	, CTYPE_UTIL	, 0					},
	{ "commands"	, POS_DEAD		, do_commands	, 0				, SCMD_COMMANDS	, CTYPE_UTIL	, 0					},
	{ "compact"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_COMPACT	, CTYPE_UTIL	, 0					},
	{ "confirm"		, POS_SLEEPING	, do_confirm	, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "craft"		, POS_STANDING	, do_craft		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "credits"		, POS_DEAD		, do_gen_ps		, 0				, SCMD_CREDITS	, CTYPE_UTIL	, 0					},
	{ "create"		, POS_STANDING	, do_create		, LVL_GOD		, 0				, CTYPE_IMMORTAL, 0					},

	{ "date"		, POS_DEAD		, do_date		, LVL_START_IMM	, SCMD_DATE		, CTYPE_IMMORTAL, 0					},
	{ "dc"			, POS_DEAD		, do_dc			, LVL_ASST		, 0				, CTYPE_IMMORTAL, 0					},
	{ "drink"		, POS_RESTING	, do_drink		, 0				, SCMD_DRINK	, CTYPE_MOVE	, 0					},
	{ "demote"		, POS_DEAD		, do_demote		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "defect"		, POS_DEAD		, do_defect		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "designate"	, POS_STANDING	, do_designate	, LVL_APPROVED	, FALSE			, CTYPE_BUILD	, 0					},
	{ "discipline"	, POS_DEAD		, do_discipline	, 0				, 0				, CTYPE_MOVE	, CMD_VAMPIRE_ONLY | CMD_GHOUL_ONLY	},
	{ "diagnose"	, POS_RESTING	, do_diagnose	, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "diplomacy"	, POS_SLEEPING	, do_diplomacy	, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "dismount"	, POS_FIGHTING	, do_dismount	, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "dismantle"	, POS_STANDING	, do_dismantle	, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "disembark"	, POS_STANDING	, do_disembark	, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "dig"			, POS_STANDING	, do_dig		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "douse"		, POS_STANDING	, do_douse		, 0				, 0				, CTYPE_BUILD	, 0					},
	{ "drop"		, POS_RESTING	, do_drop		, 0				, SCMD_DROP		, CTYPE_MOVE	, 0					},
	{ "draw"		, POS_RESTING	, do_draw		, 0				, 0				, CTYPE_COMBAT	, 0					},

	{ "eat"			, POS_RESTING	, do_eat		, 0				, SCMD_EAT		, CTYPE_MOVE	, 0					},
	{ "echo"		, POS_SLEEPING	, do_echo		, LVL_GOD		, SCMD_ECHO		, CTYPE_IMMORTAL, 0					},
	{ "empires"		, POS_DEAD		, do_empires	, 0				, 0				, CTYPE_EMPIRE	, 0					},
	{ "embrace"		, POS_STANDING	, do_embrace	, 0				, 0				, CTYPE_COMBAT	, CMD_VAMPIRE_ONLY	},
	{ "emote"		, POS_RESTING	, do_echo		, 0				, SCMD_EMOTE	, CTYPE_COMM	, 0					},
	{ ":"			, POS_RESTING	, do_echo		, 0				, SCMD_EMOTE	, CTYPE_COMM	, 0					},
	{ "enroll"		, POS_SLEEPING	, do_enroll		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "equipment"	, POS_RESTING	, do_equipment	, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "esay"		, POS_STUNNED	, do_esay		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, CMD_NOT_RP		},
	{ "etalk"		, POS_STUNNED	, do_esay		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, CMD_NOT_RP		},
	{ "examine"		, POS_SITTING	, do_examine	, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "excavate"	, POS_STANDING	, do_excavate	, LVL_APPROVED	, 0				, CTYPE_MOVE	, 0					},
	{ "execute"		, POS_STANDING	, do_execute	, 0				, 0				, CTYPE_COMBAT	, 0					},
	{ "exits"		, POS_RESTING	, do_exits		, 0				, NOWHERE		, CTYPE_MOVE	, 0					},
	{ "experience"	, POS_SLEEPING	, do_experience , LVL_APPROVED	, 0				, CTYPE_UTIL	, CMD_NOT_RP		},
	{ "expell"		, POS_SLEEPING	, do_expell		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "extract"		, POS_SLEEPING	, do_extract	, 0				, 0				, CTYPE_BUILD	, 0					},
	{ "edelete"		, POS_DEAD		, do_edelete	, LVL_TOP		, 0				, CTYPE_EMPIRE	, 0					},

	{ "force"		, POS_SLEEPING	, do_force		, LVL_CIMPL		, 0				, CTYPE_IMMORTAL, 0					},
	{ "fill"		, POS_STANDING	, do_pour		, 0				, SCMD_FILL		, CTYPE_MOVE	, 0					},
	{ "feed"		, POS_STANDING	, do_feed		, 0				, 0				, CTYPE_MOVE	, CMD_VAMPIRE_ONLY	},
	{ "file"		, POS_DEAD		, do_file		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},
	{ "forge"		, POS_STANDING	, do_forge		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "form"		, POS_DEAD		, do_form	, 0				, 0				, CTYPE_UTIL	, CMD_WEREWOLF_ONLY	},
	{ "fire"		, POS_STANDING	, do_fire		, LVL_APPROVED	, 0				, CTYPE_COMBAT	, 0					},
	{ "fish"		, POS_STANDING	, do_fish		, 0				, 0				, CTYPE_COMBAT	, 0					},
	{ "flee"		, POS_FIGHTING	, do_flee		, 0				, 0				, CTYPE_COMBAT	, 0					},
	{ "follow"		, POS_RESTING	, do_follow		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "fullsave"	, POS_DEAD		, do_fullsave	, LVL_TOP		, 0				, CTYPE_IMMORTAL, 0					},
	{ "freeze"		, POS_DEAD		, do_wizutil	, LVL_FREEZE	, SCMD_FREEZE	, CTYPE_IMMORTAL, 0					},

	{ "get"			, POS_RESTING	, do_get		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "gather"		, POS_STANDING	, do_gather		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "gecho"		, POS_DEAD		, do_gecho		, LVL_GOD		, 0				, CTYPE_IMMORTAL, 0					},
	{ "give"		, POS_RESTING	, do_give		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "goto"		, POS_SLEEPING	, do_goto		, LVL_START_IMM	, SCMD_GOTO		, CTYPE_IMMORTAL, 0					},
	{ "godnet"		, POS_DEAD		, do_pub_comm	, LVL_GOD		, SCMD_GODNET	, CTYPE_IMMORTAL, 0					},
	{ "/"			, POS_DEAD		, do_pub_comm	, LVL_GOD		, SCMD_GODNET	, CTYPE_IMMORTAL, 0					},
	{ "godlist"		, POS_DEAD		, do_gen_ps		, 0				, SCMD_GODLIST	, CTYPE_UTIL	, 0					},
	{ "gossip"		, POS_SLEEPING	, do_pub_comm	, 0				, SCMD_GOSSIP	, CTYPE_UTIL	, 0					},
	{ "grab"		, POS_RESTING	, do_grab		, 0				, 0				, CTYPE_MOVE	, 0					},

	{ "help"		, POS_DEAD		, do_help		, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "harness"		, POS_STANDING	, do_harness	, 0				, FALSE			, CTYPE_MOVE	, 0					},
	{ "harvest"		, POS_STANDING	, do_harvest	, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "handbook"	, POS_DEAD		, do_gen_ps		, LVL_START_IMM	, SCMD_HANDBOOK	, CTYPE_IMMORTAL, 0					},
	{ "heal"		, POS_DEAD		, do_vampire_heal,0				, 0				, CTYPE_MOVE	, CMD_VAMPIRE_ONLY | CMD_GHOUL_ONLY	},
	{ "herd"		, POS_STANDING	, do_herd		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "hide"		, POS_RESTING	, do_hide		, 0				, 0				, CTYPE_MOVE	, CMD_HUMAN_ONLY	},
	{ "history"		, POS_DEAD		, do_history	, 0				, 0				, CTYPE_COMM	, CMD_NOT_RP		},
	//hide email moved to prevent errors, check end of list
	{ "hit"			, POS_FIGHTING	, do_hit		, 0				, SCMD_HIT		, CTYPE_COMBAT	, 0					},
	{ "hold"		, POS_RESTING	, do_grab		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "holylight"	, POS_DEAD		, do_gen_tog	, LVL_GOD		, SCMD_HOLYLIGHT, CTYPE_IMMORTAL, 0					},

	{ "inventory"	, POS_RESTING	, do_inventory	, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "idea"		, POS_DEAD		, do_gen_write	, 0				, SCMD_IDEA		, CTYPE_COMM	, 0					},
	{ "imotd"		, POS_DEAD		, do_gen_ps		, LVL_START_IMM	, SCMD_IMOTD	, CTYPE_IMMORTAL, 0					},
	{ "infiltrate"	, POS_STANDING	, do_infiltrate	, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "info"		, POS_SLEEPING	, do_gen_ps		, 0				, SCMD_INFO		, CTYPE_UTIL	, 0					},
	{ "insult"		, POS_RESTING	, do_insult		, 0				, 0				, CTYPE_COMM	, 0					},
	{ "invis"		, POS_DEAD		, do_invis		, LVL_GOD		, 0				, CTYPE_IMMORTAL, 0					},

	{ "junk"		, POS_RESTING	, do_drop		, 0				, SCMD_JUNK		, CTYPE_UTIL	, 0					},

	{ "kill"		, POS_FIGHTING	, do_hit		, 0				, 0				, CTYPE_COMBAT	, 0					},
	{ "kick"		, POS_FIGHTING	, do_kick		, 0				, 0				, CTYPE_COMBAT	, 0					},

	{ "look"		, POS_RESTING	, do_look		, 0				, SCMD_LOOK		, CTYPE_MOVE	, 0					},
	{ "ls"			, POS_RESTING	, do_look		, 0				, SCMD_LOOK		, CTYPE_MOVE	, 0					},
	{ "lay"			, POS_STANDING	, do_lay		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "last"		, POS_DEAD		, do_last		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},
	{ "lead"		, POS_STANDING	, do_lead		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "light"		, POS_SITTING	, do_light		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "load"		, POS_DEAD		, do_load		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},
	{ "load"		, POS_STANDING	, do_load_boat	, 0				, 0				, CTYPE_MOVE	, 0					},

	{ "messages"	, POS_DEAD		, do_messages	, 0				, 0				, CTYPE_COMM	, CMD_NOT_RP		},
	{ "mappc"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_MAPPC	, CTYPE_UTIL	, 0					},
	{ "mapcolor"	, POS_DEAD		, do_gen_tog	, 0				, SCMD_NOMAPCOL , CTYPE_UTIL	, 0					},
	{ "manufacture"	, POS_STANDING	, do_manufacture, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "melt"		, POS_STANDING	, do_melt		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "mine"		, POS_STANDING	, do_mine		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "mill"		, POS_STANDING	, do_mill		, LVL_APPROVED	, 0				, CTYPE_MOVE	, 0					},
	{ "milk"		, POS_STANDING	, do_milk		, LVL_APPROVED	, 0				, CTYPE_MOVE	, 0					},
	{ "mortlog"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_MORTLOG	, CTYPE_UTIL	, 0					},
	{ "motd"		, POS_DEAD		, do_gen_ps		, 0				, SCMD_MOTD		, CTYPE_UTIL	, 0					},
	{ "mount"		, POS_STANDING	, do_mount		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "mail"		, POS_STANDING	, do_mail		, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "mold"		, POS_STANDING	, do_mold		, LVL_APPROVED	, 0				, CTYPE_MOVE	, 0					},
	{ "mute"		, POS_DEAD		, do_wizutil	, LVL_MUTE		, SCMD_MUTE		, CTYPE_IMMORTAL, 0					},

	{ "noclear"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_NOCLEAR	, CTYPE_UTIL	, 0					},
	{ "nobite"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_NOBITE	, CTYPE_UTIL	, 0					},
	{ "nofeed"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_NOFEED	, CTYPE_UTIL	, 0					},
	{ "nogossip"	, POS_DEAD		, do_gen_tog	, 0				, SCMD_NOGOSSIP	, CTYPE_UTIL	, 0					},
	{ "noooc"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_NOOOC	, CTYPE_UTIL	, 0					},
	{ "norepeat"	, POS_DEAD		, do_gen_tog	, 0				, SCMD_NOREPEAT	, CTYPE_UTIL	, 0					},
	{ "noshout"		, POS_SLEEPING	, do_gen_tog	, 0				, SCMD_DEAF		, CTYPE_UTIL	, 0					},
	{ "notell"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_NOTELL	, CTYPE_UTIL	, 0					},
	{ "noteach"		, POS_DEAD		, do_gen_tog	, 0				, SCMD_NOTEACH	, CTYPE_UTIL	, 0					},
	{ "notitle"		, POS_DEAD		, do_wizutil	, LVL_ASST		, SCMD_NOTITLE	, CTYPE_IMMORTAL, 0					},
	{ "nowiz"		, POS_DEAD		, do_gen_tog	, LVL_GOD		, SCMD_NOWIZ	, CTYPE_IMMORTAL, 0					},

	{ "ooc"			, POS_DEAD		, do_pub_comm	, 0				, SCMD_OOC		, CTYPE_COMM	, CMD_NOT_RP		},
	{ "oocsay"		, POS_RESTING	, do_say		, 0				, SCMD_OOCSAY	, CTYPE_COMM	, 0					},
	{ "\""			, POS_RESTING	, do_say		, 0				, SCMD_OOCSAY	, CTYPE_COMM	, 0					},
	{ "order"		, POS_RESTING	, do_order		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "open"		, POS_SITTING	, do_gen_door	, 0				, SCMD_OPEN		, CTYPE_MOVE	, 0					},

	{ "put"			, POS_RESTING	, do_put		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "path"		, POS_DEAD		, do_path		, 0				, 0				, CTYPE_MOVE	, CMD_VAMPIRE_ONLY | CMD_GHOUL_ONLY	},
	{ "page"		, POS_DEAD		, do_page		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},
	{ "pan"			, POS_STANDING	, do_pan		, LVL_APPROVED	, 0				, CTYPE_MOVE	, 0					},
	{ "party"		, POS_RESTING	, do_party		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "pick"		, POS_STANDING	, do_pick		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "play"		, POS_STANDING	, do_play		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "plant"		, POS_STANDING	, do_plant		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "pledge"		, POS_SLEEPING	, do_pledge		, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "political"	, POS_DEAD		, do_gen_tog	, 0				, SCMD_POLITICAL, CTYPE_EMPIRE	, 0					},
	{ "policy"		, POS_DEAD		, do_gen_ps		, 0				, SCMD_POLICIES	, CTYPE_UTIL	, 0					},
	{ "poofin"		, POS_DEAD		, do_poofset	, LVL_GOD		, SCMD_POOFIN	, CTYPE_IMMORTAL, 0					},
	{ "poofout"		, POS_DEAD		, do_poofset	, LVL_GOD		, SCMD_POOFOUT	, CTYPE_IMMORTAL, 0					},
	{ "pour"		, POS_STANDING	, do_pour		, 0				, SCMD_POUR		, CTYPE_MOVE	, 0					},
	{ "promote"		, POS_DEAD		, do_promote	, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "prompt"		, POS_DEAD		, do_prompt		, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "publicize"	, POS_RESTING	, do_publicize	, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "purge"		, POS_DEAD		, do_purge		, LVL_ASST		, 0				, CTYPE_IMMORTAL, 0					},
	{ "purgemobs"	, POS_DEAD		, do_purgemobs	, LVL_TOP		, 0				, CTYPE_IMMORTAL, 0					},
	{ "purgeobjs"	, POS_DEAD		, do_purgeobjs	, LVL_TOP		, 0				, CTYPE_COMM	, 0					},
	{ "psay"		, POS_SLEEPING	, do_psay		, 0				, 0				, CTYPE_COMM	, CMD_NOT_RP		},
	{ "ptell"		, POS_SLEEPING	, do_psay		, 0				, 0				, CTYPE_COMM	, CMD_NOT_RP		},
	{ "purgevnum"	, POS_STANDING	, do_purgevnum	, LVL_TOP		, 0				, CTYPE_IMMORTAL, 0					},

	{ "qui"			, POS_DEAD		, do_quit		, 0				, 0				, CTYPE_UTIL	, CMD_NOT_RP		},
	{ "quit"		, POS_DEAD		, do_quit		, 0				, SCMD_QUIT		, CTYPE_UTIL	, CMD_NOT_RP		},

	{ "reply"		, POS_DEAD		, do_reply		, 0				, 0				, CTYPE_COMM	, CMD_NOT_RP		},
	{ "redesignate"	, POS_STANDING	, do_designate	, LVL_APPROVED	, TRUE			, CTYPE_BUILD	, 0					},
	{ "respond"		, POS_RESTING	, do_respond	, 0				, 0				, CTYPE_COMM	, 0					},
	{ "reboo"		, POS_DEAD		, do_reboot		, LVL_CIMPL		, SCMD_REBOOT_DUMMY	, CTYPE_IMMORTAL, 0				},
	{ "reboot"		, POS_DEAD		, do_reboot		, LVL_CIMPL		, SCMD_REBOOT	, CTYPE_IMMORTAL, 0					},
	{ "reload"		, POS_DEAD		, do_reload		, LVL_TOP		, 0				, CTYPE_IMMORTAL, 0					},
	{ "reward"		, POS_DEAD		, do_reward		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},
	{ "random"		, POS_SLEEPING	, do_random		, LVL_TOP		, 0				, CTYPE_IMMORTAL, 0					},
	{ "read"		, POS_RESTING	, do_read		, 0				, 0				, CTYPE_COMM	, 0					},
	{ "redit"		, POS_DEAD		, do_olc		, LVL_BUILDER	, SCMD_REDIT	, CTYPE_OLC		, 0					},
	{ "remove"		, POS_RESTING	, do_remove		, 0				, 0				, CTYPE_COMM	, 0					},
	{ "report"		, POS_RESTING	, do_report		, 0				, 0				, CTYPE_COMM	, 0					},
	{ "rescue"		, POS_FIGHTING	, do_rescue		, 0				, 0				, CTYPE_COMBAT	, 0					},
	{ "rest"		, POS_RESTING	, do_rest		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "restore"		, POS_DEAD		, do_restore	, LVL_CIMPL	, 0				, CTYPE_IMMORTAL, 0					},
	{ "retrieve"	, POS_STANDING	, do_retrieve	, LVL_APPROVED	, 0				, CTYPE_MOVE	, 0					},
	{ "return"		, POS_DEAD		, do_return		, 0				, 0				, CTYPE_IMMORTAL, 0					},
	{ "rise"		, POS_STUNNED	, do_rise		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "roster"		, POS_DEAD		, do_roster		, 0				, 0				, CTYPE_EMPIRE	, 0					},
	{ "rp"			, POS_DEAD		, do_gen_tog	, 0				, SCMD_RP		, CTYPE_UTIL	, 0					},

	{ "say"			, POS_RESTING	, do_say		, 0				, SCMD_SAY		, CTYPE_COMM	, 0					},
	{ "'"			, POS_RESTING	, do_say		, 0				, SCMD_SAY		, CTYPE_COMM	, 0					},
	{ "sail"		, POS_STANDING	, do_sail		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "sap"			, POS_STANDING	, do_sap		, 0				, 0				, CTYPE_BUILD	, 0					},
	{ "save"		, POS_STUNNED	, do_save		, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "sacrifice"	, POS_STANDING	, do_sacrifice	, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "score"		, POS_DEAD		, do_score		, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "scrape"		, POS_STANDING	, do_scrape		, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "scrolling"	, POS_DEAD		, do_gen_tog	, 0				, SCMD_SCROLLING, CTYPE_UTIL	, 0					},
	{ "seal"		, POS_RESTING	, do_seal		, 0				, 0				, CTYPE_MOVE	, CMD_VAMPIRE_ONLY	},
	{ "search"		, POS_STANDING	, do_search		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "send"		, POS_SLEEPING	, do_send		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},
	{ "set"			, POS_DEAD		, do_set		, LVL_ASST		, 0				, CTYPE_IMMORTAL, 0					},
	{ "sew"			, POS_STANDING	, do_sew		, LVL_APPROVED	, 0				, CTYPE_MOVE	, 0					},
	{ "sheath"		, POS_RESTING	, do_sheath		, 0				, 0				, CTYPE_COMBAT	, 0					},
	{ "shift"		, POS_FIGHTING	, do_shift		, LVL_APPROVED	, 0				, CTYPE_MOVE	, CMD_WEREWOLF_ONLY	},
	{ "shoot"		, POS_STANDING	, do_shoot		, 0				, 0				, CTYPE_COMBAT	, 0					},
	{ "shout"		, POS_RESTING	, do_pub_comm	, 0				, SCMD_SHOUT	, CTYPE_COMM	, 0					},
	{ "show"		, POS_DEAD		, do_show		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},
	{ "shutdow"		, POS_DEAD		, do_reboot		, LVL_TOP		, SCMD_REBOOT_DUMMY	, CTYPE_IMMORTAL, 0				},
	{ "shutdown"	, POS_DEAD		, do_reboot		, LVL_TOP		, SCMD_SHUTDOWN	, CTYPE_IMMORTAL, 0					},
	{ "sip"			, POS_RESTING	, do_drink		, 0				, SCMD_SIP		, CTYPE_MOVE	, 0					},
	{ "sit"			, POS_RESTING	, do_sit		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "skin"		, POS_STANDING	, do_skin		, LVL_APPROVED	, 0				, CTYPE_MOVE	, 0					},
	{ "sleep"		, POS_SLEEPING	, do_sleep		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "slay"		, POS_RESTING	, do_slay		, LVL_IMPL		, 0				, CTYPE_IMMORTAL, 0					},
	{ "slit"		, POS_RESTING	, do_slit		, 0				, 0				, CTYPE_MOVE	, CMD_VAMPIRE_ONLY	},
	{ "sneak"		, POS_STANDING	, do_sneak		, 0				, 0				, CTYPE_MOVE	, CMD_HUMAN_ONLY | CMD_STAY_HIDDEN	},
	{ "snoop"		, POS_DEAD		, do_snoop		, LVL_ASST		, 0				, CTYPE_IMMORTAL, 0					},
	{ "socials"		, POS_DEAD		, do_socials	, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "speak"		, POS_DEAD		, do_speak		, 0				, 0				, CTYPE_COMM	, 0					},
	{ "stand"		, POS_RESTING	, do_stand		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "stake"		, POS_FIGHTING	, do_stake		, 0				, FALSE			, CTYPE_COMBAT	, 0					},
	{ "stat"		, POS_DEAD		, do_stat		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},
	{ "steal"		, POS_STANDING	, do_steal		, LVL_APPROVED	, 0				, CTYPE_MOVE	, 0					},
	{ "store"		, POS_STANDING	, do_store		, LVL_APPROVED	, 0				, CTYPE_MOVE	, 0					},
	{ "struggle"	, POS_SLEEPING	, do_struggle	, 0				, 0				, CTYPE_COMBAT	, 0					},
	{ "swap"		, POS_RESTING	, do_swap		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "switch"		, POS_DEAD		, do_switch		, LVL_CIMPL		, 0				, CTYPE_IMMORTAL, 0					},
	{ "spawn"		, POS_DEAD		, do_spawn		, LVL_TOP		, 0				, CTYPE_IMMORTAL, 0					},

	{ "tell"		, POS_DEAD		, do_tell		, 0				, 0				, CTYPE_COMM	, CMD_NOT_RP		},
	{ "take"		, POS_RESTING	, do_get		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "taste"		, POS_RESTING	, do_eat		, 0				, SCMD_TASTE	, CTYPE_MOVE	, 0					},
	{ "teach"		, POS_STANDING	, do_teach		, LVL_APPROVED	, 0				, CTYPE_UTIL	, CMD_VAMPIRE_ONLY	},
	{ "tedit"		, POS_DEAD		, do_tedit		, LVL_CIMPL		, 0				, CTYPE_IMMORTAL, 0					},
	{ "teleport"	, POS_STANDING	, do_goto		, LVL_GOD		, SCMD_TELEPORT	, CTYPE_IMMORTAL, 0					},
	{ "throw"		, POS_FIGHTING	, do_throw		, LVL_APPROVED	, 0				, CTYPE_COMBAT	, 0					},
	{ "thaw"		, POS_DEAD		, do_wizutil	, LVL_FREEZE	, SCMD_THAW		, CTYPE_IMMORTAL, 0					},
	{ "tie"			, POS_STANDING	, do_tie		, 0				, FALSE			, CTYPE_COMBAT	, 0					},
	{ "title"		, POS_DEAD		, do_title		, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "time"		, POS_DEAD		, do_time		, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "track"		, POS_STANDING	, do_track		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "transfer"	, POS_SLEEPING	, do_trans		, LVL_ASST		, 0				, CTYPE_IMMORTAL, 0					},
	{ "transport"	, POS_STANDING	, do_transport	, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "typo"		, POS_DEAD		, do_gen_write	, 0				, SCMD_TYPO		, CTYPE_COMM	, 0					},

	{ "unparty"		, POS_DEAD		, do_unparty	, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "unharness"	, POS_STANDING	, do_harness	, 0				, TRUE			, CTYPE_MOVE	, 0					},
	{ "unload"		, POS_STANDING	, do_unload_boat, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "unstake"		, POS_STANDING	, do_stake		, 0				, TRUE			, CTYPE_COMBAT	, 0					},
	{ "untie"		, POS_STANDING	, do_tie		, 0				, TRUE			, CTYPE_COMBAT	, 0					},
	{ "unban"		, POS_DEAD		, do_unban		, LVL_TOP		, 0				, CTYPE_IMMORTAL, 0					},
	{ "unpublicize"	, POS_DEAD		, do_unpublicize, LVL_APPROVED	, 0				, CTYPE_EMPIRE	, 0					},
	{ "uptime"		, POS_DEAD		, do_date		, LVL_START_IMM	, SCMD_UPTIME	, CTYPE_IMMORTAL, 0					},
	{ "upgrade"		, POS_STANDING	, do_upgrade	, LVL_APPROVED	, 0				, CTYPE_BUILD	, 0					},
	{ "users"		, POS_DEAD		, do_users		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},

	{ "vc"			, POS_DEAD		, do_vc			, 0				, 0				, CTYPE_COMM	, CMD_NOT_RP		},
	{ "vcsay"		, POS_DEAD		, do_vcsay		, 0				, 0				, CTYPE_COMM	, CMD_NOT_RP		},
	{ "."			, POS_DEAD		, do_vcsay		, 0				, 0				, CTYPE_COMM	, CMD_NOT_RP		},
	{ "version"		, POS_DEAD		, do_gen_ps		, 0				, SCMD_VERSION	, CTYPE_UTIL	, 0					},
	{ "visible"		, POS_RESTING	, do_visible	, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "vnum"		, POS_DEAD		, do_vnum		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},
	{ "vstat"		, POS_DEAD		, do_vstat		, LVL_START_IMM	, 0				, CTYPE_IMMORTAL, 0					},

	{ "wake"		, POS_SLEEPING	, do_wake		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "wear"		, POS_RESTING	, do_wear		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "weather"		, POS_RESTING	, do_weather	, 0				, 0				, CTYPE_UTIL	, 0					},
	{ "who"			, POS_DEAD		, do_who		, 0				, 0				, CTYPE_COMM	, CMD_STAY_HIDDEN	},
	{ "whois"		, POS_DEAD		, do_whois		, 0				, 0				, CTYPE_COMM	, CMD_STAY_HIDDEN	},
	{ "where"		, POS_RESTING	, do_where		, 0				, 0				, CTYPE_COMM	, 0					},
	{ "whisper"		, POS_RESTING	, do_spec_comm	, 0				, SCMD_WHISPER	, CTYPE_COMM	, 0					},
	{ "wield"		, POS_RESTING	, do_wield		, 0				, 0				, CTYPE_MOVE	, 0					},
	{ "wiznet"		, POS_DEAD		, do_pub_comm	, LVL_START_IMM	, SCMD_WIZNET	, CTYPE_IMMORTAL, 0					},
	{ ";"			, POS_DEAD		, do_pub_comm	, LVL_START_IMM	, SCMD_WIZNET	, CTYPE_IMMORTAL, 0					},
	{ "wizhelp"		, POS_SLEEPING	, do_commands	, LVL_GOD		, SCMD_WIZHELP	, CTYPE_IMMORTAL, 0					},
	{ "wizlist"		, POS_DEAD		, do_gen_ps		, 0				, SCMD_WIZLIST	, CTYPE_UTIL	, 0					},
	{ "wizlock"		, POS_DEAD		, do_wizlock	, LVL_CIMPL		, 0				, CTYPE_IMMORTAL, 0					},
	{ "write"		, POS_STANDING	, do_write		, 0				, 0				, CTYPE_COMM	, 0					},

	//moved to help prevent glitch of "hide" executing "hideemail"
	{ "hideemail"	, POS_DEAD		, do_gen_tog	, LVL_APPROVED	, SCMD_HIDEEMAIL, CTYPE_UTIL	, 0					},

	{ "\n", 0, 0, 0, 0, 0, 0 } };	/* this must be last */


const char *fill[] = {
	"in",
	"from",
	"with",
	"the",
	"on",
	"at",
	"to",
	"\n"
	};

const char *reserved[] = {
	"a",
	"an",
	"some",
	"self",
	"me",
	"all",
	"room",
	"someone",
	"something",
	"\n"
	};

/*
 * This is the actual command interpreter called from game_loop() in comm.c
 * It makes sure you are the proper level and position to execute the command,
 * then calls the appropriate function.
 */
void command_interpreter(Creature ch, char *argument) {
	extern int check_social(Creature ch, char *string);
	int cmd, length;
	char *line;

	/* just drop to next line for hitting CR */
	skip_spaces(&argument);
	if (!*argument)
		return;

	/*
	 * special case to handle one-character, non-alphanumeric commands;
	 * requested by many people so "'hi" or ";godnet test" is possible.
	 * Patch sent by Eric Green and Stefan Wasilewski.
	 */
	if (!isalpha(*argument)) {
		arg[0] = argument[0];
		arg[1] = '\0';
		line = argument + 1;
		}
	else
		line = any_one_arg(argument, arg);

	/* otherwise, find the command */
	for (length = strlen(arg), cmd = 0; *cmd_info[cmd].command != '\n'; cmd++)
		if (!strncmp(cmd_info[cmd].command, arg, length))
			if (GET_LEVEL(ch) >= cmd_info[cmd].minimum_level) {
				if ((IS_SET(cmd_info[cmd].flags, CMD_VAMPIRE_ONLY) && IS_VAMPIRE(ch)) || (IS_SET(cmd_info[cmd].flags, CMD_WEREWOLF_ONLY) && IS_WEREWOLF(ch)) || (IS_SET(cmd_info[cmd].flags, CMD_GHOUL_ONLY) && IS_GHOUL(ch)) || (IS_SET(cmd_info[cmd].flags, CMD_HUMAN_ONLY) && IS_HUMAN(ch)))
					break;
				else if (!IS_SET(cmd_info[cmd].flags, CMD_VAMPIRE_ONLY | CMD_WEREWOLF_ONLY | CMD_GHOUL_ONLY | CMD_HUMAN_ONLY))
					break;
				}

	if (!IS_SET(cmd_info[cmd].flags, CMD_STAY_HIDDEN | CMD_UNHIDE_AFTER))
		REMOVE_BIT(AFF_FLAGS(ch), AFF_HIDE);

	if (*cmd_info[cmd].command == '\n' && check_social(ch, argument))
		return;
	else if (*cmd_info[cmd].command == '\n')
		send_to_char(HUH, ch);
	else if (!IS_NPC(ch) && PLR_FLAGGED(ch, PLR_FROZEN))
		send_to_char("You try, but the mind-numbing cold prevents you...\r\n", ch);
	else if (!IS_NPC(ch) && !IS_GOD(ch) && !IS_IMMORTAL(ch) && PRF_FLAGGED(ch, PRF_RP) && IS_SET(cmd_info[cmd].flags, CMD_NOT_RP))
		msg_to_char(ch, "You can't do that while role-playing!\r\n");
	else if (IS_INJURED(ch, INJ_STAKED))
		msg_to_char(ch, "You can't do that while staked!\r\n");
	else if (IS_INJURED(ch, INJ_TORPOR) && cmd_info[cmd].minimum_position >= POS_SLEEPING)
		msg_to_char(ch, "You can't do that while in torpor!\r\n");
	else if (DSC_FLAGGED(ch, DSC_EARTHMELD) && cmd_info[cmd].minimum_position >= POS_SLEEPING)
		msg_to_char(ch, "You can't do that while interred in the earth.  Use 'rise' first.\r\n");
	else if (DSC_FLAGGED(ch, DSC_BITUMENOUS_FLESH) && cmd_info[cmd].minimum_position >= POS_SLEEPING)
		msg_to_char(ch, "You can't do that while mummified.\r\n");
	else if (DSC_FLAGGED(ch, DSC_DEATHS_WHISPER) && cmd_info[cmd].minimum_position >= POS_SLEEPING)
		msg_to_char(ch, "You can't do that while under the influence of death's whisper!\r\n");
	else if (GET_FED_ON_BY(ch) && cmd_info[cmd].minimum_position >= POS_SLEEPING)
		msg_to_char(ch, "The ecstasy of the fangs in your flesh is too enchanting to do that...\r\n");
	else if (GET_FEEDING_FROM(ch) && cmd_info[cmd].minimum_position >= POS_SLEEPING && cmd_info[cmd].command_pointer != do_bite)
		msg_to_char(ch, "You can't do that while feeding!\r\n");
	else if (cmd_info[cmd].command_pointer == NULL)
		send_to_char("Sorry, that command hasn't been implemented yet.\r\n", ch);
	else if (IS_NPC(ch) && cmd_info[cmd].minimum_level >= LVL_GOD)
		send_to_char("You can't use immortal commands while switched.\r\n", ch);
	else if (IS_INJURED(ch, INJ_TIED) && cmd_info[cmd].minimum_position > POS_SLEEPING)
		msg_to_char(ch, "You're tied up!\r\n");
	else if (GET_POS(ch) < cmd_info[cmd].minimum_position)
		switch (GET_POS(ch)) {
			case POS_DEAD:
				send_to_char("Lie still; you are DEAD!!! :-(\r\n", ch);
				break;
			case POS_INCAP:
			case POS_MORTALLYW:
				send_to_char("You are in a pretty bad shape, unable to do anything!\r\n", ch);
				break;
			case POS_STUNNED:
				send_to_char("All you can do right now is think about the stars!\r\n", ch);
				break;
			case POS_SLEEPING:
				send_to_char("In your dreams, or what?\r\n", ch);
				break;
			case POS_RESTING:
				send_to_char("Nah... You feel too relaxed to do that..\r\n", ch);
				break;
			case POS_SITTING:
				send_to_char("Maybe you should get on your feet first?\r\n", ch);
				break;
			case POS_FIGHTING:
				send_to_char("No way!  You're fighting for your life!\r\n", ch);
				break;
			}
	else
		((*cmd_info[cmd].command_pointer) (ch, line, cmd, cmd_info[cmd].subcmd));

	/* Unhide after ? */
	if (ch && IS_SET(cmd_info[cmd].flags, CMD_UNHIDE_AFTER))
		REMOVE_BIT(AFF_FLAGS(ch), AFF_HIDE);
	}


/**************************************************************************
 * Routines to handle aliasing                                             *
  **************************************************************************/

struct alias_data *find_alias(struct alias_data *alias_list, char *str) {
	while (alias_list != NULL) {
		if (*str == *alias_list->alias)	/* hey, every little bit counts :-) */
			if (!strcmp(str, alias_list->alias))
				return (alias_list);

		alias_list = alias_list->next;
		}

	return (NULL);
	}


void free_alias(struct alias_data *a) {
	if (a->alias)
		free(a->alias);
	if (a->replacement)
		free(a->replacement);
	free(a);
	}


/* The interface to the outside world: do_alias */
ACMD(do_alias) {
	char *repl;
	struct alias_data *a, *temp;

	if (IS_NPC(ch))
		return;

	repl = any_one_arg(argument, arg);

	if (!*arg) {			/* no argument specified -- list currently defined aliases */
		send_to_char("Currently defined aliases:\r\n", ch);
		if ((a = GET_ALIASES(ch)) == NULL)
			send_to_char(" None.\r\n", ch);
		else {
			while (a != NULL) {
				sprintf(buf, "%-15s %s\r\n", a->alias, a->replacement);
				send_to_char(buf, ch);
				a = a->next;
				}
			}
		}
	else {			/* otherwise, add or remove aliases */
		/* is this an alias we've already defined? */
		if ((a = find_alias(GET_ALIASES(ch), arg)) != NULL) {
			REMOVE_FROM_LIST(a, GET_ALIASES(ch), next);
			free_alias(a);
			}
		/* if no replacement string is specified, assume we want to delete */
		if (!*repl) {
			if (a == NULL)
				send_to_char("No such alias.\r\n", ch);
			else
				send_to_char("Alias deleted.\r\n", ch);
			}
		else {			/* otherwise, either add or redefine an alias */
			if (!str_cmp(arg, "alias")) {
				send_to_char("You can't alias 'alias'.\r\n", ch);
				return;
				}
			CREATE(a, struct alias_data, 1);
			a->alias = str_dup(arg);
			delete_doubledollar(repl);
			a->replacement = str_dup(repl);
			if (strchr(repl, ALIAS_SEP_CHAR) || strchr(repl, ALIAS_VAR_CHAR))
				a->type = ALIAS_COMPLEX;
			else
				a->type = ALIAS_SIMPLE;
			a->next = GET_ALIASES(ch);
			GET_ALIASES(ch) = a;
			send_to_char("Alias added.\r\n", ch);
			}
		}
	}


/*
 * Valid numeric replacements are only $1 .. $9 (makes parsing a little
 * easier, and it's not that much of a limitation anyway.)  Also valid
 * is "$*", which stands for the entire original line after the alias.
 * ";" is used to delimit commands.
 */
#define NUM_TOKENS       9

void perform_complex_alias(struct txt_q *input_q, char *orig, struct alias_data *a) {
	struct txt_q temp_queue;
	char *tokens[NUM_TOKENS], *temp, *write_point;
	int num_of_tokens = 0, num;

	skip_spaces(&orig);

	/* First, parse the original string */
	temp = strtok(strcpy(buf2, orig), " ");
	while (temp != NULL && num_of_tokens < NUM_TOKENS) {
		tokens[num_of_tokens++] = temp;
			temp = strtok(NULL, " ");
		}

	/* initialize */
	write_point = buf;
	temp_queue.head = temp_queue.tail = NULL;

	/* now parse the alias */
	for (temp = a->replacement; *temp; temp++) {
		if (*temp == ALIAS_SEP_CHAR) {
			*write_point = '\0';
			buf[MAX_INPUT_LENGTH - 1] = '\0';
			write_to_q(buf, &temp_queue, 1);
			write_point = buf;
			}
		else if (*temp == ALIAS_VAR_CHAR) {
			temp++;
			if ((num = *temp - '1') < num_of_tokens && num >= 0) {
				strcpy(write_point, tokens[num]);
					write_point += strlen(tokens[num]);
				}
			else if (*temp == ALIAS_GLOB_CHAR) {
				strcpy(write_point, orig);
				write_point += strlen(orig);
				}
			else if ((*(write_point++) = *temp) == '$')	/* redouble $ for act safety */
				*(write_point++) = '$';
			}
		else
			*(write_point++) = *temp;
		}

	*write_point = '\0';
	buf[MAX_INPUT_LENGTH - 1] = '\0';
	write_to_q(buf, &temp_queue, 1);

	/* push our temp_queue on to the _front_ of the input queue */
	if (input_q->head == NULL)
		*input_q = temp_queue;
	else {
		temp_queue.tail->next = input_q->head;
		input_q->head = temp_queue.head;
		}
	}


/*
 * Given a character and a string, perform alias replacement on it.
 *
 * Return values:
 *   0: String was modified in place; call command_interpreter immediately.
 *   1: String was _not_ modified in place; rather, the expanded aliases
 *      have been placed at the front of the character's input queue.
 */
int perform_alias(Descr d, char *orig) {
	char first_arg[MAX_INPUT_LENGTH], *ptr;
	struct alias_data *a, *tmp;

	/* Mobs don't have alaises. */
	if (IS_NPC(d->character))
		return (0);

	/* bail out immediately if the guy doesn't have any aliases */
	if ((tmp = GET_ALIASES(d->character)) == NULL)
		return (0);

	/* find the alias we're supposed to match */
	ptr = any_one_arg(orig, first_arg);

	/* bail out if it's null */
	if (!*first_arg)
		return (0);

	/* if the first arg is not an alias, return without doing anything */
	if ((a = find_alias(tmp, first_arg)) == NULL)
		return (0);

	if (a->type == ALIAS_SIMPLE) {
		strcpy(orig, a->replacement);
		return (0);
		}
	else {
		perform_complex_alias(&d->input, ptr, a);
		return (1);
		}
	}



/***************************************************************************
 * Various other parsing utilities                                         *
 **************************************************************************/

int enter_player_game(Descr d, int dolog) {
	void read_aliases(Creature ch);
	void read_lore(Creature ch);
	extern struct time_info_data time_info;
	extern room_rnum find_haven(Creature ch);
	extern room_rnum create_haven(Creature ch);
	extern room_rnum find_load_room(Creature ch);
	extern long get_ptable_by_name(char *name);
	extern long top_idnum;

	room_rnum load_room;
	int load_result, i;
	Creature ch = d->character;

	reset_char(ch);
	read_aliases(ch);
	read_lore(ch);

	if (GET_IDNUM(ch) == 0)
		if ((i = get_ptable_by_name(GET_NAME(ch))) != -1)
			player_table[i].id = GET_IDNUM(ch) = ++top_idnum;

	if (GET_IMM_LEV(ch) > -1)
		GET_LEVEL(ch) = LVL_TOP - GET_IMM_LEV(ch);

	if (PLR_FLAGGED(ch, PLR_INVSTART))
		GET_INVIS_LEV(ch) = GET_LEVEL(ch);

	if (real_empire(GET_LOYALTY(ch)) == -1)
		GET_LOYALTY(ch) = 0;

	/*
	 * We have to place the character in a room before equipping them
	 * or equip_char() will gripe about the person in NOWHERE.
	 */
	if ((load_room = GET_LOADROOM(ch)) != NOWHERE)
		load_room = real_room(load_room);

	/* If that failed, check for a haven */
	if (load_room == NOWHERE)
		load_room = find_haven(d->character);

	/* If char was saved with NOWHERE, or real_room above failed... */
	if (load_room == NOWHERE) {
		if (IS_VAMPIRE(d->character))
			load_room = create_haven(d->character);
		else
			load_room = find_load_room(d->character);
		}

	/* Temporary provision */
	if (SECT(load_room) == SECT_OCEAN)
		load_room = find_load_room(d->character);

	/* No toasting!  Place them in a haven or kick them back out! */
	if (SECT(load_room) != SECT_INSIDE && ((SECT(load_room) != SECT_BUILDING && SECT(load_room) != SECT_MULTI) || !IS_COMPLETE(load_room)) && IS_VAMPIRE(d->character) && weather_info.sunlight != SUN_DARK && !DSC_FLAGGED(ch, DSC_EARTHMELD) && !ROOM_AFF_FLAGGED(load_room, ROOM_AFF_DARK) && (load_room = find_haven(d->character)) == NOWHERE) {
		sprintf(buf, "Current game time: %d o'clock %s\r\n", ((time_info.hours % 12 == 0) ? 12 : ((time_info.hours) % 12)), ((time_info.hours >= 12) ? "pm" : "am"));
		SEND_TO_Q("\r\nThe area where you would enter the game is lit by the sun.  You are denied entry at this time because your character would probably be killed very quickly.\r\n", d);
		SEND_TO_Q(buf, d);
		SEND_TO_Q("\r\n*** Press ENTER: ", d);
		/* We aren't always sent here by CON_MENU */
		STATE(d) = CON_MENU;
		return -2;
		}

	/* fail-safe */
	if (IS_VAMPIRE(ch) && GET_APPARENT_AGE(ch) <= 0)
		GET_APPARENT_AGE(ch) = 25;

	/* position must be reset */
	if (DSC_FLAGGED(ch, DSC_EARTHMELD | DSC_BITUMENOUS_FLESH) || IS_INJURED(ch, INJ_TORPOR))
		if (GET_DAMAGE(ch) < 7)
			GET_POS(ch) = POS_SLEEPING;

	ch->next = character_list;
	character_list = ch;
	char_to_room(ch, load_room);
	load_result = Crash_load(ch, dolog);

	affect_total(ch);
	SAVE_CHAR(ch);

	return load_result;
	}


/*
 * searches an array of strings for a target string.  "exact" can be
 * 0 or non-0, depending on whether or not the match must be exact for
 * it to be returned.  Returns -1 if not found; 0..n otherwise.  Array
 * must be terminated with a '\n' so it knows to stop searching.
 */
int search_block(char *arg, const char **list, int exact) {
	register int i, l;

	/* Make into lower case, and get length of string */
	for (l = 0; *(arg + l); l++)
		*(arg + l) = LOWER(*(arg + l));

	if (exact) {
		for (i = 0; **(list + i) != '\n'; i++)
			if (!strcmp(arg, *(list + i)))
		return (i);
		}
	else {
		if (!l)
			l = 1;			/* Avoid "" to match the first available string */
		for (i = 0; **(list + i) != '\n'; i++)
			if (!strncmp(arg, *(list + i), l))
				return (i);
		}

	return (-1);
	}


int is_number(const char *str) {
	while (*str)
		if (!isdigit(*(str++)))
			return (0);

	return (1);
	}


/*
 * Function to skip over the leading spaces of a string.
 */
void skip_spaces(char **string) {
	for (; **string && isspace(**string); (*string)++);
	}


/*
 * Given a string, change all instances of double dollar signs ($$) to
 * single dollar signs ($).  When strings come in, all $'s are changed
 * to $$'s to avoid having users be able to crash the system if the
 * inputted string is eventually sent to act().  If you are using user
 * input to produce screen output AND YOU ARE SURE IT WILL NOT BE SENT
 * THROUGH THE act() FUNCTION (i.e., do_gecho, do_title, but NOT do_say),
 * you can call delete_doubledollar() to make the output look correct.
 *
 * Modifies the string in-place.
 */
char *delete_doubledollar(char *string) {
	char *read, *write;

	/* If the string has no dollar signs, return immediately */
	if ((write = strchr(string, '$')) == NULL)
		return (string);

	/* Start from the location of the first dollar sign */
	read = write;

	while (*read)   /* Until we reach the end of the string... */
		if ((*(write++) = *(read++)) == '$') /* copy one char */
			if (*read == '$')
				read++; /* skip if we saw 2 $'s in a row */

	*write = '\0';

	return (string);
	}


int fill_word(char *argument) {
	return (search_block(argument, fill, TRUE) >= 0);
	}


int reserved_word(char *argument) {
	return (search_block(argument, reserved, TRUE) >= 0);
	}


/*
 * copy the first non-fill-word, space-delimited argument of 'argument'
 * to 'first_arg'; return a pointer to the remainder of the string.
 */
char *one_argument(char *argument, char *first_arg) {
	char *begin = first_arg;

	if (!argument) {
		log("SYSERR: one_argument received a NULL pointer!");
		*first_arg = '\0';
		return (NULL);
		}

	do {
		skip_spaces(&argument);

		first_arg = begin;
		while (*argument && !isspace(*argument)) {
			*(first_arg++) = LOWER(*argument);
			argument++;
			}

		*first_arg = '\0';
		} while (fill_word(begin));

	return (argument);
	}


/*
 * one_word is like one_argument, except that words in quotes ("") are
 * considered one word.
 */
char *one_word(char *argument, char *first_arg) {
	char *begin = first_arg;

	do {
		skip_spaces(&argument);

		first_arg = begin;

		if (*argument == '\"') {
			argument++;
			while (*argument && *argument != '\"') {
				*(first_arg++) = LOWER(*argument);
				argument++;
				}
			argument++;
			}
		else {
			while (*argument && !isspace(*argument)) {
				*(first_arg++) = LOWER(*argument);
				argument++;
				}
			}

		*first_arg = '\0';
		} while (fill_word(begin));

	return (argument);
	}


/* same as one_argument except that it doesn't ignore fill words */
char *any_one_arg(char *argument, char *first_arg) {
	skip_spaces(&argument);

	while (*argument && !isspace(*argument)) {
		*(first_arg++) = LOWER(*argument);
		argument++;
		}

	*first_arg = '\0';

	return (argument);
	}


/*
 * Same as one_argument except that it takes two args and returns the rest;
 * ignores fill words
 */
char *two_arguments(char *argument, char *first_arg, char *second_arg) {
	return (one_argument(one_argument(argument, first_arg), second_arg));
	}


/*
 * determine if a given string is an abbreviation of another
 * (now works symmetrically -- JE 7/25/94)
 *
 * that was dumb.  it shouldn't be symmetrical.  JE 5/1/95
 *
 * returnss 1 if arg1 is an abbreviation of arg2
 */
int is_abbrev(const char *arg1, const char *arg2) {
	if (!*arg1)
		return (0);

	for (; *arg1 && *arg2; arg1++, arg2++)
		if (LOWER(*arg1) != LOWER(*arg2))
			return (0);

	if (!*arg1)
		return (1);
	else
		return (0);
	}



/* return first space-delimited token in arg1; remainder of string in arg2 */
void half_chop(char *string, char *arg1, char *arg2) {
	char *temp;

	temp = any_one_arg(string, arg1);
	skip_spaces(&temp);
	strcpy(arg2, temp);
	}



/* Used in specprocs, mostly.  (Exactly) matches "command" to cmd number */
int find_command(const char *command) {
	int cmd;

	for (cmd = 0; *cmd_info[cmd].command != '\n'; cmd++)
	if (!strcmp(cmd_info[cmd].command, command))
		return (cmd);

	return (-1);
	}



/* *************************************************************************
*  Stuff for controlling the non-playing sockets (get name, pwd etc)       *
************************************************************************* */

/* locate entry in p_table with entry->name == name. -1 mrks failed search */
int find_name(char *name) {
	int i;

	for (i = 0; i <= top_of_p_table; i++) {
		if (!str_cmp((player_table + i)->name, name))
			return (i);
		}

	return (-1);
	}


int _parse_name(char *arg, char *name) {
	int i;

	/* skip whitespaces */
	for (; isspace(*arg); arg++);

	for (i = 0; (*name = *arg); arg++, i++, name++)
		if (!isalpha(*arg) && *arg != '\'' && *arg != '-')
			return (1);

	if (!i)
		return (1);

	return (0);
	}


#define RECON		1
#define USURP		2
#define UNSWITCH	3

/*
 * XXX: Make immortals 'return' instead of being disconnected when switched
 *      into person returns.  This function seems a bit over-extended too.
 */
int perform_dupe_check(Descr d) {
	Descr k, next_k;
	Creature target = NULL, ch, next_ch;
	int mode = 0;

	int id = GET_IDNUM(d->character);

	/*
	 * Now that this descriptor has successfully logged in, disconnect all
	 * other descriptors controlling a character with the same ID number.
	 */

	for (k = descriptor_list; k; k = next_k) {
		next_k = k->next;

		if (k == d)
			continue;

		if (k->original && (GET_IDNUM(k->original) == id)) {    /* switched char */
			SEND_TO_Q("\r\nMultiple login detected -- disconnecting.\r\n", k);
			STATE(k) = CON_CLOSE;
			if (!target) {
				target = k->original;
				mode = UNSWITCH;
				}
			if (k->character)
				k->character->desc = NULL;
				k->character = NULL;
				k->original = NULL;
			}
		else if (k->character && (GET_IDNUM(k->character) == id)) {
			if (!target && STATE(k) == CON_PLAYING) {
				SEND_TO_Q("\r\nThis body has been usurped!\r\n", k);
				target = k->character;
				mode = USURP;
				}
			k->character->desc = NULL;
			k->character = NULL;
			k->original = NULL;
			SEND_TO_Q("\r\nMultiple login detected -- disconnecting.\r\n", k);
			STATE(k) = CON_CLOSE;
			}
		}

	/*
	 * now, go through the character list, deleting all characters that
	 * are not already marked for deletion from the above step (i.e., in the
	 * CON_HANGUP state), and have not already been selected as a target for
	 * switching into.  In addition, if we haven't already found a target,
	 * choose one if one is available (while still deleting the other
	 * duplicates, though theoretically none should be able to exist).
	 */

	for (ch = character_list; ch; ch = next_ch) {
		next_ch = ch->next;

		if (IS_NPC(ch))
			continue;
		if (GET_IDNUM(ch) != id)
			continue;

		/* ignore chars with descriptors (already handled by above step) */
		if (ch->desc)
			continue;

		/* don't extract the target char we've found one already */
		if (ch == target)
			continue;

		/* we don't already have a target and found a candidate for switching */
		if (!target) {
			target = ch;
			mode = RECON;
			continue;
			}

		/* we've found a duplicate - blow him away. */
		if (ch->in_room != NOWHERE)
			char_from_room(ch);
		char_to_room(ch, 0);
		extract_char(ch);
		}

	/* no target for swicthing into was found - allow login to continue */
	if (!target)
		return (0);

	/* Okay, we've found a target.  Connect d to target. */
	free_char(d->character); /* get rid of the old char */
	d->character = target;
	d->character->desc = d;
	d->original = NULL;
	d->character->char_specials.timer = 0;
	REMOVE_BIT(PLR_FLAGS(d->character), PLR_MAILING | PLR_WRITING);
	REMOVE_BIT(AFF_FLAGS(d->character), AFF_PARTY);
	STATE(d) = CON_PLAYING;

	if (PLR_FLAGGED(d->character, PLR_IPMASK))
		strcpy(d->host, "masked");

	switch (mode) {
		case RECON:
			SEND_TO_Q("Reconnecting.\r\n", d);
			act("$n has reconnected.", TRUE, d->character, 0, 0, TO_ROOM);
			syslog(GET_INVIS_LEV(d->character), TRUE, "%s [%s] has reconnected.", GET_NAME(d->character), d->host);
			break;
		case USURP:
			SEND_TO_Q("You take over your own body, already in use!\r\n", d);
			act("$n suddenly keels over in pain, surrounded by a white aura...\r\n"
				"$n's body has been taken over by a new spirit!", TRUE, d->character, 0, 0, TO_ROOM);
			syslog(GET_INVIS_LEV(d->character), TRUE, "%s has re-logged in ... disconnecting old socket.", GET_NAME(d->character));
			break;
		case UNSWITCH:
			SEND_TO_Q("Reconnecting to unswitched char.", d);
			syslog(GET_INVIS_LEV(d->character), TRUE, "%s [%s] has reconnected.", GET_NAME(d->character), d->host);
			break;
		}

	return (1);
	}


void send_motd(Descr d) {
	extern char *motd;
	extern char *imotd;
	extern char *CREDIT_MESSG;
	int i;

	if (!PRF_FLAGGED(d->character, PRF_NOCLEAR))
		SEND_TO_Q("", d);
	SEND_TO_Q(CREDIT_MESSG, d);

	SEND_TO_Q(" ", d);
	for (i = 0; i < 79; i++)
		SEND_TO_Q("=", d);
	SEND_TO_Q("\r\n\r\n", d);

	if (GET_LEVEL(d->character) >= LVL_START_IMM)
		SEND_TO_Q(imotd, d);
	else
		SEND_TO_Q(motd, d);

	SEND_TO_Q("\r\n ", d);
	for (i = 0; i < 79; i++)
		SEND_TO_Q("=", d);
	SEND_TO_Q("\r\n", d);
	}


struct sort_struct {
	int sort_pos;
	byte is_social;
	} *cmd_sort_info = NULL;
int num_of_cmds;

void sort_commands(void) {
	int a, b, tmp;

	num_of_cmds = 0;

	/*
	 * first, count commands (num_of_commands is actually one greater than the
	 * number of commands; it inclues the '\n'.
	 */
	while (*cmd_info[num_of_cmds].command != '\n')
		num_of_cmds++;

	/* create data array */
	CREATE(cmd_sort_info, struct sort_struct, num_of_cmds);

	/* initialize it */
	for (a = 1; a < num_of_cmds; a++) {
		cmd_sort_info[a].sort_pos = a;
		cmd_sort_info[a].is_social = 0;
		}

	/* Sort.  'a' starts at 1, not 0, to remove 'RESERVED' */
	for (a = 1; a < num_of_cmds - 1; a++)
		for (b = a + 1; b < num_of_cmds; b++)
			if (strcmp(cmd_info[cmd_sort_info[a].sort_pos].command, cmd_info[cmd_sort_info[b].sort_pos].command) > 0) {
				tmp = cmd_sort_info[a].sort_pos;
				cmd_sort_info[a].sort_pos = cmd_sort_info[b].sort_pos;
				cmd_sort_info[b].sort_pos = tmp;
				}
	}


ACMD(do_commands) {
	int no, i, cmd_num;
	int wizhelp = 0;
	Creature vict;

	one_argument(argument, arg);

	if (*arg) {
		if (!(vict = get_char_vis(ch, arg, FIND_CHAR_WORLD)) || IS_NPC(vict)) {
			send_to_char("Who is that?\r\n", ch);
			return;
			}
		if (GET_LEVEL(ch) < GET_LEVEL(vict)) {
			send_to_char("You can't see the commands of people above your level.\r\n", ch);
			return;
			}
		}
	else
		vict = ch;

	if (subcmd == SCMD_WIZHELP)
		wizhelp = 1;

	sprintf(buf, "The following %s%s are available to %s:\r\n", wizhelp ? "privileged " : "", "commands", vict == ch ? "you" : PERS(vict, ch, 1));

	/* cmd_num starts at 1, not 0, to remove 'RESERVED' */
	for (no = 1, cmd_num = 1; cmd_num < num_of_cmds; cmd_num++) {
		i = cmd_sort_info[cmd_num].sort_pos;
		if (cmd_info[i].minimum_level >= 0 && GET_LEVEL(vict) >= cmd_info[i].minimum_level && (cmd_info[i].minimum_level >= LVL_GOD) == wizhelp) {
			sprintf(buf + strlen(buf), "%-11s", cmd_info[i].command);
			if (!(no % 7))
				strcat(buf, "\r\n");
			no++;
			}
		}

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


/* Determine if a person is multiplaying */
bool check_multiplaying(Descr d) {
	Descr c;
	bool ok = TRUE;

	if (GET_LEVEL(d->character) >= LVL_START_IMM)
		return TRUE;

	if (PLR_FLAGGED(d->character, PLR_MULTIOK | PLR_IPMASK))
		return TRUE;

	/* Check for connected players with identical hosts */
	for (c = descriptor_list; c; c = c->next)
		if (c != d && STATE(c) == CON_PLAYING && GET_LEVEL(c->character) >= LVL_APPROVED && !str_cmp(c->host, d->host) && !PLR_FLAGGED(c->character, PLR_MULTIOK) && GET_IDNUM(c->character) != GET_IDNUM(d->character))
			ok = FALSE;

	return ok;
	}


/*
 * Determine if a player can be autoauthorized
 *  if idnum != -1 then we ignore the person with that idnum
 */
bool validate_autoauthorize(Descr d, char *arg, long idnum) {
	extern struct time_info_data *real_time_passed(time_t t2, time_t t1);
	extern struct player_index_element *player_table;
	extern int top_of_p_table;

	struct char_file_u vbuf;
	Descr c;
	int j;
	bool ok = TRUE;

	/* Process the e-mail address into buf */
	one_argument(arg, buf);

	/* Check for connected players with identical hosts */
	for (c = descriptor_list; c; c = c->next)
		if (c != d && c->character && GET_LEVEL(c->character) >= LVL_APPROVED && !str_cmp(c->host, d->host))
			if (!PLR_FLAGGED(c->character, PLR_IPMASK | PLR_MULTIOK))
				ok = FALSE;

	/* Check common email addresses and hosts - done here to help reduce lag */
	if (ok) {
		for (j = 0; j <= top_of_p_table; j++) {
			load_char((player_table + j)->name, &vbuf);
			if (!IS_SET(vbuf.char_specials_saved.act, PLR_DELETED | PLR_SLAIN) && vbuf.level >= LVL_APPROVED)
				if (!str_cmp(vbuf.email, buf) || ((*real_time_passed(vbuf.last_logon, 0)).day < 14 && !str_cmp(vbuf.host, d->host)))
					if (!IS_SET(vbuf.char_specials_saved.act, PLR_IPMASK))
						if (vbuf.char_specials_saved.idnum != idnum)
							ok = FALSE;
			}
		}

	if (ok) {
		syslog(0, TRUE, "Autoauthorization approved for %s: %s [%s]", GET_PC_NAME(d->character), buf, d->host);
		if (GET_EMAIL(d->character))
			free(GET_EMAIL(d->character));
		d->character->player.email = str_dup(buf);
		GET_LEVEL(d->character) = LVL_APPROVED;
		return TRUE;
		}

	syslog(0, TRUE, "Autoauthorization denied for %s [%s]", GET_PC_NAME(d->character), d->host);
	GET_LEVEL(d->character) = 1;
	return FALSE;
	}


/* Protocol for adjusting Attributes */
#define Attribute_Modify(text, store, attribute, not1, not2)	{								\
	if (*buf1 && is_abbrev(buf1, text)) {														\
		if (add) {																				\
			if (store >= 5)																		\
				SEND_TO_Q("\r\nYou may not begin with any Attribute greater than 5.\r\n", d);	\
			else if (attribute >= 10)															\
				SEND_TO_Q("\r\nYou can't raise any this Attribute group any more.\r\n", d);		\
			else if ((not1 > 8 || not2 > 8) && attribute >= 8)									\
				SEND_TO_Q("\r\nYou may not increase this Attribute group any more.\r\n", d);	\
			else if (((not1 > 6 && not2 > 6) || (not2 > 6 && not1 > 6)) && attribute >= 6)		\
				SEND_TO_Q("\r\nYou may not increase this Attribute group any more.\r\n", d);	\
			else {																				\
				store += 1;																		\
				d->character->player_specials->create_points -= 1;								\
				}																				\
			}																					\
		else if (subtract) {																	\
			if (store <= 1)																		\
				SEND_TO_Q("\r\nYou may not lower an Attribute below 1.\r\n", d);				\
			else {																				\
				store -= 1;																		\
				d->character->player_specials->create_points += 1;								\
				}																				\
			}																					\
		}																						\
	}


/* Protocol for adjusting Abilities */
#define Ability_Modify(text, store, ability, not1, not2)	{									\
	if (*buf1 && is_abbrev(buf1, text)) {														\
		if (add) {																				\
			if (store >= 3)																		\
				SEND_TO_Q("\r\nYou may not begin with any Ability greater than 3.\r\n", d);		\
			else if (ability >= 13)																\
				SEND_TO_Q("\r\nYou can't raise any this Ability group any more.\r\n", d);		\
			else if ((not1 > 9 || not2 > 9) && ability >= 9)									\
				SEND_TO_Q("\r\nYou may not increase this Ability group any more.\r\n", d);		\
			else if (((not1 > 5 && not2 > 5) || (not2 > 5 && not1 > 5)) && ability >= 5)		\
				SEND_TO_Q("\r\nYou may not increase this Ability group any more.\r\n", d);		\
			else {																				\
				store += 1;																		\
				d->character->player_specials->create_points -= 1;								\
				}																				\
			}																					\
		else if (subtract) {																	\
			if (store <= 0)																		\
				SEND_TO_Q("\r\nYou may not lower an Ability below 0.\r\n", d);					\
			else {																				\
				store -= 1;																		\
				d->character->player_specials->create_points += 1;								\
				}																				\
			}																					\
		}																						\
	}


void assign_werewolf_advantages(Descr d) {
	/* Gnosis: by breed */
	switch (GET_BREED(d->character)) {
		case BREED_HOMID:
			GET_MAX_GNOSIS(d->character) = 1;
			break;
		case  BREED_METIS:
			GET_MAX_GNOSIS(d->character) = 3;
			break;
		case BREED_LUPUS:
			GET_MAX_GNOSIS(d->character) = 5;
			break;
		}

	/* Rage: by auspice */
	GET_MAX_RAGE(d->character) = GET_AUSPICE(d->character) + 1;

	/* Willpower: by tribe */
	switch (GET_TRIBE(d->character)) {
		case TRIBE_BLACK_FURIES:
		case TRIBE_FENRIR:
		case TRIBE_FIANNA:
		case TRIBE_RED_TALONS:
		case TRIBE_SHADOW_LORDS:
		case TRIBE_SILENT_STRIDERS:
		case TRIBE_WARDERS:
			GET_MAX_WILLPOWER(d->character) = 3;
			break;
		case TRIBE_BONE_GNAWERS:
		case TRIBE_CHILDREN_OF_GAIA:
		case TRIBE_SILVER_FANGS:
			GET_MAX_WILLPOWER(d->character) = 4;
			break;
		}
	}


/* deal with newcomers and other non-playing sockets */
void nanny(Descr d, char *arg) {
	extern struct discipline_data path[];
	extern const char *hardcore_slain_msg;
	extern struct new_eq_set_data new_eq[];
	extern char *background;
	extern char *MENU;
	extern char *WELC_MESSG;
	extern char *START_MESSG;
	extern const char *AUTH_MESSG;
	extern int wizlock_level;
	extern char *wizlock_message;
	extern const char *langs[];
	extern struct tribe_data tribe[];
	extern const char *skin_colors[];
	extern const char *hair_colors[];
	extern const char *eye_colors[];

	void parse_empire_edit(Descr d, char *arg);
	void display_statistics_to_char(Creature ch);
	void display_attributes(Creature ch, Creature to, bool real);
	void display_abilities(Creature ch, Creature to);
	struct time_info_data *real_time_passed(time_t t2, time_t t1);
	void delete_empire(int rnum);
	extern struct empire_edit_data *create_empire_editor(int emp);
	void send_empire_edit_menu(Descr d);

	int emp;
	char buf[128];
	int player_i, load_result, i, j;
	char tmp_name[MAX_INPUT_LENGTH];
	struct char_file_u tmp_store;
	struct time_info_data playing_time;
	bool add = FALSE, subtract = FALSE;
	byte physical, social, mental;
	byte talents, skills, knowledges;

	skip_spaces(&arg);

	switch (STATE(d)) {
		case CON_EMPIRE_EDIT:
			parse_empire_edit(d, arg);
			break;

		case CON_GET_NAME:		/* wait for input of name */
			if (d->character == NULL) {
				CREATE(d->character, struct char_data, 1);
				clear_char(d->character);
				CREATE(d->character->player_specials, struct player_special_data, 1);
				d->character->desc = d;
				}
			if (!*arg)
				STATE(d) = CON_CLOSE;
			else {
				if ((_parse_name(arg, tmp_name)) || strlen(tmp_name) < 2 || strlen(tmp_name) > MAX_NAME_LENGTH || !Valid_Name(tmp_name) || fill_word(strcpy(buf, tmp_name)) || reserved_word(buf)) {
					SEND_TO_Q("Invalid name, please try another.\r\nName: ", d);
					return;
					}
				if ((player_i = load_char(tmp_name, &tmp_store)) > -1) {
					store_to_char(&tmp_store, d->character);
					GET_PFILEPOS(d->character) = player_i;

					if (PLR_FLAGGED(d->character, PLR_DELETED)) {
						/* We get a false positive from the original deleted character. */
						free_char(d->character);
						/* Check for multiple creations... */
						if (!Valid_Name(tmp_name)) {
							SEND_TO_Q("Invalid name, please try another.\r\nName: ", d);
							return;
							}
						CREATE(d->character, struct char_data, 1);
						clear_char(d->character);
						CREATE(d->character->player_specials, struct player_special_data, 1);
						d->character->desc = d;
						CREATE(d->character->player.name, char, strlen(tmp_name) + 1);
						strcpy(d->character->player.name, CAP(tmp_name));
						GET_PFILEPOS(d->character) = player_i;
						sprintf(buf, "Did I get that right, %s (Y/N)? ", tmp_name);
						SEND_TO_Q(buf, d);
						STATE(d) = CON_NAME_CNFRM;
						}
					else {
						/* undo it just in case they are set */
						REMOVE_BIT(PLR_FLAGS(d->character), PLR_WRITING | PLR_MAILING);
						REMOVE_BIT(AFF_FLAGS(d->character), AFF_PARTY);

						SEND_TO_Q("Password: ", d);
						echo_off(d);
						d->idle_tics = 0;
						STATE(d) = CON_PASSWORD;
						}
					}
				else {
					/* player unknown -- make new character */

					/* Check for multiple creations of a character. */
					if (!Valid_Name(tmp_name)) {
						SEND_TO_Q("Invalid name, please try another.\r\nName: ", d);
						return;
						}
					CREATE(d->character->player.name, char, strlen(tmp_name) + 1);
					strcpy(d->character->player.name, CAP(tmp_name));

					sprintf(buf, "Did I get that right, %s (Y/N)? ", tmp_name);
					SEND_TO_Q(buf, d);
					STATE(d) = CON_NAME_CNFRM;
					}
				}
			break;

		case CON_NAME_CNFRM:		/* wait for conf. of new name    */
			if (UPPER(*arg) == 'Y') {
				if (isbanned(d->host) >= BAN_NEW) {
					syslog(0, TRUE, "Request for new char %s denied from [%s] (siteban)", GET_PC_NAME(d->character), d->host);
					SEND_TO_Q("Sorry, new characters are not allowed from your site!\r\n", d);
					STATE(d) = CON_CLOSE;
					return;
					}
				if (wizlock_level) {
					if (!wizlock_message)
						SEND_TO_Q("Sorry, new players can't be created at the moment.\r\n", d);
					else
						SEND_TO_Q(wizlock_message, d);
					syslog(0, TRUE, "Request for new char %s denied from [%s] (wizlock)", GET_PC_NAME(d->character), d->host);
					STATE(d) = CON_CLOSE;
					return;
					}
				SEND_TO_Q("New character.\r\n\r\n", d);
				sprintf(buf, "Give me a password for %s: ", GET_PC_NAME(d->character));
				SEND_TO_Q(buf, d);
				echo_off(d);
				STATE(d) = CON_NEWPASSWD;
				}
			else if (*arg == 'n' || *arg == 'N') {
				SEND_TO_Q("Okay, what IS it, then? ", d);
				free(d->character->player.name);
				d->character->player.name = NULL;
				STATE(d) = CON_GET_NAME;
				}
			else {
				SEND_TO_Q("Please type Yes or No: ", d);
				}
			break;

		case CON_PASSWORD:		/* get pwd for known player      */
			/*
			 * To really prevent duping correctly, the player's record should
			 * be reloaded from disk at this point (after the password has been
			 * typed).  However I'm afraid that trying to load a character over
			 * an already loaded character is going to cause some problem down the
			 * road that I can't see at the moment.  So to compensate, I'm going to
			 * (1) add a 15 or 20-second time limit for entering a password, and (2)
			 * re-add the code to cut off duplicates when a player quits.  JE 6 Feb 96
			 */

			/* turn echo back on */
			echo_on(d);

			/* New echo_on() eats the return on telnet. Extra space better than none. */
			SEND_TO_Q("\r\n", d);

			if (!*arg)
				STATE(d) = CON_CLOSE;
			else {
				if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) {
					syslog(0, TRUE, "BAD PW: %s [%s]", GET_NAME(d->character), d->host);
					GET_BAD_PWS(d->character)++;
					SAVE_CHAR(d->character);
					if (++(d->bad_pws) >= max_bad_pws) {	/* 3 strikes and you're out. */
						SEND_TO_Q("Wrong password... disconnecting.\r\n", d);
						STATE(d) = CON_CLOSE;
						}
					else {
						SEND_TO_Q("Wrong password.\r\nPassword: ", d);
						echo_off(d);
						}
					return;
					}

				/* Password was correct. */
				load_result = GET_BAD_PWS(d->character);
				GET_BAD_PWS(d->character) = 0;
				d->bad_pws = 0;

				if (isbanned(d->host) == BAN_SELECT && !PLR_FLAGGED(d->character, PLR_SITEOK)) {
					SEND_TO_Q("Sorry, this character has not been cleared for login from your site!\r\n", d);
					STATE(d) = CON_CLOSE;
					syslog(0, TRUE, "Connection attempt for %s denied from %s", GET_NAME(d->character), d->host);
					return;
					}
				if (GET_LEVEL(d->character) < wizlock_level) {
					if (wizlock_message)
						SEND_TO_Q(wizlock_message, d);
					else
						SEND_TO_Q("The game is temporarily restricted.. try again later.\r\n", d);
					STATE(d) = CON_CLOSE;
					syslog(0, TRUE, "Request for login denied for %s [%s] (wizlock)", GET_NAME(d->character), d->host);
					return;
					}
				/* check and make sure no other copies of this player are logged in */
				if (!check_multiplaying(d)) {
					SEND_TO_Q("\r\n\033[31mAccess Denied: Multiplaying detected\033[0m\r\n", d);
					SEND_TO_Q("There is already someone logged in from the same IP address as you.  If you\r\n", d);
					SEND_TO_Q("are controlling that character, you must remove it from the game before this\r\n", d);
					SEND_TO_Q("character can enter.  Rarely, computers may share IP addresses.  If this is\r\n", d);
					SEND_TO_Q("the case, exceptions may be granted.  You will need to petition the staff\r\n", d);
					SEND_TO_Q("member in charge of authorization.  When you are able to log into the mud,\r\n", d);
					SEND_TO_Q("type HELP AUTHORIZATION for the appropriate e-mail address, or contact the\r\n", d);
					SEND_TO_Q("staff member via the game.\r\n", d);
					SEND_TO_Q("\r\nPress ENTER to contine: ", d);
					syslog(0, TRUE, "Login denied: Multiplaying detected for %s [%s]", GET_NAME(d->character), d->host);

					STATE(d) = CON_GOODBYE;
					return;
					}
				if (perform_dupe_check(d))
					return;

				send_motd(d);
				if (!PLR_FLAGGED(d->character, PLR_INVSTART))
					syslog(GET_INVIS_LEV(d->character), TRUE, "%s [%s] has connected.", GET_NAME(d->character), PLR_FLAGGED(d->character, PLR_IPMASK) ? "masked" : d->host);

				/* Check bad passwords */
				if (load_result) {
					sprintf(buf, "\r\n\r\n\007\007\007&1%d LOGIN FAILURE%s SINCE LAST SUCCESSFUL LOGIN.&0\r\n", load_result, (load_result > 1) ? "S" : "");
					SEND_TO_Q(buf, d);
					GET_BAD_PWS(d->character) = 0;
					}

				/* Check previous logon */
				if (d->character->prev_host) {
					sprintf(buf, "Your last%s login was on %6.10s from %s.\r\n", load_result ? " attempted" : "", ctime(&d->character->prev_logon), d->character->prev_host);
					SEND_TO_Q(buf, d);
					}

				SEND_TO_Q("\r\n*** Press ENTER: ", d);
				STATE(d) = CON_RMOTD;
				}
			break;

		case CON_NEWPASSWD:
		case CON_CHPWD_GETNEW:
			if (!*arg || strlen(arg) > MAX_PWD_LENGTH || strlen(arg) < 3 || !str_cmp(arg, GET_PC_NAME(d->character))) {
				SEND_TO_Q("\r\nIllegal password.\r\n", d);
				SEND_TO_Q("Password: ", d);
				return;
				}
			strncpy(GET_PASSWD(d->character), CRYPT(arg, GET_PC_NAME(d->character)), MAX_PWD_LENGTH);
			*(GET_PASSWD(d->character) + MAX_PWD_LENGTH) = '\0';

			SEND_TO_Q("\r\nPlease retype password: ", d);
			if (STATE(d) == CON_NEWPASSWD)
				STATE(d) = CON_CNFPASSWD;
			else
				STATE(d) = CON_CHPWD_VRFY;

			break;

		case CON_CNFPASSWD:
		case CON_CHPWD_VRFY:
			if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) {
				SEND_TO_Q("\r\nPasswords don't match... start over.\r\n", d);
				SEND_TO_Q("Password: ", d);
				if (STATE(d) == CON_CNFPASSWD)
					STATE(d) = CON_NEWPASSWD;
				else
					STATE(d) = CON_CHPWD_GETNEW;
				return;
				}
			echo_on(d);

			if (STATE(d) == CON_CNFPASSWD) {
				SEND_TO_Q("\r\nWould you like a last name (y/N)? ", d);
				STATE(d) = CON_QLAST_NAME;
				}
			else {
				SAVE_CHAR(d->character);
				echo_on(d);
				SEND_TO_Q("\r\nDone.\r\n", d);
				if (GET_LEVEL(d->character) < LVL_APPROVED)
					SEND_TO_Q(AUTH_MESSG, d);

				display_statistics_to_char(d->character);
				SEND_TO_Q(MENU, d);
				STATE(d) = CON_MENU;
				}
			break;

		case CON_QLAST_NAME:		/* Want a last name? */
			if (UPPER(*arg) == 'Y') {
				SEND_TO_Q("\r\nEnter your last name: ", d);
				STATE(d) = CON_SLAST_NAME;
				}
			else if (UPPER(*arg) == 'N') {
				GET_LASTNAME(d->character) = NULL;
				SEND_TO_Q("\r\nWhat is your sex (M/F)? ", d);
				STATE(d) = CON_QSEX;
			/* Please crash_delete here */
				break;
				}
			else
				SEND_TO_Q("\r\nPlease type Yes or No: ", d);
			break;

		case CON_SLAST_NAME:		/* What's yer last name? */
			if (!*arg) {
				SEND_TO_Q("\r\nEnter a last name: ", d);
				return;
				}
			else {
				if ((_parse_name(arg, tmp_name)) || !Valid_Name(tmp_name) || strlen(tmp_name) < 2 || strlen(tmp_name) > MAX_NAME_LENGTH || fill_word(strcpy(buf, tmp_name)) || reserved_word(buf)) {
					SEND_TO_Q("\r\nInvalid last name, please try another.\r\n"
							  "Enter a last name: ", d);
					return;
					}
				if (GET_LASTNAME(d->character))
					free(d->character->player.lastname);

				GET_LASTNAME(d->character) = str_dup(tmp_name);

				sprintf(buf, "\r\nDid I get that right, %s %s (Y/N)? ", d->character->player.name, tmp_name);
				SEND_TO_Q(buf, d);
				STATE(d) = CON_CLAST_NAME;
				}
			break;

		case CON_CLAST_NAME:		/* Wait for conf. of last name    */
			if (UPPER(*arg) == 'Y') {
				SEND_TO_Q("\r\nWhat is your sex (M/F)? ", d);
				STATE(d) = CON_QSEX;
				}
			else if (UPPER(*arg) == 'N') {
				SEND_TO_Q("Okay, what IS it, then? ", d);
				free(d->character->player.lastname);
				d->character->player.lastname = NULL;

				STATE(d) = CON_SLAST_NAME;
				}
			else
				SEND_TO_Q("Please type Yes or No: ", d);
			break;

		case CON_QSEX:		/* query sex of new user         */
			switch (LOWER(*arg)) {
				case 'm':
					d->character->player.sex = SEX_MALE;
					break;
				case 'f':
					d->character->player.sex = SEX_FEMALE;
					break;
				default:
					SEND_TO_Q("That is not a sex..\r\nWhat IS your sex? ", d);
					return;
				}

			SEND_TO_Q("\r\nDo you want color on? ", d);
			STATE(d) = CON_QCOLOR;
			break;

		case CON_QCOLOR:
			switch (LOWER(*arg)) {
				case 'y':
					SET_BIT(PRF_FLAGS(d->character), PRF_COLOR);
					break;
				case 'n':
					break;
				default:
					SEND_TO_Q("Please type YES or NO: ", d);
					return;
				}

			/* We set all Attributes to 1 now because the "races" diverge in creation */
			d->character->real_abils.strength = 1;
			d->character->real_abils.dexterity = 1;
			d->character->real_abils.stamina = 1;
			d->character->real_abils.charisma = 1;
			d->character->real_abils.manipulation = 1;
			d->character->real_abils.appearance = 1;
			d->character->real_abils.perception = 1;
			d->character->real_abils.intelligence = 1;
			d->character->real_abils.wits = 1;

			SEND_TO_Q("\r\nHardcore Character:\r\n", d);
			SEND_TO_Q("  - Permanent death\r\n", d);
			SEND_TO_Q("  - More powerful abilities\r\n", d);
			SEND_TO_Q("  - More clan choices\r\n", d);
			SEND_TO_Q("  - More disciplines\r\n", d);
			SEND_TO_Q("Please consider this carefully!  You can't change your mind if you choose yes.\r\n", d);
			SEND_TO_Q("Do you want your character to be hardcore? ", d);

			STATE(d) = CON_QHARDCORE;
			break;

		case CON_QPREV_HARDCORE:
			switch (LOWER(*arg)) {
				case 'y':
					SEND_TO_Q("\r\nPlease type the name of your former hardcore character: ", d);
					STATE(d) = CON_LOAD_HARDCORE_NAME;
					return;
				case 'n':
					SEND_TO_Q("\r\nPress ENTER to choose status.", d);
					STATE(d) = CON_PROMPT_STATUS;
					return;
				default:
					SEND_TO_Q("Please type YES or NO: ", d);
					return;
				}
			break;

		case CON_LOAD_HARDCORE_NAME:
			if (!*arg) {
				SEND_TO_Q("\r\nEnter a name: ", d);
				return;
				}

			if (!(d->temp_char)) {
				CREATE(d->temp_char, struct char_data, 1);
				clear_char(d->temp_char);
				}
			if ((player_i = load_char(arg, &tmp_store)) > NOBODY)
				store_to_char(&tmp_store, d->temp_char);
			else {
				free(d->temp_char);
				SEND_TO_Q("\r\nThere is no such character.\r\n", d);
				SEND_TO_Q("\r\nPress ENTER to choose status.", d);
				STATE(d) = CON_PROMPT_STATUS;
				return;
				}

			if (!PLR_FLAGGED(d->temp_char, PLR_SLAIN) || PLR_FLAGGED(d->temp_char, PLR_DELETED)) {
				SEND_TO_Q("Unable to load valid hardcore character.\r\n", d);
				SEND_TO_Q("\r\nPress ENTER to choose status.", d);
				STATE(d) = CON_PROMPT_STATUS;
				return;
				}

			SEND_TO_Q("\r\nCharacter loaded.  Password: ", d);
			echo_off(d);
			STATE(d) = CON_LOAD_HARDCORE_PWORD;

			break;

		case CON_LOAD_HARDCORE_PWORD:
			if (!*arg) {
				SEND_TO_Q("\r\nEnter password: ", d);
				return;
				}

			echo_on(d);
			if (strncmp(CRYPT(arg, GET_PASSWD(d->temp_char)), GET_PASSWD(d->temp_char), MAX_PWD_LENGTH)) {
				SEND_TO_Q("\r\nInvalid password.  Hardcore character not loaded.\r\n", d);
				SEND_TO_Q("\r\nPress ENTER to choose status.", d);
				free(d->temp_char);
				STATE(d) = CON_PROMPT_STATUS;
				return;
				}

			if (!validate_autoauthorize(d, GET_EMAIL(d->temp_char), GET_IDNUM(d->temp_char))) {
				SEND_TO_Q("\r\nThe hardcore system was unable to auto-authorize you or verify your hardcore status.\r\n", d);
				SEND_TO_Q("Hardcore character not loaded.\r\n", d);
				SEND_TO_Q("\r\nPress ENTER to choose status.", d);
				free(d->temp_char);
				STATE(d) = CON_PROMPT_STATUS;
				return;
				}

			playing_time = *real_time_passed(d->temp_char->player.time.played, 0);
			i = (playing_time.day * 2) + (playing_time.hours >= 12 ? 2 : 0);
			i += GET_EXPERIENCE(d->temp_char);
			i = MAX(0, MIN(EXP_CAP, i));

			d->character->points.experience = i;
			GET_LEVEL(d->character) = LVL_APPROVED;
			GET_EMAIL(d->character) = str_dup(GET_EMAIL(d->temp_char));
			SET_BIT(PLR_FLAGS(d->temp_char), PLR_DELETED);
			save_char(d->temp_char, NOWHERE);
			free_char(d->temp_char);

			//remove the one xp granted to new chars
			d->character->points.experience -= 1;

			sprintf(buf, "%d experience granted.\r\n", i);
			SEND_TO_Q(buf, d);
			SEND_TO_Q("Previous hardcore character deleted.\r\n", d);
			SEND_TO_Q("\r\nPress ENTER to choose status.", d);
			STATE(d) = CON_PROMPT_STATUS;

			break;

		case CON_QHARDCORE:		/* Decide about being a hardcore player */
			switch (LOWER(*arg)) {
				case 'y':
					SET_BIT(PLR_FLAGS(d->character), PLR_HARDCORE);

					SEND_TO_Q("\r\nDo you have a previously slain hardcore character? ", d);
					STATE(d) = CON_QPREV_HARDCORE;

					return;
				case 'n':
					SEND_TO_Q("Please type YES: ", d);
					return;
				default:
					SEND_TO_Q("Please type YES: ", d);
					return;
				}


		/* This BREAK is left out intentionally */
		case CON_PROMPT_STATUS:

			SEND_TO_Q("\r\nCharacter Status:\r\n", d);
			SEND_TO_Q(" 1. Human    - A focus on skills and abilities; humans are a challenge\r\n", d);
			SEND_TO_Q("               to play but are well-rewarded with skills.\r\n", d);
			SEND_TO_Q(" 2. Vampire  - Undead and scorned by the sun, vampires are split into\r\n", d);
			SEND_TO_Q("               clans with unique powers and ablities.  Each vampire begins\r\n", d);
			SEND_TO_Q("               with a haven, a home free of sunlight.\r\n", d);
			SEND_TO_Q("               You may become a vampire later in the game if you choose Human.\r\n", d);
			SEND_TO_Q(" 3. Werewolf - Gifted by Luna, the Garou are far stronger and fiercer than any\r\n", d);
			SEND_TO_Q("               of nature's creations!  They are thus hardcore-only.\r\n", d);
			SEND_TO_Q("\r\n", d);
			SEND_TO_Q("Choose a number: ", d);

			STATE(d) = CON_CHOOSE_STATUS;
			break;

		case CON_CHOOSE_STATUS:	/* Choose Human/Vampire */
			switch (*arg) {
				case '1':
					break;

				case '2':
					SET_BIT(PLR_FLAGS(d->character), PLR_VAMPIRE);

					SEND_TO_Q("\r\nChoose a clan:\r\n", d);
					for (i = 0; i < NUM_CLANS; i++)
						if (clan[i].can_pick) {
							sprintf(buf, " %s%2d. %-15.15s %s", clan[i].hardcore ? "*" : " ", i+1, clan[i].name, !((i+1)%2) ? "\r\n" : "");
							SEND_TO_Q(buf, d);
							}
					SEND_TO_Q("\r\n* Hardcore character only\r\n", d);
					SEND_TO_Q("Please see our web site for information on each clan.\r\n", d);
					SEND_TO_Q("> ", d);

					STATE(d) = CON_QCLAN;
					return;

				case '3':
					if (!IS_HARDCORE(d->character)) {
						SEND_TO_Q("\r\nYou must be hardcore to be a werewolf!\r\n> ", d);
						return;
						}

					SET_BIT(PLR_FLAGS(d->character), PLR_WEREWOLF);

					SEND_TO_Q("\r\nChoose a Breed (birth form):\r\n", d);
					SEND_TO_Q("  1. Homid\r\n", d);
					SEND_TO_Q("  2. Metis\r\n", d);
					SEND_TO_Q("  3. Lupus\r\n", d);
					SEND_TO_Q("> ", d);

					STATE(d) = CON_BREED_FORM;
					return;

				default:
					SEND_TO_Q("Please choose a number: ", d);
					return;
				}

			STATE(d) = CON_CUSTOMIZE;
			SEND_TO_Q("Would you like to customize your Attributes and Abilities (y/n)? ", d);

			break;

		case CON_BREED_FORM:
			if ((i = atoi(arg)) < 1 || i > 3) {
				SEND_TO_Q("\r\nInvalid choice.\r\n> ", d);
				return;
				}

			GET_BREED(d->character) = i - 1;

			SEND_TO_Q("\r\nChoose an Auspice (phase of the moon under which you were born):\r\n", d);
			SEND_TO_Q("  1. Ragabash (new moon)\r\n", d);
			SEND_TO_Q("  2. Theurge (crescent moon)\r\n", d);
			SEND_TO_Q("  3. Philodox (half moon)\r\n", d);
			SEND_TO_Q("  4. Galliard (gibbous moon)\r\n", d);
			SEND_TO_Q("  5. Ahroun (full moon)\r\n", d);
			SEND_TO_Q("> ", d);

			STATE(d) = CON_AUSPICE;
			break;

		case CON_AUSPICE:
			if ((i = atoi(arg)) < 1 || i > 5) {
				SEND_TO_Q("\r\nInvalid choice.\r\n> ", d);
				return;
				}

			GET_AUSPICE(d->character) = i - 1;

			SEND_TO_Q("\r\nChoose a Tribe:\r\n", d);
			for (i = 0; i < NUM_TRIBES; i++) {
				sprintf(buf, " %2d. %s\r\n", i + 1, tribe[i].name);
				SEND_TO_Q(buf, d);
				}
			SEND_TO_Q("> ", d);

			STATE(d) = CON_TRIBE;
			break;

		case CON_TRIBE:
			if ((i = atoi(arg) - 1) < 0 || i >= NUM_TRIBES) {
				SEND_TO_Q("Invalid choice.\r\n> ", d);
				return;
				}

			GET_REAL_TRIBE(d->character) = i;

			STATE(d) = CON_CUSTOMIZE;
			SEND_TO_Q("Would you like to customize your Attributes and Abilities (y/n)? ", d);

			break;

		case CON_CUSTOMIZE:
			switch (LOWER(*arg)) {
				case 'y':
					STATE(d) = CON_CHOOSE_ATTRIBUTES;
					d->character->player_specials->create_points = 15;
					SEND_TO_Q("Press ENTER to choose Attributes: ", d);
					break;
				case 'n':
					d->character->real_abils.strength = 3;
					d->character->real_abils.dexterity = 3;
					d->character->real_abils.stamina = 2;

					/* Clan Weakness: Nosferatu */
					if (GET_CLAN(d->character) == CLAN_NOSFERATU) {
						d->character->real_abils.charisma = 3;
						d->character->real_abils.manipulation = 4;
						d->character->real_abils.appearance = 0;
						}
					else {
						d->character->real_abils.charisma = 3;
						d->character->real_abils.manipulation = 3;
						d->character->real_abils.appearance = 2;
						}

					d->character->real_abils.perception = 3;
					d->character->real_abils.intelligence = 3;
					d->character->real_abils.wits = 2;

					d->character->player_specials->saved.talents[TALENT_ACTING] = 0;
					d->character->player_specials->saved.talents[TALENT_ALERTNESS] = 1;
					d->character->player_specials->saved.talents[TALENT_ATHLETICS] = 1;
					d->character->player_specials->saved.talents[TALENT_BRAWL] = 1;
					d->character->player_specials->saved.talents[TALENT_DODGE] = 1;
					d->character->player_specials->saved.talents[TALENT_EMPATHY] = 1;
					d->character->player_specials->saved.talents[TALENT_INTIMIDATION] = 1;
					d->character->player_specials->saved.talents[TALENT_LARCENY] = 1;
					d->character->player_specials->saved.talents[TALENT_LEADERSHIP] = 1;
					if (IS_WEREWOLF(d->character))
						d->character->player_specials->saved.talents[TALENT_PRIMAL_URGE] = 2;
					d->character->player_specials->saved.talents[TALENT_SUBTERFUGE] = 0;

					d->character->player_specials->saved.skills[SKILL_ANIMAL_KEN] = 1;
					d->character->player_specials->saved.skills[SKILL_ARCHERY] = 1;
					d->character->player_specials->saved.skills[SKILL_CRAFTS] = 2;
					d->character->player_specials->saved.skills[SKILL_ETIQUETTE] = 1;
					d->character->player_specials->saved.skills[SKILL_HERBALISM] = 1;
					d->character->player_specials->saved.skills[SKILL_MELEE] = 1;
					d->character->player_specials->saved.skills[SKILL_MUSIC] = 1;
					d->character->player_specials->saved.skills[SKILL_PERFORMANCE] = 0;
					d->character->player_specials->saved.skills[SKILL_RIDE] = 1;
					d->character->player_specials->saved.skills[SKILL_STEALTH] = 1;
					d->character->player_specials->saved.skills[SKILL_SURVIVAL] = 0;

					d->character->player_specials->saved.knowledges[KNOWLEDGE_ACADEMICS] = 1;
					if (IS_WEREWOLF(d->character))
						d->character->player_specials->saved.knowledges[KNOWLEDGE_ENIGMAS] = 2;
					d->character->player_specials->saved.knowledges[KNOWLEDGE_HEARTH_WISDOM] = 1;
					d->character->player_specials->saved.knowledges[KNOWLEDGE_INVESTIGATION] = 1;
					d->character->player_specials->saved.knowledges[KNOWLEDGE_LAW] = 0;
					d->character->player_specials->saved.knowledges[KNOWLEDGE_LINGUISTICS] = 1;
					d->character->player_specials->saved.knowledges[KNOWLEDGE_MEDICINE] = 1;
					d->character->player_specials->saved.knowledges[KNOWLEDGE_OCCULT] = 1;
					d->character->player_specials->saved.knowledges[KNOWLEDGE_POLITICS] = 1;
					d->character->player_specials->saved.knowledges[KNOWLEDGE_SCIENCE] = 2;
					d->character->player_specials->saved.knowledges[KNOWLEDGE_SENESCHAL] = 0;

					/* See also: CON_CHOOSE_ABILITIES */
					if (IS_VAMPIRE(d->character)) {
						STATE(d) = CON_CHOOSE_VIRTUES;
						d->character->player_specials->create_points = 7;
						d->character->points.conscience = 1;
						d->character->points.self_control = 1;
						d->character->points.courage = 1;
						SEND_TO_Q("\r\nPress ENTER to choose Virtues: ", d);
						break;
						}
					else if (IS_WEREWOLF(d->character)) {
						STATE(d) = CON_ADVANTAGES_W;
						d->character->points.humanity = 10;
						assign_werewolf_advantages(d);
						d->character->player_specials->create_points = 7;
						SEND_TO_Q("\r\nPress ENTER to choose Advantages: ", d);
						break;
						}
					else /* is_human */ {
						d->character->points.max_willpower = number(2, 5);
						d->character->points.humanity = 10;
						STATE(d) = CON_APPEARANCE;
						SEND_TO_Q("\r\nPress ENTER to finish character creation: ", d);
						break;
						}

					break;
				default:
					SEND_TO_Q("Please type YES or NO: ", d);
					return;
				}

			break;

		case CON_QCLAN:
			if ((i = atoi(arg) - 1) < 0 || i >= NUM_CLANS) {
				SEND_TO_Q("Invalid choice.\r\n> ", d);
				return;
				}
			if (!clan[i].can_pick) {
				SEND_TO_Q("You can't pick that clan!\r\n", d);
				return;
				}
			if (clan[i].hardcore && !IS_HARDCORE(d->character)) {
				SEND_TO_Q("You must be a Hardcore character to choose that clan!\r\n> ", d);
				return;
				}
			GET_REAL_CLAN(d->character) = i;

			/* Clan Weakness: Nosferatu */
			if (GET_CLAN(d->character) == CLAN_NOSFERATU)
				d->character->real_abils.appearance = 0;

			STATE(d) = CON_CUSTOMIZE;
			SEND_TO_Q("Would you like to customize your Attributes and Abilities (y/n)? ", d);

			break;

		case CON_QHEIGHT:
			if ((i = atoi(arg)) < 1 || i > 5) {
				SEND_TO_Q("Invalid choice.\r\n> ", d);
				return;
				}
			switch (i) {
				case 1:
					if (d->character->player.sex == SEX_MALE)		d->character->player.height = number(60, 64);
					else								d->character->player.height = number(53, 56);
					break;
				case 2:
					if (d->character->player.sex == SEX_MALE)		d->character->player.height = number(64, 66);
					else								d->character->player.height = number(56, 59);
					break;
				case 3:
					if (d->character->player.sex == SEX_MALE)		d->character->player.height = number(66, 70);
					else								d->character->player.height = number(59, 62);
					break;
				case 4:
					if (d->character->player.sex == SEX_MALE)		d->character->player.height = number(70, 74);
					else								d->character->player.height = number(62, 64);
					break;
				case 5:
					if (d->character->player.sex == SEX_MALE)		d->character->player.height = number(74, 78);
					else								d->character->player.height = number(64, 66);
					break;
				default:
					SEND_TO_Q("Invalid choice.\r\n> ", d);
					return;
				}

			SEND_TO_Q("\r\nHow would you describe your weight:\r\n", d);
			SEND_TO_Q(" 1. Anorexic\r\n", d);
			SEND_TO_Q(" 2. Scrawny\r\n", d);
			SEND_TO_Q(" 3. Healthy\r\n", d);
			SEND_TO_Q(" 4. Well-fed\r\n", d);
			SEND_TO_Q(" 5. Obese\r\n", d);
			SEND_TO_Q("> ", d);
			STATE(d) = CON_QWEIGHT;
			break;

		case CON_QWEIGHT:
			i = atoi(arg);
			switch (i) {
				case 1:
					if (d->character->player.sex == SEX_MALE)	d->character->player.weight = number(90, 100);
					else							d->character->player.weight = number(80, 90);
					break;
				case 2:
					if (d->character->player.sex == SEX_MALE)	d->character->player.weight = number(100, 120);
					else							d->character->player.weight = number(90, 105);
					break;
				case 3:
					if (d->character->player.sex == SEX_MALE)	d->character->player.weight = number(120, 160);
					else							d->character->player.weight = number(105, 130);
					break;
				case 4:
					if (d->character->player.sex == SEX_MALE)	d->character->player.weight = number(160, 200);
					else							d->character->player.weight = number(130, 175);
					break;
				case 5:
					if (d->character->player.sex == SEX_MALE)	d->character->player.weight = number(200, 240);
					else							d->character->player.weight = number(175, 200);
					break;
				default:
					SEND_TO_Q("Invalid choice.\r\n> ", d);
					return;
				}

			SEND_TO_Q("\r\nDescribe your complexions:\r\n", d);
			for (i = 0; i < NUM_SKINS; i++) {
				sprintf(buf, "%2d. %s\r\n", i+1, skin_colors[i]);
				SEND_TO_Q(buf, d);
				}
			SEND_TO_Q("> ", d);
			STATE(d) = CON_QSKIN;

			break;

		case CON_QSKIN:
			if ((i = atoi(arg)) < 1 || i > NUM_SKINS) {
				SEND_TO_Q("Invalid choice.\r\n> ", d);
				return;
				}

			GET_SKIN(d->character) = i - 1;

			SEND_TO_Q("\r\nWhat color is your hair:\r\n", d);
			for (i = 0; i < NUM_HAIRS; i++) {
				sprintf(buf, "%2d. %s\r\n", i+1, hair_colors[i]);
				SEND_TO_Q(buf, d);
				}
			SEND_TO_Q("> ", d);
			STATE(d) = CON_QHAIR;

			break;

		case CON_QHAIR:
			if ((i = atoi(arg)) < 1 || i > NUM_HAIRS) {
				SEND_TO_Q("Invalid choice.\r\n> ", d);
				return;
				}

			GET_HAIR(d->character) = i - 1;

			SEND_TO_Q("\r\nWhat color are your eyes:\r\n", d);
			for (i = 0; i < NUM_EYES; i++) {
				sprintf(buf, "%2d. %s\r\n", i+1, eye_colors[i]);
				SEND_TO_Q(buf, d);
				}
			SEND_TO_Q("> ", d);
			STATE(d) = CON_QEYES;
			break;

		case CON_QEYES:
			if ((i = atoi(arg)) < 1 || i > NUM_EYES) {
				SEND_TO_Q("Invalid choice.\r\n> ", d);
				return;
				}

			GET_EYES(d->character) = i - 1;

			d->character->player_specials->create_points = GET_LINGUISTICS(d->character) + 1;
			if (d->character->player_specials->create_points > 0) {
				sprintf(buf, "\r\nSelect %d Languages (by number):\r\n", d->character->player_specials->create_points);
				SEND_TO_Q(buf, d);
				*buf = '\0';
				for (i = 0; i < NUM_LANGS; i++)
					if (i != LANG_LATIN && i != LANG_FERAL_SPEECH && i != LANG_HIGH_TONGUE)
						sprintf(buf + strlen(buf), " %d. %s\r\n", i + 1, langs[i]);
				SEND_TO_Q(buf, d);
				SEND_TO_Q("> ", d);
				}
			else
				SEND_TO_Q("\r\n*** Press ENTER: ", d);
			STATE(d) = CON_LANGUAGE;
			break;

		case CON_LANGUAGE:
		case CON_LANGUAGE_MENU:
			if (d->character->player_specials->create_points > 0) {
				if ((i = atoi(arg)) < 1 || i > NUM_LANGS || (i - 1) == LANG_LATIN || (i - 1) == LANG_FERAL_SPEECH || (i - 1) == LANG_HIGH_TONGUE) {
					SEND_TO_Q("Invalid choice.\r\n> ", d);
					return;
					}
				if (IS_SET(GET_LANGUAGES(d->character), LANGUAGE_BIT(i-1))) {
					if (STATE(d) == CON_LANGUAGE_MENU)
						SEND_TO_Q("You can't remove a language!\r\n", d);
					else {
						REMOVE_BIT(GET_LANGUAGES(d->character), LANGUAGE_BIT(i - 1));
						d->character->player_specials->create_points += 1;
						sprintf(buf, "Language %s removed.\r\n", langs[i - 1]);
						SEND_TO_Q(buf, d);
						}
					}
				else {
					/* Speaking always defaults to the first language chosen */
					if (!GET_LANGUAGES(d->character))
						SET_SPEAKING(d->character) = i - 1;
					SET_BIT(GET_LANGUAGES(d->character), LANGUAGE_BIT(i - 1));
					d->character->player_specials->create_points -= 1;
					sprintf(buf, "Language %s added.\r\n", langs[i - 1]);
					SEND_TO_Q(buf, d);
					}

				if (d->character->player_specials->create_points > 0) {
					SEND_TO_Q("> ", d);
					return;
					}
				}

			if (STATE(d) == CON_LANGUAGE_MENU) {
				display_statistics_to_char(d->character);
				SEND_TO_Q(MENU, d);
				STATE(d) = CON_MENU;
				break;
				}

			/* Check for autoauth */
			if (LVL_APPROVED > 1 && GET_LEVEL(d->character) < LVL_APPROVED) {
				SEND_TO_Q("\r\n", d);
				SEND_TO_Q(" AUTHORIZATION\r\n", d);
				SEND_TO_Q("EmpireMUD requires characters to be authorized to utilize all of its features.\r\n", d);
				SEND_TO_Q("This helps promote fair play and equal opportunity for all players.  So that\r\n", d);
				SEND_TO_Q("our players are not inconvenienced, we have a system for automatically\r\n", d);
				SEND_TO_Q("authorizing people.  Only one authorized character is allowed per person.\r\n", d);
				SEND_TO_Q(" To be authorized, you need:\r\n", d);
				SEND_TO_Q("  * a valid e-mail address\r\n", d);
				SEND_TO_Q("  * to be able to reply to an e-mail within a few days\r\n", d);
				SEND_TO_Q(" Please make sure:\r\n", d);
				SEND_TO_Q("  * if you already have an authorized character, it must be deleted first -\r\n", d);
				SEND_TO_Q("    you may do that now, while waiting at this menu\r\n", d);
				SEND_TO_Q("  * if you're on a friend's computer and your friend has an authorized\r\n", d);
				SEND_TO_Q("    character, auto-authorization will probably fail\r\n", d);
				SEND_TO_Q("\r\nDo you want to autoauthorize (y/n): ", d);

				STATE(d) = CON_AUTOAUTH;
				}
			else {
				SEND_TO_Q("\r\n*** Press ENTER: ", d);
				STATE(d) = CON_FINISH_CREATION;
				}

			break;

		case CON_QEMAIL:
			if (!*arg || !strstr(arg, "@")) {
				SEND_TO_Q("You must supply a valid e-mail address, containing an @.\r\n> ", d);
				return;
				}

			if (!validate_autoauthorize(d, arg, -1)) {
				SEND_TO_Q("\r\n AUTO-AUTHORIZATION FAILED\r\n", d);
				SEND_TO_Q("EmpireMUD failed to automatically authorize you for one of the reasons listed\r\n", d);
				SEND_TO_Q("below.  You will need to send an e-mail to the administration requesting that\r\n", d);
				SEND_TO_Q("your character be authorized.  The current address is listed when you type\r\n", d);
				SEND_TO_Q("HELP AUTORIZATION from within the mud.\r\n", d);
				SEND_TO_Q("Reasons for autoauthorize to fail:\r\n", d);
				SEND_TO_Q(" * another character from the same IP is currently logged in\r\n", d);
				SEND_TO_Q(" * another character has an identical e-mail address\r\n", d);
				}
			else {
				SEND_TO_Q("\r\n AUTO-AUTHORIZATION SUCCESSFUL\r\n", d);
				SEND_TO_Q("You will be sent an e-mail within the next few days.  You MUST respond to this\r\n", d);
				SEND_TO_Q("e-mail or your character will be unauthorized.  If the e-mail cannot be\r\n", d);
				SEND_TO_Q("delivered, even if it's because of an error in your mail system, you will be\r\n", d);
				SEND_TO_Q("unauthorized.  If this happens, you will be notified via mudmail.  You may\r\n", d);
				SEND_TO_Q("also type HELP AUTHORIZATION from within the mud to obtain the e-mail address\r\n", d);
				SEND_TO_Q("for the administration if you need to contact them.\r\n", d);
				SEND_TO_Q(" * You may only have 1 authorized character\r\n", d);
				}

			SEND_TO_Q("\r\n*** Press ENTER: ", d);
			STATE(d) = CON_FINISH_CREATION;
			break;

		case CON_AUTOAUTH:
			switch (LOWER(*arg)) {
				case 'y':
					SEND_TO_Q("\r\nEnter your full e-mail address: ", d);
					STATE(d) = CON_QEMAIL;
					return;
				case 'n':
					break;
				default:
					SEND_TO_Q("Please type YES or NO: ", d);
					return;
				}

		/* there is no break here because autoauth links back to here */
		case CON_FINISH_CREATION:

			if (GET_PFILEPOS(d->character) < 0)
				GET_PFILEPOS(d->character) = create_entry(GET_PC_NAME(d->character));
			/* Now GET_NAME() will work properly. */
			if (GET_LEVEL(d->character) == 0)
				GET_LEVEL(d->character) = 1;
			init_char(d->character);
			SAVE_CHAR(d->character);
			send_motd(d);
			SEND_TO_Q("\r\n*** Press ENTER: ", d);
			STATE(d) = CON_RMOTD;

			syslog(0, TRUE, "NEW: %s [%s]", GET_NAME(d->character), d->host);

			break;

		case CON_CHOOSE_ATTRIBUTES:
			/*
			 * This is very simple: if buf1 is nothing, it simply repeats the
			 * output.  Otherwise, it makes the change requested and displays
			 * the statistics.
			 */

			if (*arg) {
				two_arguments(arg, buf, buf1);
				if (is_abbrev(buf, "add")) {
					if (d->character->player_specials->create_points <= 0) {
						SEND_TO_Q("\r\nYou have no more Attribute points.\r\n", d);
						*buf1 = '\0';
						}
					else
						add = TRUE;
					}
				else if (is_abbrev(buf, "subtract"))
					subtract = TRUE;
				else if (is_abbrev(buf, "help")) {
					SEND_TO_Q("\r\nAttributes:\r\n", d);
					SEND_TO_Q(" Strength     - Amount you can carry, Damage with melee weapons\r\n", d);
					SEND_TO_Q(" Dexterity    - Ability to attack/dodge\r\n", d);
					SEND_TO_Q(" Stamina      - Ability to absorb damage\r\n", d);
					SEND_TO_Q(" Charisma     - Social interactions and abilities\r\n", d);
					SEND_TO_Q(" Manipulation - Forcing tasks upon others\r\n", d);
					SEND_TO_Q(" Appearance   - Looks, Visual abilities\r\n", d);
					SEND_TO_Q(" Perception   - Noticing things, Seeing through abilities\r\n", d);
					SEND_TO_Q(" Intelligence - Calling upon knowledge\r\n", d);
					SEND_TO_Q(" Wits         - Fast thinking\r\n", d);
					SEND_TO_Q("\r\nPress ENTER to contine: ", d);
					break;
					}
				else if (is_abbrev(buf, "done")) {
					if (d->character->player_specials->create_points > 0)
						SEND_TO_Q("\r\nYou still have points left to assign.\r\n", d);
					else {
						STATE(d) = CON_CHOOSE_ABILITIES;
						d->character->player_specials->create_points = 27;
						SEND_TO_Q("\r\nPress ENTER to choose Abilities: ", d);
						break;
						}
					}
				else
					*buf1 = '\0';
				}
			else
				*buf1 = '\0';

			/*
			 * Determine current Attributes
			 * Clan Weakness: Nosferatu
			 *  There is a special clause for Appearance which states that it
			 *  counts it as 1 at a minimum, this is merely for catalog purposes
			 *  as the Appearance Trait MAY be zero.
			 */
			physical = d->character->real_abils.strength + d->character->real_abils.dexterity + d->character->real_abils.stamina;
			social = d->character->real_abils.charisma + d->character->real_abils.manipulation + MAX(1, d->character->real_abils.appearance);
			mental = d->character->real_abils.perception + d->character->real_abils.intelligence + d->character->real_abils.wits;

			/* Modify Attributes: add or subtract */
			Attribute_Modify("strength", d->character->real_abils.strength, physical, social, mental);
			Attribute_Modify("dexterity", d->character->real_abils.dexterity, physical, social, mental);
			Attribute_Modify("stamina", d->character->real_abils.stamina, physical, social, mental);
			Attribute_Modify("charisma", d->character->real_abils.charisma, social, physical, mental);
			Attribute_Modify("manipulation", d->character->real_abils.manipulation, social, physical, mental);

			/* Clan Weakness: Nosferatu */
			if (GET_CLAN(d->character) != CLAN_NOSFERATU)
				Attribute_Modify("appearance", d->character->real_abils.appearance, social, physical, mental);
			Attribute_Modify("perception", d->character->real_abils.perception, mental, physical, social);
			Attribute_Modify("intelligence", d->character->real_abils.intelligence, mental, physical, social);
			Attribute_Modify("wits", d->character->real_abils.wits, mental, physical, social);

			SEND_TO_Q("\r\nAttributes:\r\n", d);
			display_attributes(d->character, d->character, TRUE);
			SEND_TO_Q("\r\n", d);

			sprintf(buf, " Points remaining: %d\r\n", d->character->player_specials->create_points);
			SEND_TO_Q(buf, d);

			SEND_TO_Q(" You must assign 7 points to one column, 5 to another, and 3 to the last.\r\n", d);
			SEND_TO_Q(" One initial point is given for free in all Attributes.\r\n", d);

			/* Clan Weakness: Nosferatu */
			if (GET_CLAN(d->character) == CLAN_NOSFERATU)
				SEND_TO_Q(" * You may not raise your Appearance.\r\n", d);

			SEND_TO_Q("Commands: add <attribute> - Adds a point to any Attribute\r\n", d);
			SEND_TO_Q("          sub <attribute> - Removes a point from any Attribute\r\n", d);
			SEND_TO_Q("          help            - Quick reference to Attributes\r\n", d);
			SEND_TO_Q("          done            - Finish Attribute assigments\r\n", d);
			SEND_TO_Q("> ", d);
			break;

		case CON_CHOOSE_ABILITIES:
			/*
			 * This is very simple: if buf1 is nothing, it simply repeats the
			 * output.  Otherwise, it makes the change requested and displays
			 * the skills.
			 */

			if (*arg) {
				two_arguments(arg, buf, buf1);
				if (is_abbrev(buf, "add")) {
					if (d->character->player_specials->create_points <= 0) {
						SEND_TO_Q("\r\nYou have no more Ability points.\r\n", d);
						*buf1 = '\0';
						}
					else
						add = TRUE;
					}
				else if (is_abbrev(buf, "subtract"))
					subtract = TRUE;
				else if (is_abbrev(buf, "help")) {
					SEND_TO_Q("\r\nAbilities:\r\n", d);
					SEND_TO_Q(" Acting        - Putting on a show\r\n", d);
					SEND_TO_Q(" Alertness     - Aware of surroundings\r\n", d);
					SEND_TO_Q(" Athletics     - Grand feats, Throwing\r\n", d);
					SEND_TO_Q(" Brawl         - Fighting barehanded or with claws\r\n", d);
					SEND_TO_Q(" Dodge         - Avoiding hits\r\n", d);
					SEND_TO_Q(" Empathy       - Sensing emotions/truths in others\r\n", d);
					SEND_TO_Q(" Intimidation  - Controlling/threatening others\r\n", d);
					SEND_TO_Q(" Larceny       - Stealing, Breaking and entering\r\n", d);
					SEND_TO_Q(" Leadership    - Controlling/leading others\r\n", d);
					SEND_TO_Q(" Primal-Urge   - Link to the wolves\r\n", d);
					SEND_TO_Q(" Subterfuge    - Lying, Cheating\r\n", d);
					SEND_TO_Q(" Animal Ken    - Animal-related tasks\r\n", d);
					SEND_TO_Q(" Archery       - Ranged combat\r\n", d);
					SEND_TO_Q(" Crafts        - Building, Forging\r\n", d);
					SEND_TO_Q(" Etiquette     - General politeness\r\n", d);
					SEND_TO_Q(" Herbalism     - Finding herbs\r\n", d);
					SEND_TO_Q(" Melee         - Hand-to-hand combat\r\n", d);
					SEND_TO_Q(" Music         - Singing\r\n", d);
					SEND_TO_Q(" Performance   - Performing\r\n", d);
					SEND_TO_Q(" Ride          - Riding an animal\r\n", d);
					SEND_TO_Q(" Stealth       - Moving quietly\r\n", d);
					SEND_TO_Q(" Survival      - Stealth in the wilderness\r\n", d);
					SEND_TO_Q(" Academics     - Schooling, Reading\r\n", d);
					SEND_TO_Q(" Enigmas       - Solving riddles\r\n", d);
					SEND_TO_Q(" Hearth Wisdom - General Knowledge\r\n", d);
					SEND_TO_Q(" Investigation - Finding things/information\r\n", d);
					SEND_TO_Q(" Law           - Knowledge of the laws\r\n", d);
					SEND_TO_Q(" Linguistics   - Knowledge of languages\r\n", d);
					SEND_TO_Q(" Medicine      - Ability to heal using herbs\r\n", d);
					SEND_TO_Q(" Occult        - Knowledge of the supernatural\r\n", d);
					SEND_TO_Q(" Politics      - Ability to run an empire\r\n", d);
					SEND_TO_Q(" Science       - Ability to use herbs\r\n", d);
					SEND_TO_Q(" Seneschal     - Ability to run a manor\r\n", d);
					SEND_TO_Q("\r\nPress ENTER to contine: ", d);
					break;
					}
				else if (is_abbrev(buf, "done")) {
					if (d->character->player_specials->create_points > 0)
						SEND_TO_Q("\r\nYou still have points left to assign.\r\n", d);
					else {
						if (IS_VAMPIRE(d->character)) {
							STATE(d) = CON_CHOOSE_VIRTUES;
							d->character->player_specials->create_points = 7;
							d->character->points.conscience = 1;
							d->character->points.self_control = 1;
							d->character->points.courage = 1;
							SEND_TO_Q("\r\nPress ENTER to choose Virtues: ", d);
							break;
							}
						else if (IS_WEREWOLF(d->character)) {
							STATE(d) = CON_ADVANTAGES_W;
							d->character->points.humanity = 10;
							assign_werewolf_advantages(d);
							d->character->player_specials->create_points = 7;
							SEND_TO_Q("\r\nPress ENTER to choose Advantages: ", d);
							break;
							}
						else /* is_human */ {
							d->character->points.max_willpower = number(2, 5);
							d->character->points.humanity = 10;
							STATE(d) = CON_APPEARANCE;
							SEND_TO_Q("\r\nPress ENTER to finish character creation: ", d);
							break;
							}
						break;
						}
					}
				else
					*buf1 = '\0';
				}
			else
				*buf1 = '\0';

			/* Determine current Abilities */
			for (i = 0, talents = 0; i < NUM_ABILITIES; i++)
				talents += d->character->player_specials->saved.talents[i];
			for (i = 0, skills = 0; i < NUM_ABILITIES; i++)
				skills += d->character->player_specials->saved.skills[i];
			for (i = 0, knowledges = 0; i < NUM_ABILITIES; i++)
				knowledges += d->character->player_specials->saved.knowledges[i];

			/* Modify Abilities: add or subtract */
			/* Talents */
			Ability_Modify("acting", d->character->player_specials->saved.talents[TALENT_ACTING], talents, skills, knowledges);
			Ability_Modify("alertness", d->character->player_specials->saved.talents[TALENT_ALERTNESS], talents, skills, knowledges);
			Ability_Modify("athletics", d->character->player_specials->saved.talents[TALENT_ATHLETICS], talents, skills, knowledges);
			Ability_Modify("brawl", d->character->player_specials->saved.talents[TALENT_BRAWL], talents, skills, knowledges);
			Ability_Modify("dodge", d->character->player_specials->saved.talents[TALENT_DODGE], talents, skills, knowledges);
			Ability_Modify("empathy", d->character->player_specials->saved.talents[TALENT_EMPATHY], talents, skills, knowledges);
			Ability_Modify("intimidation", d->character->player_specials->saved.talents[TALENT_INTIMIDATION], talents, skills, knowledges);
			Ability_Modify("larceny", d->character->player_specials->saved.talents[TALENT_LARCENY], talents, skills, knowledges);
			Ability_Modify("leadership", d->character->player_specials->saved.talents[TALENT_LEADERSHIP], talents, skills, knowledges);
			Ability_Modify("primal-urge", d->character->player_specials->saved.talents[TALENT_PRIMAL_URGE], talents, skills, knowledges);
			Ability_Modify("subterfuge", d->character->player_specials->saved.talents[TALENT_SUBTERFUGE], talents, skills, knowledges);

			Ability_Modify("animal ken", d->character->player_specials->saved.skills[SKILL_ANIMAL_KEN], skills, talents, knowledges);
			Ability_Modify("archery", d->character->player_specials->saved.skills[SKILL_ARCHERY], skills, talents, knowledges);
			Ability_Modify("crafts", d->character->player_specials->saved.skills[SKILL_CRAFTS], skills, talents, knowledges);
			Ability_Modify("etiquette", d->character->player_specials->saved.skills[SKILL_ETIQUETTE], skills, talents, knowledges);
			Ability_Modify("herbalism", d->character->player_specials->saved.skills[SKILL_HERBALISM], skills, talents, knowledges);
			Ability_Modify("melee", d->character->player_specials->saved.skills[SKILL_MELEE], skills, talents, knowledges);
			Ability_Modify("music", d->character->player_specials->saved.skills[SKILL_MUSIC], skills, talents, knowledges);
			Ability_Modify("performance", d->character->player_specials->saved.skills[SKILL_PERFORMANCE], skills, talents, knowledges);
			Ability_Modify("ride", d->character->player_specials->saved.skills[SKILL_RIDE], skills, talents, knowledges);
			Ability_Modify("stealth", d->character->player_specials->saved.skills[SKILL_STEALTH], skills, talents, knowledges);
			Ability_Modify("survival", d->character->player_specials->saved.skills[SKILL_SURVIVAL], skills, talents, knowledges);

			Ability_Modify("academics", d->character->player_specials->saved.knowledges[KNOWLEDGE_ACADEMICS], knowledges, talents, skills);
			Ability_Modify("enigmas", d->character->player_specials->saved.knowledges[KNOWLEDGE_ENIGMAS], knowledges, talents, skills);
			Ability_Modify("hearth wisdom", d->character->player_specials->saved.knowledges[KNOWLEDGE_HEARTH_WISDOM], knowledges, talents, skills);
			Ability_Modify("investigation", d->character->player_specials->saved.knowledges[KNOWLEDGE_INVESTIGATION], knowledges, talents, skills);
			Ability_Modify("law", d->character->player_specials->saved.knowledges[KNOWLEDGE_LAW], knowledges, talents, skills);
			Ability_Modify("linguistics", d->character->player_specials->saved.knowledges[KNOWLEDGE_LINGUISTICS], knowledges, talents, skills);
			Ability_Modify("medicine", d->character->player_specials->saved.knowledges[KNOWLEDGE_MEDICINE], knowledges, talents, skills);
			Ability_Modify("occult", d->character->player_specials->saved.knowledges[KNOWLEDGE_OCCULT], knowledges, talents, skills);
			Ability_Modify("politics", d->character->player_specials->saved.knowledges[KNOWLEDGE_POLITICS], knowledges, talents, skills);
			Ability_Modify("science", d->character->player_specials->saved.knowledges[KNOWLEDGE_SCIENCE], knowledges, talents, skills);
			Ability_Modify("seneschal", d->character->player_specials->saved.knowledges[KNOWLEDGE_SENESCHAL], knowledges, talents, skills);

			SEND_TO_Q("\r\nAbilities:\r\n", d);
			display_abilities(d->character, d->character);
			SEND_TO_Q("\r\n", d);

			sprintf(buf, " Points remaining: %d\r\n", d->character->player_specials->create_points);
			SEND_TO_Q(buf, d);

			SEND_TO_Q(" You must assign 13 points to one column, 9 to another, and 5 to the last.\r\n", d);
			SEND_TO_Q("Commands: add <ability> - Adds a point to any Ability\r\n", d);
			SEND_TO_Q("          sub <ability> - Removes a point from any Ability\r\n", d);
			SEND_TO_Q("          help          - Quick reference to Abilities\r\n", d);
			SEND_TO_Q("          done          - Finish Ability assigments\r\n", d);
			SEND_TO_Q("> ", d);
			break;

		case CON_CHOOSE_VIRTUES:
			/*
			 * This is very simple: if buf1 is nothing, it simply repeats the
			 * output.  Otherwise, it makes the change requested and displays
			 * the virtues.
			 */

			if (*arg) {
				two_arguments(arg, buf, buf1);
				if (is_abbrev(buf, "add")) {
					if (d->character->player_specials->create_points <= 0) {
						SEND_TO_Q("\r\nYou have no more Virtue points.\r\n", d);
						*buf1 = '\0';
						}
					else
						add = TRUE;
					}
				else if (is_abbrev(buf, "subtract"))
					subtract = TRUE;
				else if (is_abbrev(buf, "help")) {
					SEND_TO_Q("\r\nVirtues:\r\n", d);
					SEND_TO_Q(" Conscience   - A moral sense of right and wrong.\r\n", d);
					SEND_TO_Q(" Self-Control - One's control over the Beast within.\r\n", d);
					SEND_TO_Q(" Courage      - The ability to face one's fears.\r\n", d);
					SEND_TO_Q("\r\nPress ENTER to contine: ", d);
					break;
					}
				else if (is_abbrev(buf, "done")) {
					if (d->character->player_specials->create_points > 0)
						SEND_TO_Q("\r\nYou still have points left to assign.\r\n", d);
					else {
						GET_MAX_WILLPOWER(d->character) = GET_COURAGE(d->character);
						GET_HUMANITY(d->character) = GET_CONSCIENCE(d->character) + GET_SELF_CONTROL(d->character);
						STATE(d) = CON_CHOOSE_DISCIPLINES;
						d->character->player_specials->create_points = 4;
						SEND_TO_Q("\r\nPress ENTER to choose Disciplines: ", d);
						break;
						}
					}
				else
					*buf1 = '\0';
				}
			else
				*buf1 = '\0';

			if (*buf1 && is_abbrev(buf1, "conscience")) {
				if (add) {
					if (d->character->points.conscience >= 5)
						SEND_TO_Q("\r\nYou may not begin with any Virtue greater than 5.\r\n", d);
					else {
						d->character->points.conscience += 1;
						d->character->player_specials->create_points -= 1;
						}
					}
				else if (subtract) {
					if (d->character->points.conscience <= 1)
						SEND_TO_Q("\r\nYou may not lower an Virtue below 1.\r\n", d);
					else {
						d->character->points.conscience -= 1;
						d->character->player_specials->create_points += 1;
						}
					}
				}

			else if (*buf1 && is_abbrev(buf1, "self-control")) {
				if (add) {
					if (d->character->points.self_control >= 5)
						SEND_TO_Q("\r\nYou may not begin with any Virtue greater than 5.\r\n", d);
					else {
						d->character->points.self_control += 1;
						d->character->player_specials->create_points -= 1;
						}
					}
				else if (subtract) {
					if (d->character->points.self_control <= 1)
						SEND_TO_Q("\r\nYou may not lower an Virtue below 1.\r\n", d);
					else {
						d->character->points.self_control -= 1;
						d->character->player_specials->create_points += 1;
						}
					}
				}

			else if (*buf1 && is_abbrev(buf1, "courage")) {
				if (add) {
					if (d->character->points.courage >= 5)
						SEND_TO_Q("\r\nYou may not begin with any Virtue greater than 5.\r\n", d);
					else {
						d->character->points.courage += 1;
						d->character->player_specials->create_points -= 1;
						}
					}
				else if (subtract) {
					if (d->character->points.courage <= 1)
						SEND_TO_Q("\r\nYou may not lower an Virtue below 1.\r\n", d);
					else {
						d->character->points.courage -= 1;
						d->character->player_specials->create_points += 1;
						}
					}
				}

			SEND_TO_Q("\r\nVirtues:\r\n", d);

			*buf = '\0';
			strcat(buf, "Conscience:   ");
			for (i = 0; i < d->character->points.conscience; i++)
				strcat(buf, "*");
			strcat(buf, "\r\n");
			strcat(buf, "Self-Control: ");
			for (i = 0; i < d->character->points.self_control; i++)
				strcat(buf, "*");
			strcat(buf, "\r\n");
			strcat(buf, "Courage:      ");
			for (i = 0; i < d->character->points.courage; i++)
				strcat(buf, "*");
			strcat(buf, "\r\n");

			SEND_TO_Q(strcat(buf, "\r\n"), d);

			sprintf(buf, " Points remaining: %d\r\n", d->character->player_specials->create_points);
			SEND_TO_Q(buf, d);

			SEND_TO_Q("Commands: add <virtue> - Adds a point to any Virtue\r\n", d);
			SEND_TO_Q("          sub <virtue> - Removes a point from any Virtue\r\n", d);
			SEND_TO_Q("          help         - Quick reference to Virtues\r\n", d);
			SEND_TO_Q("          done         - Finish Virtue assigments\r\n", d);
			SEND_TO_Q("> ", d);
			break;

		case CON_CHOOSE_DISCIPLINES:
			/*
			 * This is very simple: if arg is nothing, it simply repeats the
			 * output.  Otherwise, it makes the change requested and displays
			 * the virtues.
			 */

			if (*arg) {
				/* Find if they chose a discipline */
				for (i = 0; i < NUM_DISCS; i++)
					if ((clan[GET_CLAN(d->character)].disc[0] == i || clan[GET_CLAN(d->character)].disc[1] == i || clan[GET_CLAN(d->character)].disc[2] == i) && is_abbrev(arg, disc[i].name))
						break;
				/* Parse the input */
				if (is_abbrev(arg, "done")) {
					if (d->character->player_specials->create_points > 0)
						SEND_TO_Q("\r\nYou still have points left to assign.\r\n", d);
					else {
						if (GET_THAUMATURGY(d->character)) {
							STATE(d) = CON_PATH;
							SEND_TO_Q("\r\nPress ENTER to choose a Path: ", d);
							}
						else {
							STATE(d) = CON_ADVANTAGES_V;
							GET_GENERATION(d->character) = 12;
							d->character->player_specials->create_points = 7;
							SEND_TO_Q("\r\nPress ENTER to choose Advantages: ", d);
							}
						break;
						}
					}
				else if (is_abbrev(arg, "help")) {
					SEND_TO_Q("\r\nDisciplines:\r\n", d);
					SEND_TO_Q(" Animalism     - Control over animals.\r\n", d);
					SEND_TO_Q(" Auspex        - Heightened senses and awareness.\r\n", d);
					SEND_TO_Q(" Celerity      - Improved dexterity and speed.\r\n", d);
					SEND_TO_Q(" Chimerstry    - Mastery over illusions.\r\n", d);
					SEND_TO_Q(" Dementation   - Control over the sanity of others.\r\n", d);
					SEND_TO_Q(" Dominate      - Command over fragile minds.\r\n", d);
					SEND_TO_Q(" Fortitude     - Supernatural defense.\r\n", d);
					SEND_TO_Q(" Mortis        - Mastery over the dead.\r\n", d);
					SEND_TO_Q(" Obfuscate     - Clouding the minds of others.\r\n", d);
					SEND_TO_Q(" Obtenebration - Commanding the darkness.\r\n", d);
					SEND_TO_Q(" Potence       - Supernatural strength.\r\n", d);
					SEND_TO_Q(" Presence      - Enticing the minds of others.\r\n", d);
					SEND_TO_Q(" Protean       - Powerful form-changing.\r\n", d);
					SEND_TO_Q(" Quietus       - The art of combat and assassination.\r\n", d);
					SEND_TO_Q(" Serpentis     - Mastery and power of the serpent.\r\n", d);
					SEND_TO_Q(" Thaumaturgy   - Blood-fueled magic.\r\n", d);
					SEND_TO_Q(" Vicissitude   - Mastery over flesh and bone.\r\n", d);

					SEND_TO_Q("\r\nPress ENTER to contine: ", d);
					break;
					}
				else if (is_abbrev(arg, "reset")) {
					for (i = 0; i < NUM_DISCS; i++)
						GET_REAL_DISC(d->character, i) = 0;
					d->character->player_specials->create_points = 4;
					}
				else if (i == NUM_DISCS) {
					SEND_TO_Q("\r\nInvalid Discipline.\r\n", d);
					}
				else if (d->character->player_specials->create_points <= 0)
					SEND_TO_Q("\r\nYou don't have any points left.\r\n", d);
				else {
					GET_REAL_DISC(d->character, i) += 1;
					d->character->player_specials->create_points -= 1;
					}
				}

			SEND_TO_Q("\r\nDisciplines:\r\n", d);

			*buf = '\0';
			sprintf(buf + strlen(buf), "%13.13s - ", disc[(int) clan[(int) GET_CLAN(d->character)].disc[0]].name);
			for (i = 0; i < 10; i++)
				if (GET_DISC(d->character, (int) clan[(int) GET_CLAN(d->character)].disc[0]) > i)
					strcat(buf, "*");
			strcat(buf, "\r\n");
			sprintf(buf + strlen(buf), "%13.13s - ", disc[(int) clan[(int) GET_CLAN(d->character)].disc[1]].name);
			for (i = 0; i < 10; i++)
				if (GET_DISC(d->character, (int) clan[(int) GET_CLAN(d->character)].disc[1]) > i)
					strcat(buf, "*");
			strcat(buf, "\r\n");
			sprintf(buf + strlen(buf), "%13.13s - ", disc[(int) clan[(int) GET_CLAN(d->character)].disc[2]].name);
			for (i = 0; i < 10; i++)
				if (GET_DISC(d->character, (int) clan[(int) GET_CLAN(d->character)].disc[2]) > i)
					strcat(buf, "*");
			strcat(buf, "\r\n");

			SEND_TO_Q(strcat(buf, "\r\n"), d);

			sprintf(buf, " Points remaining: %d\r\n", d->character->player_specials->create_points);
			SEND_TO_Q(buf, d);

			SEND_TO_Q("Commands: <discipline> - Adds a point to any Discipline listed\r\n", d);
			SEND_TO_Q("          reset        - Resets the Disciplines and points\r\n", d);
			SEND_TO_Q("          help         - Quick reference to Disciplines\r\n", d);
			SEND_TO_Q("          done         - Finish Discipline assigments\r\n", d);
			SEND_TO_Q("> ", d);
			break;

		case CON_PATH:
			if (*arg) {
				/* Find if they chose a path */
				for (i = 0; i < NUM_PATHS; i++)
					if (is_abbrev(arg, path[i].name))
						break;

				if (i < NUM_PATHS) {
					GET_PRIMARY_PATH(d->character) = i;
					GET_REAL_PATH(d->character, (int) GET_REAL_PRIMARY_PATH(d->character)) = GET_THAUMATURGY(d->character);
					STATE(d) = CON_ADVANTAGES_V;
					GET_GENERATION(d->character) = 12;
					d->character->player_specials->create_points = 7;
					SEND_TO_Q("\r\nPress ENTER to choose Advantages: ", d);
					break;
					}
				else
					SEND_TO_Q("\r\nInvalid choice.\r\n>", d);
				}

			SEND_TO_Q("\r\nChoose your Primary Path:\r\n", d);
			SEND_TO_Q(" Rego Vitae     - The Path of Blood\r\n", d);
			SEND_TO_Q(" Creo Ignem     - The Path of Fire\r\n", d);
			SEND_TO_Q(" Rego Motus     - The Path of Movement\r\n", d);
			SEND_TO_Q(" Rego Tempestas - The Path of Storms\r\n", d);
			SEND_TO_Q(" Rego Aquam     - The Path of Water\r\n", d);
			SEND_TO_Q(" Rego Elementum - The Path of Elements\r\n", d);
			SEND_TO_Q(" Way of Levinbolt\r\n", d);
			SEND_TO_Q(" Path of Warding\r\n", d);
			SEND_TO_Q("> ", d);
			break;

		case CON_CHOOSE_AGE:
			if ((i = atoi(arg)) < 16 || i > 80) {
				SEND_TO_Q("\r\nYou must choose an age between 16 and 80:  ", d);
				return;
				}

			GET_APPARENT_AGE(d->character) = i;

			STATE(d) = CON_APPEARANCE;
			SEND_TO_Q("\r\nPress ENTER to finish character creation: ", d);

			break;

		case CON_ADVANTAGES_V:
			/*
			 * This is very simple: if arg is nothing, it simply repeats the
			 * output.  Otherwise, it makes the change requested and displays
			 * the virtues.
			 */

			if (*arg) {
				/* Parse the input */
				if (is_abbrev(arg, "done")) {
					if (d->character->player_specials->create_points > 0)
						SEND_TO_Q("\r\nYou still have points left to assign.\r\n", d);
					else {
						STATE(d) = CON_CHOOSE_AGE;
						SEND_TO_Q("\r\nHow old does your character appear (16 to 80): ", d);
						break;
						}
					}
				else if (is_abbrev(arg, "help")) {
					SEND_TO_Q("\r\nAdvantages:\r\n", d);
					SEND_TO_Q(" Humanity      - Remnants of the mortal self and freedom from the Beast within.\r\n", d);
					SEND_TO_Q("                 Humanity is based upon Conscience and Self-Control.\r\n", d);
					SEND_TO_Q(" Willpower     - Mental stability and resistance to Delirium and Dominate.\r\n", d);
					SEND_TO_Q("                 Willpower is based upon Courage.\r\n", d);
					SEND_TO_Q(" Generation    - The thinning of one's blood marked by distance from Caine.\r\n", d);
					SEND_TO_Q("                 Vampires start at Generation 12 unless points are spent here.\r\n", d);
					SEND_TO_Q("\r\nPress ENTER to contine: ", d);
					break;
					}
				else if (is_abbrev(arg, "reset")) {
					GET_MAX_WILLPOWER(d->character) = GET_COURAGE(d->character);
					GET_HUMANITY(d->character) = GET_CONSCIENCE(d->character) + GET_SELF_CONTROL(d->character);
					GET_GENERATION(d->character) = 12;
					d->character->player_specials->create_points = 7;
					}
				else if (d->character->player_specials->create_points <= 0)
					SEND_TO_Q("\r\nYou don't have any points left.\r\n", d);
				else if (is_abbrev(arg, "add humanity")) {
					if (GET_HUMANITY(d->character) >= 10)
						SEND_TO_Q("You may not have more than ten Humanity.\r\n", d);
					else {
						GET_HUMANITY(d->character) += 1;
						d->character->player_specials->create_points -= 1;
						}
					}
				else if (is_abbrev(arg, "add willpower")) {
					if (GET_MAX_WILLPOWER(d->character) >= 10)
						SEND_TO_Q("You may not have more than ten Willpower.\r\n", d);
					else {
						GET_MAX_WILLPOWER(d->character) += 1;
						d->character->player_specials->create_points -= 1;
						}
					}
				else if (is_abbrev(arg, "add generation")) {
					if (GET_GENERATION(d->character) <= 7)
						SEND_TO_Q("You may not begin lower than seventh generation.\r\n", d);
					else {
						GET_GENERATION(d->character) -= 1;
						d->character->player_specials->create_points -= 1;
						}
					}
				}

			SEND_TO_Q("\r\nAdvantages:\r\n", d);

			*buf = '\0';
			strcat(buf, " Humanity:   ");
			for (i = 0; i < GET_HUMANITY(d->character); i++)
				strcat(buf, "*");
			strcat(buf, "\r\n");
			strcat(buf, " Willpower:  ");
			for (i = 0; i < GET_MAX_WILLPOWER(d->character); i++)
				strcat(buf, "*");
			strcat(buf, "\r\n");
			sprintf(buf + strlen(buf), " Generation: %dth\r\n", GET_GENERATION(d->character));

			SEND_TO_Q(strcat(buf, "\r\n"), d);

			sprintf(buf, " Points remaining: %d\r\n", d->character->player_specials->create_points);
			SEND_TO_Q(buf, d);

			SEND_TO_Q("Commands: add <advantage> - Adds a point to any Advantage\r\n", d);
			SEND_TO_Q("              reset       - Resets the Advantages and points\r\n", d);
			SEND_TO_Q("              help        - Quick reference to Advantages\r\n", d);
			SEND_TO_Q("              done        - Finish Advantage assigments\r\n", d);
			SEND_TO_Q("> ", d);
			break;

		case CON_ADVANTAGES_W:
			/*
			 * This is very simple: if arg is nothing, it simply repeats the
			 * output.  Otherwise, it makes the change requested and displays
			 * the advantages.
			 */

			if (*arg) {
				/* Parse the input */
				if (is_abbrev(arg, "done")) {
					if (d->character->player_specials->create_points > 0)
						SEND_TO_Q("\r\nYou still have points left to assign.\r\n", d);
					else {
						GET_GNOSIS(d->character) = GET_MAX_GNOSIS(d->character);
						GET_RAGE(d->character) = GET_MAX_RAGE(d->character);
						GET_WILLPOWER(d->character) = GET_MAX_WILLPOWER(d->character);

						STATE(d) = CON_APPEARANCE;
						SEND_TO_Q("\r\nPress ENTER to finish character creation: ", d);
						break;
						}
					}
				else if (is_abbrev(arg, "reset")) {
					assign_werewolf_advantages(d);
					d->character->player_specials->create_points = 7;
					}
				else if (is_abbrev(arg, "help")) {
					SEND_TO_Q("\r\nAdvantages:\r\n", d);
					SEND_TO_Q(" Gnosis        - Gnosis is the focus of one's spiritual energy, the opposite\r\n", d);
					SEND_TO_Q("                 of Rage, but equally important.\r\n", d);
					SEND_TO_Q(" Rage          - Rage is the focus of all the anger within a person.  It has\r\n", d);
					SEND_TO_Q("                 both positive and negative affects on one's being, as well as\r\n", d);
					SEND_TO_Q("                 the things shredded around him.\r\n", d);
					SEND_TO_Q(" Willpower     - Mental stability and resistance to Dominate.\r\n", d);
					SEND_TO_Q("\r\nPress ENTER to contine: ", d);
					break;
					}
				else if (d->character->player_specials->create_points <= 0)
					SEND_TO_Q("\r\nYou don't have any points left.\r\n", d);
				else if (is_abbrev(arg, "add gnosis")) {
					if (GET_MAX_GNOSIS(d->character) >= 10)
						SEND_TO_Q("You may not have more than ten Gnosis.\r\n", d);
					else {
						GET_MAX_GNOSIS(d->character) += 1;
						d->character->player_specials->create_points -= 1;
						}
					}
				else if (is_abbrev(arg, "add willpower")) {
					if (GET_MAX_WILLPOWER(d->character) >= 10)
						SEND_TO_Q("You may not have more than ten Willpower.\r\n", d);
					else {
						GET_MAX_WILLPOWER(d->character) += 1;
						d->character->player_specials->create_points -= 1;
						}
					}
				else if (is_abbrev(arg, "add rage")) {
					if (GET_MAX_RAGE(d->character) >= 10)
						SEND_TO_Q("You may not have more than ten Rage.\r\n", d);
					else {
						GET_MAX_RAGE(d->character) += 1;
						d->character->player_specials->create_points -= 1;
						}
					}
				}

			SEND_TO_Q("\r\nAdvantages:\r\n", d);

			*buf = '\0';
			strcat(buf, " Gnosis:     ");
			for (i = 0; i < GET_MAX_GNOSIS(d->character); i++)
				strcat(buf, "*");
			strcat(buf, "\r\n");
			strcat(buf, " Rage:       ");
			for (i = 0; i < GET_MAX_RAGE(d->character); i++)
				strcat(buf, "*");
			strcat(buf, "\r\n");
			strcat(buf, " Willpower:  ");
			for (i = 0; i < GET_MAX_WILLPOWER(d->character); i++)
				strcat(buf, "*");
			strcat(buf, "\r\n");

			SEND_TO_Q(strcat(buf, "\r\n"), d);

			sprintf(buf, " Points remaining: %d\r\n", d->character->player_specials->create_points);
			SEND_TO_Q(buf, d);

			SEND_TO_Q("Commands: add <advantage> - Adds a point to any Advantage\r\n", d);
			SEND_TO_Q("              reset       - Resets the Advantages and points\r\n", d);
			SEND_TO_Q("              help        - Quick reference to Advantages\r\n", d);
			SEND_TO_Q("              done        - Finish Advantage assigments\r\n", d);
			SEND_TO_Q("> ", d);
			break;

		case CON_APPEARANCE:
			SEND_TO_Q("\r\nChoose a starting equipment set:\r\n", d);
			for (i = 1, j = 0; str_cmp(new_eq[i].name, "\n"); i++) {
				sprintf(buf, " %2d. %-15.15s %s", i, new_eq[i].name, !(++j % 3) ? "\r\n" : "");
				SEND_TO_Q(buf, d);
				}
			SEND_TO_Q("\r\n> ", d);

			STATE(d) = CON_QEQUIPMENT;
			break;

		case CON_QEQUIPMENT:
			i = atoi(arg);

			/* Determine top choice # */
			for (j = 1; str_cmp(new_eq[j].name, "\n"); j++);

			if (i < 1 || i >= j) {
				SEND_TO_Q("\r\nInvalid choice.\r\n> ", d);
				return;
				}
			GET_NEW_EQ_SET(d->character) = i;

			SEND_TO_Q("\r\nHow tall are you:\r\n", d);
			SEND_TO_Q(" 1. Short\r\n", d);
			SEND_TO_Q(" 2. Below Average\r\n", d);
			SEND_TO_Q(" 3. Average\r\n", d);
			SEND_TO_Q(" 4. Above Average\r\n", d);
			SEND_TO_Q(" 5. Tall\r\n", d);
			SEND_TO_Q("> ", d);
			STATE(d) = CON_QHEIGHT;

			break;

		case CON_RMOTD:		/* read CR after printing motd   */
			if (PLR_FLAGGED(d->character, PLR_IPMASK))
				strcpy(d->host, "masked");

			if (GET_LEVEL(d->character) < LVL_APPROVED)
				SEND_TO_Q(AUTH_MESSG, d);

			display_statistics_to_char(d->character);
			SEND_TO_Q(MENU, d);
			STATE(d) = CON_MENU;
			break;

		case CON_MENU:		/* get selection from main menu  */
			switch (LOWER(*arg)) {
				case 'l':
					SEND_TO_Q("Goodbye.\r\n", d);
					STATE(d) = CON_CLOSE;
					break;
				case 'e':
					if (PLR_FLAGGED(d->character, PLR_SLAIN)) {
						SEND_TO_Q(hardcore_slain_msg, d);
						SEND_TO_Q("\r\n", d);
						return;
						}
					if (!check_multiplaying(d)) {
						SEND_TO_Q("\r\n\033[31mAccess Denied: Multiplaying detected\033[0m\r\n", d);
						SEND_TO_Q("There is already someone logged in from the same IP address as you.  If you\r\n", d);
						SEND_TO_Q("are controlling that character, you must remove it from the game before this\r\n", d);
						SEND_TO_Q("character can enter.  Rarely, computers may share IP addresses.  If this is\r\n", d);
						SEND_TO_Q("the case, exceptions may be granted.  You will need to petition the staff\r\n", d);
						SEND_TO_Q("member in charge of authorization.  When you are able to log into the mud,\r\n", d);
						SEND_TO_Q("type HELP AUTHORIZATION for the appropriate e-mail address, or contact the\r\n", d);
						SEND_TO_Q("staff member via the game.\r\n", d);
						SEND_TO_Q("\r\nPress ENTER to contine: ", d);
						syslog(0, TRUE, "Login denied: Multiplaying detected for %s [%s]", GET_NAME(d->character), d->host);

						STATE(d) = CON_GOODBYE;
						return;
						}

					/* This will make sure vampires are safe */
					if ((load_result = enter_player_game(d, 1)) != -2) {
						send_to_char(WELC_MESSG, d->character);
						act("$n has entered the game.", TRUE, d->character, 0, 0, TO_ROOM);

						STATE(d) = CON_PLAYING;
						/* We can see who's new because they have a new EQ set */
						if (GET_NEW_EQ_SET(d->character) != 0) {
							do_start(d->character);
							send_to_char(START_MESSG, d->character);
							}
						look_at_room(d->character);
						if (has_mail(GET_IDNUM(d->character)))
							send_to_char("&1You have mail waiting.&0\r\n", d->character);
						d->has_prompt = 0;
						}
					else
						return;
					break;
				case 'b':
					page_string(d, background, 0);
					STATE(d) = CON_RMOTD;
					break;
				case 'c':
					SEND_TO_Q("\r\nEnter your old password: ", d);
					echo_off(d);
					STATE(d) = CON_CHPWD_GETOLD;
					break;
				case 'd':
					SEND_TO_Q("\r\nEnter your password for verification: ", d);
					echo_off(d);
					STATE(d) = CON_DELCNF1;
					break;
				case 'n':
					if (GET_LINGUISTICS(d->character) >= att_max(d->character))
						SEND_TO_Q("Your Linguistics is already at maximum.\r\n", d);
					else if (GET_LINGUISTICS(d->character) == 0 && GET_EXPERIENCE(d->character) < ABILITY_COST_NEW)
						SEND_TO_Q("You don't have enough experience to buy a point of Linguistics.\r\n", d);
					else if (GET_LINGUISTICS(d->character) > 0 && GET_EXPERIENCE(d->character) < ABILITY_COST * (GET_LINGUISTICS(d->character) + 1))
						SEND_TO_Q("You don't have enough experience to buy a point of Linguistics.\r\n", d);
					else {
						if (GET_LINGUISTICS(d->character) == 0)
							GET_EXPERIENCE(d->character) -= ABILITY_COST_NEW;
						else
							GET_EXPERIENCE(d->character) -= ABILITY_COST * (GET_LINGUISTICS(d->character) + 1);
						d->character->player_specials->saved.knowledges[KNOWLEDGE_LINGUISTICS] += 1;

						SEND_TO_Q("\r\nSelect a Language (by number):\r\n", d);
						*buf = '\0';
						for (i = 0; i < NUM_LANGS; i++)
							if (i != LANG_LATIN && i != LANG_FERAL_SPEECH && i != LANG_HIGH_TONGUE && !IS_SET(GET_LANGUAGES(d->character), LANGUAGE_BIT(i)))
								sprintf(buf + strlen(buf), " %d. %s\r\n", i + 1, langs[i]);
						SEND_TO_Q(buf, d);
						SEND_TO_Q("> ", d);

						d->character->player_specials->create_points = 1;
						STATE(d) = CON_LANGUAGE_MENU;
						break;
						}
					break;
				case 'm':
					if (GET_LOYALTY(d->character) == 0 || real_empire(GET_LOYALTY(d->character)) < 0) {
						SEND_TO_Q("\r\nYou are not a member of an empire!\r\n> ", d);
						return;
						}
					if (GET_LOYALTY(d->character) != GET_IDNUM(d->character)) {
						SEND_TO_Q("\r\nYou are not the leader of the empire!\r\n> ", d);
						return;
						}
					d->empire = create_empire_editor(real_empire(GET_LOYALTY(d->character)));
					STATE(d) = CON_EMPIRE_EDIT;
					send_empire_edit_menu(d);
					break;

				default:
					SEND_TO_Q("\r\nThat's not a menu choice!\r\n", d);
					if (GET_LEVEL(d->character) < LVL_APPROVED)
						SEND_TO_Q(AUTH_MESSG, d);
					display_statistics_to_char(d->character);
					SEND_TO_Q(MENU, d);
					break;
				}
			break;

		case CON_CHPWD_GETOLD:
			if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) {
				echo_on(d);
				SEND_TO_Q("\r\nIncorrect password.\r\n", d);

				if (GET_LEVEL(d->character) < LVL_APPROVED)
					SEND_TO_Q(AUTH_MESSG, d);
				display_statistics_to_char(d->character);
				SEND_TO_Q(MENU, d);
				STATE(d) = CON_MENU;
				}
			else {
				SEND_TO_Q("\r\nEnter a new password: ", d);
				STATE(d) = CON_CHPWD_GETNEW;
				}
			return;

		case CON_DELCNF1:
			echo_on(d);
			if (strncmp(CRYPT(arg, GET_PASSWD(d->character)), GET_PASSWD(d->character), MAX_PWD_LENGTH)) {
				SEND_TO_Q("\r\nIncorrect password.\r\n", d);

				if (GET_LEVEL(d->character) < LVL_APPROVED)
					SEND_TO_Q(AUTH_MESSG, d);
				display_statistics_to_char(d->character);
				SEND_TO_Q(MENU, d);
				STATE(d) = CON_MENU;
				}
			else {
				SEND_TO_Q("\r\nYOU ARE ABOUT TO DELETE THIS CHARACTER PERMANENTLY.\r\nARE YOU ABSOLUTELY SURE?\r\n\r\nPlease type \"yes\" to confirm: ", d);
				STATE(d) = CON_DELCNF2;
				}
			break;

		case CON_DELCNF2:
			if (!str_cmp(arg, "yes")) {
				if (PLR_FLAGGED(d->character, PLR_FROZEN)) {
					SEND_TO_Q("You try to kill yourself, but the ice stops you.\r\n", d);
					SEND_TO_Q("Character not deleted.\r\n\r\n", d);
					STATE(d) = CON_CLOSE;
					return;
					}
				if (GET_LEVEL(d->character) < LVL_TOP)
					SET_BIT(PLR_FLAGS(d->character), PLR_DELETED);

				/* Check that empire */
				if ((emp = real_empire(GET_LOYALTY(d->character))) != -1) {
					GET_LOYALTY(d->character) = 0;
					GET_RANK(d->character) = 0;
					empire[emp].members--;
					if (empire[emp].members == 0)
						delete_empire(emp);
					}

				SAVE_CHAR(d->character);
				Crash_delete_file(GET_NAME(d->character));
				sprintf(buf, "Character '%s' deleted!\r\nGoodbye.\r\n", GET_NAME(d->character));
				SEND_TO_Q(buf, d);
				syslog(0, TRUE, "DEL: %s (lev %d) has self-deleted.", GET_NAME(d->character), GET_LEVEL(d->character));
				STATE(d) = CON_CLOSE;
				return;
				}
			else {
				SEND_TO_Q("\r\nCharacter not deleted.\r\n", d);

				if (GET_LEVEL(d->character) < LVL_APPROVED)
					SEND_TO_Q(AUTH_MESSG, d);
				display_statistics_to_char(d->character);
				SEND_TO_Q(MENU, d);
				STATE(d) = CON_MENU;
				}
			break;

		case CON_GOODBYE:		/* take an ENTER and then quit */
			SEND_TO_Q("Goodbye.\r\n", d);
			STATE(d) = CON_CLOSE;
			break;

		/*
		 * It's possible, if enough pulses are missed, to kick someone off
		 * while they are at the password prompt. We'll just defer to let
		 * the game_loop() axe them.
		 */
		case CON_CLOSE:
			break;

		default:
			log("SYSERR: Nanny: illegal state of con'ness (%d) for '%s'; closing connection.", STATE(d), d->character ? GET_NAME(d->character) : "<unknown>");
			STATE(d) = CON_DISCONNECT;	/* Safest to do. */
			break;
		}
	}