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

#include "merc.h"
#include "interp.h"
#include "telnet.h"
#include "recycle.h"
#include "tables.h"
#include "vnums.h"
#include "special.h"

Proto(bool check_playing, (Descriptor *, const char *));
Proto(bool check_reconnect, (Descriptor *, const char *, bool));

Do_Fun(nanny_help)
{
	HelpData *pHelp;
	Buffer *output;
	char argall[MAX_INPUT_LENGTH], argone[MAX_INPUT_LENGTH];
	int level;

	output = new_buf();

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

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

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

		if (level > get_trust(ch) || pHelp->category != HELP_CREATION)
			continue;

		if (is_name(argall, pHelp->keyword))
		{

			bprint(output, help_text(pHelp->text));
			break;
		}
	}

	if (!pHelp)
		chprintlnf(ch, "{cNo help on %s.{x", argall);
	else
		sendpage(ch, buf_string(output));
	free_buf(output);
}

Nanny_Fun(HANDLE_CON_GET_TERM)
{
	switch (argument[0])
	{
		case 'y':
		case 'Y':
			SetBit(d->desc_flags, DESC_COLOR);
			d_println(d, "{?Color {cEnabled...{x");
			break;
		case 'n':
		case 'N':
			RemBit(d->desc_flags, DESC_COLOR);
			d_println(d, "Color Disabled...");
			break;
		case 't':
		case 'T':
			d_printlnf(d,
					   NEWLINE "This text should be " ESC "[%d;%dmGREEN"
					   CL_DEFAULT "." NEWLINE "This text should be " ESC
					   "[%d;%dmRED" CL_DEFAULT ".", CL_BRIGHT, FG_GREEN,
					   CL_BRIGHT, FG_RED);
			d_println(d, NEWLINE "Did you see color? (Y)es, (N)o, (T)est: ");
			return;
		default:
			d_println(d, "Please answer (Y)es, (N)o, (T)est: ");
			return;
	}
	show_greeting(d);
	d->connected = CON_GET_NAME;
}

Nanny_Fun(HANDLE_CON_GET_NAME)
{
	CharData *ch;
	bool fOld;
	NameProfile *nl;

	Proto(NameProfile * profile_lookup, (int));
	Proto(char *genname, (NameProfile *));

	if (NullStr(argument))
	{
		d_println(d,
				  "You can't have a blank name, type 'list' to list name generator profiles,"
				  NEWLINE
				  "<#> to generate a list of names based on profile number '#'"
				  NEWLINE
				  "'quit' to disconnect, or type your characters name - try again.");
		d_print(d, mud_info.login_prompt);
		return;
	}
	else if (!str_cmp(argument, "quit"))
	{
		close_socket(d);
		return;
	}
	else if (!str_cmp(argument, "list"))
	{
		int count = 0;

		d_println(d, "{RNAME GENERATOR PROFILES{x");
		for (nl = name_profile_first; nl; nl = nl->next)
		{
			d_printlnf(d, "{W%2d{c> %s{x", ++count, nl->title);
		}
		d_println(d, "{cEnter a profile number to view generated names:{x");
		return;
	}
	else if (is_number(argument))
	{
		int count = 0, i;
		int profile_num = atoi(argument);
		Column Cd;

		if (profile_num < 1 || profile_num > top_name_profile
			|| (nl = profile_lookup(profile_num)) == NULL)
		{
			d_printlnf(d, "{cInvalid profile number {W%d{c.{x", profile_num);
			d_println(d, "{RNAME GENERATOR PROFILES{x");
			for (nl = name_profile_first; nl; nl = nl->next)
			{
				d_printlnf(d, "{W%2d{c> %s{x", ++count, nl->title);
			}
			d_println(d,
					  "{cEnter a profile number to view generated names:{x");
			return;
		}

		set_cols(&Cd, NULL, 4, COLS_DESC, d);
		d_printlnf(d, "{RNAME GENERATOR - %s{x", strupper(nl->title));
		for (i = 0; i < 60; i++)
		{
			print_cols(&Cd, capitalize(genname(nl)));
		}
		cols_nl(&Cd);

		d_println(d, "{cPlease enter your name:{x");
		d_println(d,
				  "{c(to view a list of profiles, type 'list' or enter a profile number){x");
		return;
	}
	else if (!check_parse_name(argument))
	{
		d_println(d, "{cIllegal name, try another.{x" NEWLINE "Name: {x");
		return;
	}

	fOld = load_char_obj(d, argument);
	ch = d->character;

	if (IsSet(ch->act, PLR_DENY))
	{
		logf("Denying access to %s@%s.", argument, d->host);
		d_println(d, "{cYou are {Rdenied{c access.{x");
		close_socket(d);
		return;
	}

	if (check_ban(d->host, BAN_PERMIT) && !IsSet(ch->act, PLR_PERMIT))
	{
		d_println(d, "{cYour site has been {Rbanned{c from this mud.{x");
		close_socket(d);
		return;
	}

	if (check_reconnect(d, argument, false))
	{
		fOld = true;
	}
	else
	{
		if (IsSet(mud_info.mud_flags, MUD_WIZLOCK) && !IsImmortal(ch))
		{
			d_println(d, "{cThe game is {Rwizlocked{c.{x");
			close_socket(d);
			return;
		}
	}

	if (fOld)
	{

		d_write(d, echo_off_str, 0);
		d_println(d, "{cPassword: {x");
		d->connected = CON_GET_OLD_PASSWORD;
		d->wrong_password_count = 0;
		return;
	}
	else
	{

		if (IsSet(mud_info.mud_flags, MUD_NEWLOCK))
		{
			d_println(d, "{cThe game is {Rnewlocked{c.{x");
			close_socket(d);
			return;
		}

		if (check_ban(d->host, BAN_NEWBIES))
		{
			d_println(d, "{cNew players are not allowed from your site.{x");
			close_socket(d);
			return;
		}

		d_printlnf(d, "{cDid I get that right, %s ({WY{c/{WN{c)? {x",
				   capitalize(argument));
		d->connected = CON_CONFIRM_NEW_NAME;
		return;
	}
}

Nanny_Fun(HANDLE_CON_GET_OLD_PASSWORD)
{
	CharData *ch = CH(d);

	if (str_casecmp(crypt(argument, ch->pcdata->pwd), ch->pcdata->pwd))
	{
		d_print(d, "{cWrong password");
		if (++d->wrong_password_count < 3)
		{
			d_println(d, " - try again.");
			d_println(d, "{cPassword: {x");
			d_println(d, echo_off_str);
			return;
		}
		else
		{
			d_println(d, ".");
		}
		close_socket(d);
		return;
	}

	d_write(d, echo_on_str, 0);

	if (check_playing(d, ch->name))
		return;

	if (check_reconnect(d, ch->name, true))
		return;

	new_wiznet(ch, d->host, WIZ_SITES, true, get_trust(ch),
			   "$N@$t has connected.");

	set_desc_flags(d);
	if (IsImmortal(ch))
	{
		d_print(d,
				"{cWould you like to login ({WW{c)izinvis, ({WI{c)ncognito, "
				"({WB{c)oth, or ({WN{c)ormal?{x" NEWLINE
				"{c(Include a level number to specify what level){x");
		d->connected = CON_GET_WIZ;
	}
	else
	{
		do_function(ch, &nanny_help, "motd");
		d->connected = CON_READ_MOTD;
	}
}

Nanny_Fun(HANDLE_CON_GET_WIZ)
{
	CharData *ch = CH(d);
	char arg[MIL];
	int wizlevel = Range(LEVEL_IMMORTAL, ch->level, MAX_LEVEL);

	argument = one_argument(argument, arg);

	if (!NullStr(argument) && is_number(argument))
		wizlevel = Range(LEVEL_IMMORTAL, atoi(argument), MAX_LEVEL);
	switch (tolower(*arg))
	{
		case 'w':
			ch->invis_level = wizlevel;
			ch->incog_level = 0;
			break;
		case 'i':
			ch->incog_level = wizlevel;
			ch->invis_level = 0;
			break;
		case 'b':
			ch->incog_level = wizlevel;
			ch->invis_level = wizlevel;
			break;
		default:
		case 'n':
			ch->incog_level = 0;
			ch->invis_level = 0;
			break;
	}
	do_function(ch, &nanny_help, "imotd");
	d->connected = CON_READ_MOTD;
}

Nanny_Fun(HANDLE_CON_BREAK_CONNECT)
{
	CharData *ch = CH(d);
	Descriptor *d_old, *pd_next;

	switch (*argument)
	{
		case 'y':
		case 'Y':
			for (d_old = descriptor_first; d_old != NULL; d_old = pd_next)
			{
				pd_next = d_old->next;
				if (d_old == d || d_old->character == NULL)
					continue;

				if (str_cmp(ch->name, CH(d_old)->name))
					continue;

				close_socket(d_old);
			}
			if (check_reconnect(d, ch->name, true))
				return;
			d_println(d, "{cReconnect attempt failed.{x" NEWLINE "{cName: ");
			if (d->character != NULL)
			{
				free_char(d->character);

				d->character = NULL;
			}
			d->connected = CON_GET_NAME;
			break;

		case 'n':
		case 'N':
			d_println(d, "{cName: {x");
			if (d->character != NULL)
			{
				free_char(d->character);

				d->character = NULL;
			}
			d->connected = CON_GET_NAME;
			break;

		default:
			d_println(d, "{cPlease type ({WY{c)es or ({WN{c)o: {x");
			break;
	}
}

Nanny_Fun(HANDLE_CON_CONFIRM_NEW_NAME)
{
	CharData *ch = CH(d);

	switch (*argument)
	{
		case 'y':
		case 'Y':
			d_printlnf(d,
					   "{cWelcome to {R%s{c!" NEWLINE
					   "{cGive me a password for {W%s{c: {x", mud_info.name,
					   ch->name);
			d_write(d, echo_off_str, 0);
			d->connected = CON_GET_NEW_PASSWORD;
			break;

		case 'n':
		case 'N':
			d_println(d, "{cOk, what IS it, then? {x");
			free_char(d->character);

			d->character = NULL;
			d->connected = CON_GET_NAME;
			break;

		default:
			d_println(d, "{cPlease type ({WY{c)es or ({WN{c)o: {x");
			break;
	}
}

Nanny_Fun(HANDLE_CON_GET_NEW_PASSWORD)
{
	CharData *ch = CH(d);
	const char *pwdnew;
	const char *p;

	if (strlen(argument) < 5)
	{
		d_println(d,
				  "{cPassword must be at least five characters long." NEWLINE
				  "{cPassword: {x");
		return;
	}

	pwdnew = crypt(argument, ch->name);
	for (p = pwdnew; *p != '\0'; p++)
	{
		if (*p == '~')
		{
			d_println(d,
					  "{cNew password not acceptable, try again." NEWLINE
					  "{cPassword: {x");
			return;
		}
	}

	replace_str(&ch->pcdata->pwd, pwdnew);
	d_println(d, "{cPlease retype password: {x");
	d->connected = CON_CONFIRM_NEW_PASSWORD;
}

void send_race_info(Descriptor * d)
{
	RaceData *race;

	d_println(d, NEWLINE "{cThe following races are available:{x");
	d_printlnf(d, "{W%s{x", draw_line(CH(d), "{w-{W-", 0));
	for (race = race_first; race; race = race->next)
	{
		if (!race->pc_race)
			continue;
		d_printlnf(d, "{c\t%s{x", race->name);
	}
	d_printlnf(d, "{W%s", draw_line(CH(d), "{w-{W-", 0));
	d_printlnf(d, "{cFor more information, use help. (i.e. 'help %s'){x",
			   race_first->name);
}

Nanny_Fun(HANDLE_CON_CONFIRM_NEW_PASSWORD)
{
	CharData *ch = CH(d);

	if (str_casecmp(crypt(argument, ch->pcdata->pwd), ch->pcdata->pwd))
	{
		d_println(d,
				  "{cPasswords don't match.{x" NEWLINE
				  "{cRetype password: {x");
		d->connected = CON_GET_NEW_PASSWORD;
		return;
	}

	d_write(d, echo_on_str, 0);
	send_race_info(d);
	d_println(d, "{cWhat is your race? {x");
	d->connected = CON_GET_NEW_RACE;
}

Nanny_Fun(HANDLE_CON_GET_NEW_RACE)
{
	CharData *ch = CH(d);
	char arg[MAX_INPUT_LENGTH];
	RaceData *race;
	int i;

	one_argument(argument, arg);

	if (!str_cmp(arg, "help"))
	{
		argument = one_argument(argument, arg);
		if (NullStr(argument))
			do_function(ch, &nanny_help, "race help");
		else
			do_function(ch, &nanny_help, argument);
		d_println(d,
				  NEWLINE
				  "{cWhat is your race (help for more information)? {x");
		return;
	}

	race = race_lookup(argument);

	if (race == NULL || !race->pc_race)
	{
		d_println(d, "{cThat is not a valid race.{x");
		send_race_info(d);
		return;
	}

	if (IsRemort(ch) && ch->race != race)
	{
		d_printlnf(d, "{cYou are now a {R%s{c forever.{x", ch->race->name);
		ch->pcdata->stay_race = true;
	}

	ch->race = race;

	for (i = 0; i < STAT_MAX; i++)
		ch->perm_stat[i] = race->stats[i];
	ch->affected_by = ch->affected_by | race->aff;
	ch->imm_flags = ch->imm_flags | race->imm;
	ch->res_flags = ch->res_flags | race->res;
	ch->vuln_flags = ch->vuln_flags | race->vuln;
	ch->form = race->form;
	ch->parts = race->parts;

	for (i = 0; i < MAX_RACE_SKILL; i++)
	{
		if (race->skills[i] == NULL)
			break;
		group_add(ch, race->skills[i], false);
	}

	ch->pcdata->points = race->points;
	ch->size = race->size;

	d_printlnf(d, "{cYou are now a {W%s{c.", race->name);

	d_println(d,
			  NEWLINE
			  "{cWhat is your sex ({WM{c)ale/({WF{c)emale/({WN{c)eutral? {x");
	d->connected = CON_GET_NEW_SEX;
}

void send_class_info(Descriptor * d)
{
	int iClass;

	d_println(d, NEWLINE "{cThe following classes are available:{x");
	d_printlnf(d, "{W%s{x", draw_line(CH(d), "{w-{W-", 0));
	for (iClass = 0; iClass < top_class; iClass++)
	{
		if (is_class(d->character, iClass))
			continue;
		d_printlnf(d, "{c\t%s{x", ClassName(d->character, iClass));
	}
	d_printlnf(d, "{W%s{x", draw_line(CH(d), "{w-{W-", 0));
	d_printlnf(d, "{cFor more information, use help. (i.e. 'help %s'){x",
			   class_table[0].name[0]);
}

Nanny_Fun(HANDLE_CON_GET_NEW_SEX)
{
	CharData *ch = CH(d);

	switch (toupper(argument[0]))
	{
		case 'M':
			d_println(d, "{cYou are now {Wmale{c.");
			ch->sex = SEX_MALE;
			ch->pcdata->true_sex = SEX_MALE;
			break;
		case 'F':
			d_println(d, "{cYou are now {Wfemale{c.");
			ch->sex = SEX_FEMALE;
			ch->pcdata->true_sex = SEX_FEMALE;
			break;
		case 'N':
			d_println(d, "{cYou are now {Wneutral{c.");
			ch->sex = SEX_NEUTRAL;
			ch->pcdata->true_sex = SEX_NEUTRAL;
			break;
		default:
			d_println(d,
					  "{cThat's not a sex.{x" NEWLINE
					  "{cWhat IS your sex? {x");
			return;
	}

	send_class_info(d);
	d_printlnf(d, "{cWhat is your %sclass? {x", IsRemort(ch) ? "next " : "");
	d->connected = CON_GET_NEW_CLASS;
}

int roll_a_stat(CharData * ch, int pStat)
{
	int percent, bonus, low, high;

	if (!ch || !ch->race->pc_race)
		return number_range(13, 22);

	percent = number_percent();
	if (percent > 99)
		bonus = 2;
	else if (percent > 95)
		bonus = 1;
	else if (percent < 5)
		bonus = -1;
	else if (percent < 1)
		bonus = -2;
	else
		bonus = 0;

	high = ch->race->max_stats[pStat] - (3 - bonus);
	low = ch->race->stats[pStat] - (3 - bonus);
	return number_range(low, high);
}

void roll_stats(CharData * ch)
{
	int i;

	for (i = 0; i < STAT_MAX; i++)
		ch->perm_stat[i] = roll_a_stat(ch, i);
}

void init_gen_data(Descriptor * d)
{
	int i;

	CharData *ch = CH(d);

	ch->gen_data = new_gen_data();
	ch->gen_data->points_chosen = ch->pcdata->points;
	d_println(d, NEWLINE "{cYou may now roll your stats.{x" NEWLINE);
	roll_stats(ch);
	for (i = 0; i < STAT_MAX; i++)
		d_printf(d, "{c%.3s {W%02d {x", capitalize(stat_types[i].name),
				 ch->perm_stat[i]);
	d_println(d, "{c  Keep? ({WY{c/{WN{c) {x");
}

Nanny_Fun(HANDLE_CON_GET_NEW_CLASS)
{
	CharData *ch = CH(d);
	char arg[MIL];
	int iClass;

	one_argument(argument, arg);
	iClass = class_lookup(arg);

	if (iClass == -1)
	{
		if (!str_cmp(arg, "help"))
		{
			argument = one_argument(argument, arg);
			if (NullStr(argument))
				do_function(ch, &nanny_help, "class help");
			else
				do_function(ch, &nanny_help, argument);
			d_printlnf(d, NEWLINE "{cWhat IS your %sclass? {x",
					   IsRemort(ch) ? "next " : "");
			return;
		}
		d_println(d, "{cInvalid class.{x");
		send_class_info(d);
		d_printlnf(d, "{cWhat IS your %sclass? {x",
				   IsRemort(ch) ? "next " : "");
		return;
	}

	if (is_class(ch, iClass))
	{
		d_printlnf(d, "{cYou are already part {W%s{c. Try another!{x",
				   ClassName(ch, iClass));
		return;
	}

	ch->Class[ch->Class[CLASS_COUNT]] = iClass;
	ch->Class[CLASS_COUNT] += 1;
	ch->Class[ch->Class[CLASS_COUNT]] = -1;

	d_printlnf(d, "{cYou are now a {W%s{c.", class_long(ch));
	if (!IsRemort(ch))
	{
		wiznet("Newbie alert! $N sighted.", ch, NULL, WIZ_NEWBIE, false, 0);
		new_wiznet(ch, d->host, WIZ_SITES, true, get_trust(ch),
				   "$N@$t new player.");
		mud_info.stats.newbies++;
		d_println(d,
				  NEWLINE
				  "{cYou may now choose a general alignment of your character.{x");
		d_println(d,
				  "{cWhich alignment ({WG{c)ood/({WN{c)eutral/({WE{c)vil? {x");
		d->connected = CON_GET_ALIGNMENT;
	}
	else
	{

		init_gen_data(d);
		d->connected = CON_ROLL_STATS;
	}
}

void send_deity_info(Descriptor * d)
{
	DeityData *i;
	int e;

	d_println(d, NEWLINE "{cDeities available for worship:{x");
	d_printlnf(d, "{W%s", draw_line(CH(d), "{w-{W-", 0));
	for (e = ETHOS_LAWFUL_GOOD; e != ETHOS_CHAOTIC_EVIL; e--)
	{
		for (i = deity_first; i; i = i->next)
		{
			if (i->ethos != (ethos_t) e)
				continue;

			d_printlnf(d, "{c\t%-12s (%s): %s{x", i->name,
					   flag_string(ethos_types, i->ethos), i->desc);
		}
	}
	d_printlnf(d, "{W%s", draw_line(CH(d), "{w-{W-", 0));
	d_printlnf(d, "{cFor more information, use help. (i.e. 'help %s'){x",
			   deity_first->name);
}

Nanny_Fun(HANDLE_CON_GET_ALIGNMENT)
{
	CharData *ch = CH(d);

	switch (toupper(argument[0]))
	{
		case 'G':
			d_println(d, "{cYou are now {Wgood{c.{x");
			ch->alignment = 750;
			break;
		case 'N':
			d_println(d, "{cYou are now {Yneutral{c.{x");
			ch->alignment = 0;
			break;
		case 'E':
			d_println(d, "{cYou are now {Revil{c.{x");
			ch->alignment = -750;
			break;
		default:
			d_println(d, "{cThat's not a valid alignment.{x");
			d_println(d,
					  "{cWhich alignment ({WG{c)ood/({WN{c)eutral/({WE{c)vil? {x");
			return;
	}

	send_deity_info(d);
	d_println(d, "{cWhat deity would you like to worship?{x");
	d->connected = CON_GET_DEITY;
	return;
}

void send_timezone_info(Descriptor * d)
{
	int i;

	d_println(d,
			  NEWLINE
			  "{cPlease choose a timezone closest to where you live:{x");
	d_printlnf(d, "{W%s", draw_line(CH(d), "{w-{W-", 0));
	for (i = 0; i < MAX_TZONE; i++)
	{
		d_printlnf(d, "{c\t{W%5s{c - %9s - %s{x", tzone_table[i].name,
				   str_time(-1, i, "%I:%M:%S %p"), tzone_table[i].zone);
	}
	d_printlnf(d, "{W%s", draw_line(CH(d), "{w-{W-", 0));
	d_printlnf(d, "{cFor more information, use help. (i.e. 'help %s'){x",
			   tzone_table[0].name);
}

Nanny_Fun(HANDLE_CON_GET_DEITY)
{
	char arg[MIL];
	DeityData *i;
	CharData *ch = CH(d);

	one_argument(argument, arg);

	if (!str_cmp(arg, "help"))
	{
		argument = one_argument(argument, arg);
		if (NullStr(argument))
		{
			send_deity_info(d);
			d_println(d, "{cWhat deity would you like to worship? {x");
		}
		else
			do_function(ch, &do_help, argument);
		d_println(d, "{cWhat deity would you like to worship? {x");
		return;
	}
	i = deity_lookup(argument);

	if (i == NULL)
	{
		send_deity_info(d);
		d_println(d, "{cWhat deity would you like to worship? {x");
		return;
	}
	ch->deity = i;
	d_printlnf(d, "{cYou now worship {W%s{c.{x", ch->deity->name);

	send_timezone_info(d);
	d_println(d, "{cWhat time zone do you live in? {x");
	d->connected = CON_GET_TIMEZONE;
	return;
}

Nanny_Fun(HANDLE_CON_GET_TIMEZONE)
{
	int i;
	char arg[MIL];
	CharData *ch = CH(d);

	one_argument(argument, arg);

	if (NullStr(arg))
	{
		send_timezone_info(d);
		d_println(d, "{cWhat time zone do you live in? {x");
		return;
	}
	if (!str_cmp(arg, "help"))
	{
		d_printlnf(d,
				   "{cTime zones around the world are split up into %d areas,",
				   MAX_TZONE);
		d_printlnf(d,
				   "{ceach relating to Greenwich Mean Time (GMT) which is %s.{x",
				   str_time(-1, tzone_lookup("GMT"), "%I:%M:%S %p"));
		d_println(d, "{cWhat time zone do you live in? {x");
		return;
	}
	i = tzone_lookup(argument);

	if (i == -1)
	{
		d_println(d,
				  "{cThat is not a valid time zone, please enter the full time zone name. (ex. GMT-5)");
		d_println(d, "{cWhat time zone do you live in? {x");
		return;
	}

	ch->pcdata->timezone = i;
	d_printlnf(d, "{cYour time zone is now %s %s (%s) {x",
			   tzone_table[i].zone, tzone_table[i].name, str_time(-1, i,
																  "%I:%M:%S %p"));
	d_println(d, NULL);

	d_println(d,
			  "{cWhat is your e-mail address? (Hit return to leave blank){x");
	d->connected = CON_GET_EMAIL;
}

Nanny_Fun(HANDLE_CON_GET_EMAIL)
{
	if (NullStr(argument))
	{
		d_println(d, "{cE-mail not set.{x");
	}
	else
	{
		char *valid;
		CharData *ch = CH(d);

		if ((valid = is_invalid_email(argument)) != NULL)
		{
			d_printlnf(d, "{c%s{x", valid);
			d_println(d, "{cWhat is your e-mail address?{x");
			return;
		}

		replace_str(&ch->pcdata->email, argument);
		d_printlnf(d, "{cE-mail address set to '{W%s{c'.{x",
				   ch->pcdata->email);
	}
	d_println(d, NULL);

	if (IsSet(d->desc_flags, DESC_TELOPT_NAWS))
	{
		init_gen_data(d);
		d->connected = CON_ROLL_STATS;
	}
	else
	{
		d_println(d,
				  "{cThis mud makes use of formating text to your screen size, your client does not");
		d_println(d,
				  "support auto-negotation so you may now enter a screen size manually.  The default");
		d_printlnf(d, "screen is %d columns by %d lines.{x" NEWLINE,
				   DEFAULT_SCR_WIDTH, DEFAULT_SCR_HEIGHT);
		d_println(d,
				  "{cWhat is your screen size? Please answer in the form of 'AA BB' where AA is your screen{x");
		d_println(d, "{cwidth and BB is your screen height.{x");
		d->connected = CON_GET_SCR_SIZE;
	}
}

Nanny_Fun(HANDLE_CON_GET_SCR_SIZE)
{
	int sz;
	unsigned int i, j;
	char w[MIL], h[MIL];
	CharData *ch = CH(d);

	if (NullStr(argument))
	{
		d_printlnf(d, "{cDefault screen size of %d by %d used.{x",
				   DEFAULT_SCR_WIDTH, DEFAULT_SCR_HEIGHT);
		init_gen_data(d);
		d->connected = CON_ROLL_STATS;
		return;
	}

	argument = one_argument(argument, w);

	if (!is_number(w) || (sz = atoi(w)) < 10 || sz > 250)
	{
		d_println(d,
				  "{cPlease keep your screen width between 10 and 250 columns.{x");
		return;
	}
	else
	{
		d->scr_width = sz;
		ch->columns = sz;
	}

	argument = one_argument(argument, h);

	if (!NullStr(h))
	{
		if (!is_number(h) || (sz = atoi(h)) < 10 || sz > 100)
		{
			d_println(d,
					  "{cPlease keep your screen height between 10 and 100 lines.{x");
			return;
		}
		else
		{
			d->scr_height = sz;
			ch->lines = sz;
		}
	}
	d_println(d,
			  stringf(ch, 0, Center, "{?-{W=", "{c[ %d Columns by %d Lines ]",
					  d->scr_width, d->scr_height));
	for (i = 0; i < d->scr_height; i++)
	{
		d_print(d, "{?*");
		for (j = 0; j < 6; j++)
			d_printf(d, "{?%*s", ScrWidth(d) / 6, "*");
		d_println(d, NULL);
	}
	d_println(d, draw_line(ch, "{`-{W=", 0));
	d_println(d,
			  "{cBased on the above page, is your screen size set to your satisfaction? ({WY{c/{WN{c) ");
	d->connected = CON_CONFIRM_SCR_SIZE;
}

Nanny_Fun(HANDLE_CON_CONFIRM_SCR_SIZE)
{
	switch (toupper(argument[0]))
	{
		case 'Y':
			d_printlnf(d,
					   "{cScreen size set to {W%d{c columns by {W%d{c lines.{x",
					   d->scr_width, d->scr_height);
			init_gen_data(d);
			d->connected = CON_ROLL_STATS;
			break;
		case 'N':
			d_println(d,
					  "{cWhat is your screen size? Please answer in the form of 'AA BB' where AA is your screen{x");
			d_println(d, "{cwidth and BB is your screen height.{x");
			d->connected = CON_GET_SCR_SIZE;
			break;
		default:
			d_println(d, "{cYes or No?{x");
			break;
	}
}

Nanny_Fun(HANDLE_CON_ROLL_STATS)
{
	CharData *ch = CH(d);
	int i;

	switch (tolower(argument[0]))
	{
		case 'y':
			ch->gen_data->rerolls = 1;
			group_add(ch, "rom basics", false);
			add_base_groups(ch);
			ch->pcdata->learned[gsn_recall] = 50;
			d_println(d, "{cDo you wish to customize this character?{x");
			d_println(d,
					  "{cCustomization takes time, but allows a wider range of skills and abilities.{x");
			d_println(d, "{cCustomize ({WY{c/{WN{c)? {x");
			d->connected = CON_DEFAULT_CHOICE;
			break;
		case 'n':
			if (ch->gen_data->rerolls >= 10)
			{
				d_println(d,
						  NEWLINE
						  "You cannot reroll forever. Your stuck with what you have.{x");
				d_println(d, NULL);
				group_add(ch, "rom basics", false);
				add_base_groups(ch);
				ch->pcdata->learned[gsn_recall] = 50;
				d_println(d, "{cDo you wish to customize this character?{x");
				d_println(d,
						  "Customization takes time, but allows a wider range of skills and abilities.");
				d_println(d, "{cCustomize ({WY{c/{WN{c)? {x");
				d->connected = CON_DEFAULT_CHOICE;
				break;
			}
			ch->gen_data->rerolls++;

			roll_stats(ch);
			d_printlnf(d, "{cYou have {W%d{c re-rolls remaining.{x",
					   (11 - ch->gen_data->rerolls));
			for (i = 0; i < STAT_MAX; i++)
				d_printf(d, "{c%.3s {W%02d {x",
						 capitalize(stat_types[i].name), ch->perm_stat[i]);
			d_println(d, "{c  Keep? ({WY{c/{WN{c) {x");
			break;
		default:
			d_println(d, "{cYes or No?{x");
			break;
	}
}

void send_weapon_info(Descriptor * d)
{
	CharData *ch = CH(d);
	int i;

	free_gen_data(ch->gen_data);
	d_println(d, "{cPlease pick a weapon from the following choices:{x");
	for (i = 0; weapon_table[i].name != NULL; i++)
		if (ch->pcdata->learned[*weapon_table[i].gsn] > 0)
			d_printlnf(d, "{c\t%s{x", weapon_table[i].name);
	d_println(d, "{cYour choice? {x");
}

Nanny_Fun(HANDLE_CON_DEFAULT_CHOICE)
{
	CharData *ch = CH(d);

	d_println(d, NULL);
	switch (toupper(argument[0]))
	{
		case 'Y':
			d_println(d,
					  "{cThe following skills and groups are available to your character:{x");
			d_println(d, "{c(this list may be seen again by typing list){x");
			list_group_costs(ch);
			if (!IsRemort(ch))
			{
				d_println(d, "{cYou already have the following skills:{x");
				do_function(ch, &do_skills, "");
			}
			d_println(d,
					  NEWLINE
					  "{cChoice? (add, drop, list, learned, info, lookup, help, premise, done){x ");
			d->connected = CON_GEN_GROUPS;
			break;
		case 'N':
			d_printlnf(d, "{cDefault skill set for %s used.",
					   ClassName(ch, prime_class(ch)));
			add_default_groups(ch);
			send_weapon_info(d);
			d->connected = CON_PICK_WEAPON;
			break;
		default:
			d_println(d, "{cPlease answer ({WY{c/{WN{c)? {x");
			return;
	}
}

Nanny_Fun(HANDLE_CON_PICK_WEAPON)
{
	CharData *ch = CH(d);
	int i, weapon;
	void finish_remort(CharData *);

	weapon = weapon_lookup(argument);
	if (weapon == -1 || ch->pcdata->learned[*weapon_table[weapon].gsn] <= 0)
	{
		d_println(d, "{cThat's not a valid selection. Choices are:{x");
		for (i = 0; weapon_table[i].name != NULL; i++)
			if (ch->pcdata->learned[*weapon_table[i].gsn] > 0)
				d_printlnf(d, "{c\t%s{x", weapon_table[i].name);
		d_println(d, "{cYour choice? {x");
		return;
	}

	ch->pcdata->learned[*weapon_table[weapon].gsn] =
		Max(40, ch->pcdata->learned[*weapon_table[weapon].gsn]);

	if (IsRemort(ch))
	{
		finish_remort(ch);
	}
	else
	{
		do_function(ch, &nanny_help, "motd");
		d->connected = CON_READ_MOTD;
	}
}

Nanny_Fun(HANDLE_CON_GEN_GROUPS)
{
	CharData *ch = CH(d);

	if (!str_cmp(argument, "done"))
	{
		if (!IsRemort(ch))
		{
			if (ch->pcdata->points == ch->race->points)
			{
				chprintln(ch, "{cYou didn't pick anything.{x");
				return;
			}
		}

		ch->pcdata->points = Max(ch->pcdata->points, mud_info.max_points);

		chprintlnf(ch, "{cCreation points: %d{x", ch->pcdata->points);
		chprintlnf(ch, "{cExperience per level: %d{x",
				   exp_per_level(ch, ch->gen_data->points_chosen));
		send_weapon_info(d);
		d->connected = CON_PICK_WEAPON;
		return;
	}

	if (!parse_gen_groups(ch, argument))
		d_println(d,
				  "{cChoices are: (add, drop, list, learned, info, lookup, help, premise, done){x ");
	else
		d_println(d,
				  "{cChoice? (add, drop, list, learned, info, lookup, help, premise, done){x ");
}

Nanny_Fun(HANDLE_CON_READ_IMOTD)
{
	CharData *ch = CH(d);

	do_function(ch, &nanny_help, "motd");
	d->connected = CON_READ_MOTD;
}

Nanny_Fun(HANDLE_CON_READ_MOTD)
{
	CharData *ch = CH(d);
	char buf[MSL];
	int i;
	Proto(int num_changes, (void));

	if (ch->pcdata == NULL || NullStr(ch->pcdata->pwd))
	{
		d_println(d, "{WWarning! Null password!{x");
		d_println(d, "{WPlease report old password with bug.{x");
		d_println(d, "{WType '{Wpassword null <new password>{c' to fix.{x");
	}

	d_printlnf(d, "{cWelcome to {?%s{c, %s.{x", mud_info.name, ch->name);
	Link(ch, char, next, prev);

	Link(ch, player, next_player, prev_player);
	d->connected = CON_PLAYING;
	reset_char(ch);

	if (ch->level == 0)
	{
		if (ch->Class[0] == -1)
			ch->Class[0] = 0;

		ch->perm_stat[class_table[prime_class(ch)].attr_prime] += 3;

		if (pfiles.count == 0)
		{
			int sn;

			ch->level = MAX_LEVEL;
			ch->pcdata->perm_hit = ch->max_hit = 50000;
			ch->pcdata->perm_mana = ch->max_mana = 50000;
			ch->pcdata->perm_move = ch->max_move = 50000;
			ch->pcdata->security = 9;
			ch->trust = MAX_LEVEL;
			for (sn = 0; sn < top_skill; sn++)
			{
				if (get_skill(ch, sn) > 0)
					ch->pcdata->learned[sn] = 100;
			}
#ifndef DISABLE_I3
			ch->pcdata->i3chardata->i3perm = I3PERM_IMP;
#endif

			SetBit(ch->act, PLR_HOLYLIGHT);
			replace_str(&ch->prompt, IMMORTAL_PROMPT);
			save_char_obj(ch);
			realloc_mem(pfiles.names, const char *, pfiles.count + 1);

			pfiles.names[pfiles.count++] = str_dup(ch->name);
		}
		else
			ch->level = 1;

		ch->exp = exp_per_level(ch, ch->pcdata->points);
		ch->hit = ch->max_hit;
		ch->mana = ch->max_mana;
		ch->move = ch->max_move;
		ch->train = 3;
		ch->practice = 5;
		ch->gold = 10;
		sprintf(buf, "the %s %s", ch->race->name,
				ClassName(ch, prime_class(ch)));
		set_title(ch, buf);

		if (ch->level >= LEVEL_IMMORTAL)
		{
			char_to_room(ch, get_room_index(ROOM_VNUM_CHAT));
			chprintlnf(ch,
					   "{RSince you are the first player file on {?%s{R, "
					   "you have been made an {rImplementor{R automatically.",
					   mud_info.name);
		}
		else
		{
			do_function(ch, &do_outfit, "");
			obj_to_char(create_object(get_obj_index(OBJ_VNUM_MAP), 0), ch);

			char_to_room(ch, get_room_index(ROOM_VNUM_SCHOOL));
			chprintln(ch, NULL);
			do_function(ch, &nanny_help, "newbie info");
		}
	}
	else if (ch->in_room != NULL)
	{
		char_to_room(ch, ch->in_room);
	}
	else if (IsImmortal(ch))
	{
		char_to_room(ch, get_room_index(ROOM_VNUM_CHAT));
	}
	else
	{
		char_to_room(ch, get_room_index(ROOM_VNUM_TEMPLE));
	}

	announce(ch, INFO_LOGIN, "$n has entered the realms.");
	act("$n has entered the game.", ch, NULL, NULL, TO_ROOM);

	mud_info.stats.logins++;

	d_println(d, NULL);

	do_function(ch, &do_look, "auto");

	wiznet("$N has left real life behind.", ch, NULL, WIZ_LOGINS, false,
		   get_trust(ch));

	if (ch->pet != NULL)
	{
		char_to_room(ch->pet, ch->in_room);
		act("$n has entered the game.", ch->pet, NULL, NULL, TO_ROOM);
	}

	do_function(ch, &do_backup, "check");
	do_function(ch, &do_ncheck, "");
	do_function(ch, &do_count, "");
	i = num_changes();
	if (i > 0)
	{
		d_printlnf(d,
				   "{R==> {WThere were {R%s {Wmade to the mud today type {G%s{W to view.{x",
				   intstr(i, "change"), cmd_name(do_changes));
	}
	unfinished_quest(ch);
	update_explored(ch);
	checkcorpse(ch);
}

#define NANNY_CASE(state, fun) \
    case state : \
        fun (d, argument); \
        break

void nanny(Descriptor * d, const char *argument)
{

	if (d->connected != CON_NOTE_TEXT)
	{
		while (isspace(*argument))
			argument++;
	}

	switch (d->connected)
	{

		default:
			bugf("Nanny: bad d->connected %d.", d->connected);
			close_socket(d);
			return;

			NANNY_CASE(CON_GET_TERM, HANDLE_CON_GET_TERM);

			NANNY_CASE(CON_GET_NAME, HANDLE_CON_GET_NAME);

			NANNY_CASE(CON_GET_OLD_PASSWORD, HANDLE_CON_GET_OLD_PASSWORD);

			NANNY_CASE(CON_GET_WIZ, HANDLE_CON_GET_WIZ);

			NANNY_CASE(CON_BREAK_CONNECT, HANDLE_CON_BREAK_CONNECT);

			NANNY_CASE(CON_CONFIRM_NEW_NAME, HANDLE_CON_CONFIRM_NEW_NAME);

			NANNY_CASE(CON_GET_NEW_PASSWORD, HANDLE_CON_GET_NEW_PASSWORD);

			NANNY_CASE(CON_CONFIRM_NEW_PASSWORD,
					   HANDLE_CON_CONFIRM_NEW_PASSWORD);

			NANNY_CASE(CON_GET_NEW_RACE, HANDLE_CON_GET_NEW_RACE);

			NANNY_CASE(CON_GET_NEW_SEX, HANDLE_CON_GET_NEW_SEX);

			NANNY_CASE(CON_GET_NEW_CLASS, HANDLE_CON_GET_NEW_CLASS);

			NANNY_CASE(CON_GET_ALIGNMENT, HANDLE_CON_GET_ALIGNMENT);

			NANNY_CASE(CON_GET_DEITY, HANDLE_CON_GET_DEITY);

			NANNY_CASE(CON_GET_TIMEZONE, HANDLE_CON_GET_TIMEZONE);

			NANNY_CASE(CON_GET_EMAIL, HANDLE_CON_GET_EMAIL);

			NANNY_CASE(CON_GET_SCR_SIZE, HANDLE_CON_GET_SCR_SIZE);

			NANNY_CASE(CON_CONFIRM_SCR_SIZE, HANDLE_CON_CONFIRM_SCR_SIZE);

			NANNY_CASE(CON_ROLL_STATS, HANDLE_CON_ROLL_STATS);

			NANNY_CASE(CON_DEFAULT_CHOICE, HANDLE_CON_DEFAULT_CHOICE);

			NANNY_CASE(CON_PICK_WEAPON, HANDLE_CON_PICK_WEAPON);

			NANNY_CASE(CON_GEN_GROUPS, HANDLE_CON_GEN_GROUPS);

			NANNY_CASE(CON_READ_IMOTD, HANDLE_CON_READ_IMOTD);

			NANNY_CASE(CON_NOTE_TO, HANDLE_CON_NOTE_TO);

			NANNY_CASE(CON_NOTE_SUBJECT, HANDLE_CON_NOTE_SUBJECT);

			NANNY_CASE(CON_NOTE_EXPIRE, HANDLE_CON_NOTE_EXPIRE);

			NANNY_CASE(CON_NOTE_TEXT, HANDLE_CON_NOTE_TEXT);

			NANNY_CASE(CON_NOTE_FINISH, HANDLE_CON_NOTE_FINISH);

			NANNY_CASE(CON_READ_MOTD, HANDLE_CON_READ_MOTD);
	}

	return;
}