roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * login.cpp
 *	 Functions to log a person into the mud or create a new character
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2009 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include "login.h"
#include "commands.h"
#include "guilds.h"
#include "skills.h"
#include "calendar.h"
#include "magic.h"

#include <sstream>
#include <iomanip>
#include <locale>
//#include <arpa/telnet.h>



/*
 * Generic get function, copy for future use
 *
bool Create::get(Socket* sock, char* str, int mode) {
	if(mode == Create::doPrint) {

	} else if(mode == Create::doWork) {

	}
	return(true);
}
 *
 */


//*********************************************************************
//						cmdReconnect
//*********************************************************************

int cmdReconnect(Player* player, cmd* cmnd) {
	Socket* sock = player->getSock();

	player->print("\n\nReconnecting.\n\n\n");

	player->save(true);
	gServer->clearPlayer(player->name);

	player->uninit();
	free_crt(player);
	player = 0;
	sock->setPlayer(0);

	sock->reconnect();
	return(0);
}


//*********************************************************************
//						login
//*********************************************************************
// This function is the first function that gets input from a player when
// they log in. It asks for the player's name and password, and performs
// the according function calls.

void login(Socket* sock, char *str) {
	char	tempstr[20];
	Player	*player=0;
	int newline=0;

	if(!sock) {
		printf("**** ERORR: Null socket in login.\n");
		return;
	}

	if(sock->color == WANTS_MIRC_COLOR)
		newline = 1;

	switch(sock->getState()) {
	case LOGIN_DNS_LOOKUP:
		sock->print("Still performing DNS lookup, please be patient!\n");
		return;
	case LOGIN_GET_COLOR:
		sock->color = WANTS_NO_COLOR;
		switch (low(str[0])) {
		case 'a':
			sock->color = WANTS_ANSI_COLOR;
			sock->printColor("^WANSI Color^x activated.\n");
			break;
		case 'm':
			sock->color = WANTS_MIRC_COLOR;
			newline = 1;
			sock->printColor("^WmIRC Color^x activated. (For best results set background color to black)\n");
			break;
		case 'x':
			sock->color = WANTS_MXP_COLOR;
			sock->printColor("^WANSI Color^x with ^WMXP^x activated.\n");
			break;
		default:
			sock->print("\n");
			break;
		}

		sock->askFor("Please enter name: ");
		if(newline)
			sock->print("\n");
		gServer->processOutput();
		sock->setState(LOGIN_GET_NAME);
		return;
		// End LOGIN_GET_COLOR
	case LOGIN_GET_LOCKOUT_PASSWORD:
		if(strcmp(sock->tempstr[0], str)) {
			sock->disconnect();
			return;
		}
		sock->print("\n\nChoose - [A]nsi color, [M]irc color, [X] MXP + Ansi, or [N]o color\n: ");
		sock->setState(LOGIN_GET_COLOR);
		return;
		// End LOGIN_GET_LOCKOUT_PASSWORD
	case LOGIN_GET_NAME:
		lowercize(str, 1);
		if(strlen(str) >= 25)
			str[25]=0;

		if(!nameIsAllowed(str, sock)) {
			sock->askFor("Please enter name: ");
			if(newline)
				sock->print("\n");
			return;
		}

		if(!loadPlayer(str, &player)) {
			strcpy(sock->tempstr[0], str);
			sock->print("\n%s? Did I get that right? ", str);
			if(newline)
				sock->print("\n");
			sock->setState(LOGIN_CHECK_CREATE_NEW);
			return;
		} else {
			player->fd = -1;
			//gServer->addPlayer(player);
			sock->setPlayer(player);
			sock->print("%c%c%c", 255, 251, 1);
			sock->askFor("Please enter password: ");//, 255, 251, 1);
			if(newline)
				sock->print("\n");
			sock->setState(LOGIN_GET_PASSWORD);
			return;
		}
		// End LOGIN_GET_NAME
	case LOGIN_CHECK_CREATE_NEW:
		if(str[0] != 'y' && str[0] != 'Y') {
			sock->tempstr[0][0] = 0;
			sock->askFor("Please enter name: ");
			if(newline)
				sock->print("\n");
			sock->setState(LOGIN_GET_NAME);
			return;
		} else {

			sock->print("\nHit return: ");
			if(newline)
				sock->print("\n");
			sock->setState(CREATE_NEW);
			return;
		}
		// End LOGIN_CHECK_CREATE_NEW
	case LOGIN_GET_PASSWORD:

		if(!sock->getPlayer()->isPassword(str)) {
			sock->write("\255\252\1\n\rIncorrect.\n\r");
			if(newline)
				sock->print("\n");
			logn("log.incorrect", "Invalid password(%s) for %s from %s\n", str, sock->getPlayer()->name, sock->getHostname().c_str());
			sock->disconnect();
			return;
		} else {
			sock->print("%c%c%c\n\r", 255, 252, 1);
			strcpy(tempstr, sock->getPlayer()->name);

			gServer->checkDuplicateName(sock, true);
			if(gServer->checkDouble(sock)) {
				gServer->cleanUp();
				return;
			}
			gServer->cleanUp();

			if(!loadPlayer(tempstr, &player)) {
				sock->askFor("Player no longer exists!\n\nPlease enter name: ");
				if(newline)
					sock->print("\n");
				sock->setState(LOGIN_GET_NAME);
				return;
			}

//			if(player->flagIsSet(P_HARDCORE)) {
//				const StartLoc *location = gConfig->getStartLoc("highport");
//				player->bind(location);
//				// put them in the docks: hp.100
//				player->room.area = "hp";
//				player->room.id = 100;
//				// remove all their stuff
//				player->coins.zero();
//				otag *obj=0, *op = player->first_obj;
//				while(op) {
//					obj = op;
//					op = op->next_tag;
//					delete obj->obj;
//					delete obj;
//				}
//				player->first_obj = 0;
//			}

			sock->setPlayer(player);
			player->fd = sock->getFd();
			player->setSock(sock);
			player->init();

			gServer->addPlayer(player);
			// mIRC wants ANSI, but ANSI doesn't want mIRC
			if(sock->color == 1) {
				player->clearFlag(P_MIRC);
				player->setFlag(P_ANSI_COLOR);
			} else if(sock->color == 2) {
				player->setFlag(P_ANSI_COLOR);
				player->setFlag(P_MIRC);
			}

			sock->setState(CON_PLAYING);

//			if(player->flagIsSet(P_HARDCORE)) {
//				player->clearFlag(P_HARDCORE);
//				player->print("\n\n\n");
//				player->print("You wake up on the shores of Derlith, completely naked...\n");
//				player->print("\n\n");
//				player->print("You do not know how long you have been unconscious, or how long you have\n");
//				player->print("been floating at sea. The sounds of the ocean fill the air, interrupted by\n");
//				player->print("the bustling noise of a city street. An occasional bell rings and the\n");
//				player->print("sounds of horse-drawn carriages stumbling over cobblestone soon grow louder\n");
//				player->print("and louder. You look around to find yourself at the docks of Highport.\n");
//				player->print("People stare at you as they pass.\n");
//				player->print("\n\n");
//				player->print("You no longer feel hunted, as you did in Oceancrest. You feel the peaceful\n");
//				player->print("onset of immortality that comes with living in Derlith. You are now free to\n");
//				player->print("continue your adventures in this world...\n");
//				player->print("\n\n\n");
//			}
		}
	}
}


// Blah I know its a big hack...fix it later if you don't like it

int setPlyClass(Socket* sock, int cClass) {
	// Make sure they both start off at 0
	sock->getPlayer()->setClass(0);
	sock->getPlayer()->setSecondClass(0);
	// Define's BASE as first # to interpret as multi class
	// Increment this when a class is added

	switch(cClass) {
	case ASSASSIN:
	case BARD:
	case BERSERKER:
	case CLERIC:
	case DEATHKNIGHT:
	case DRUID:
	case FIGHTER:
	case LICH:
	case MAGE:
	case MONK:
	case PALADIN:
	case RANGER:
	case ROGUE:
	case THIEF:
	case VAMPIRE:
	case WEREWOLF:
		sock->getPlayer()->setClass(cClass);
		break;
	case MULTI_BASE + 0:
		sock->getPlayer()->setClass(FIGHTER);
		sock->getPlayer()->setSecondClass(MAGE);
		break;
	case MULTI_BASE + 1:
		sock->getPlayer()->setClass(FIGHTER);
		sock->getPlayer()->setSecondClass(THIEF);
		break;
	case MULTI_BASE + 2:
		sock->getPlayer()->setClass(CLERIC);
		sock->getPlayer()->setSecondClass(ASSASSIN);
		break;
	case MULTI_BASE + 3:
		sock->getPlayer()->setClass(MAGE);
		sock->getPlayer()->setSecondClass(THIEF);
		break;
	case MULTI_BASE + 4:
		sock->getPlayer()->setClass(THIEF);
		sock->getPlayer()->setSecondClass(MAGE);
		break;
	case MULTI_BASE + 5:
		sock->getPlayer()->setClass(CLERIC);
		sock->getPlayer()->setSecondClass(FIGHTER);
		break;
	case MULTI_BASE + 6:
		sock->getPlayer()->setClass(MAGE);
		sock->getPlayer()->setSecondClass(ASSASSIN);
		break;
	default:
		break;
	}
	return(0);
}


//*********************************************************************
//						setPlyDeity
//*********************************************************************

void setPlyDeity(Socket* sock, int deity) {

	switch(deity) {
		case ARAMON:
		case CERIS:
		case ENOCH:
		case GRADIUS:
		case ARES:
		case KAMIRA:
		case LINOTHAN:
		case ARACHNUS:
			break;
		default:
			deity = 0;
			break;
	}

	sock->getPlayer()->setDeity(deity);
}


//*********************************************************************
//						createPlayer
//*********************************************************************
// This function allows a new player to create their character.

void createPlayer(Socket* sock, char *str) {
	switch(sock->getState()) {
	case CREATE_NEW:
		{
			Player* target = sock->getPlayer();
			sock->print("\n");
			if(target) {
				gServer->clearPlayer(target->name);
				delete target;
			}
			target = new Player;
			if(!target)
				merror("createPlayer", FATAL);

			target->fd = -1;

			target->setSock(sock);
			sock->setPlayer(target);

			target->defineColors();
		}
		if(isdm(sock->tempstr[0])) {
			sock->print("\nYou must enter a password to create that character.\n");
			sock->print("Please enter password: ");
			Create::newline(sock);
			gServer->processOutput();
			sock->setState(CREATE_GET_DM_PASSWORD);
			return;
		} else
			goto no_pass;
		// End CREATE_NEW
	case CREATE_GET_DM_PASSWORD:
		if(strcmp(gConfig->getDmPass().c_str(), str)) {
			sock->disconnect();
			return;
		}

	case CREATE_CHECK_LOCKED_OUT:
no_pass:
		if(gConfig->isLockedOut(sock) == 1) {
			sock->disconnect();
			return;
		}

		Create::getRace(sock, str, Create::doPrint);
		return;

	case CREATE_GET_RACE:

		if(!Create::getRace(sock, str, Create::doWork))
			return;
		if(	gConfig->getRace(sock->getPlayer()->getRace())->isParent() &&
			Create::getSubRace(sock, str, Create::doPrint)
		)
			return;
		Create::getSex(sock, str, Create::doPrint);
		return;

	case CREATE_GET_SUBRACE:

		if(!Create::getSubRace(sock, str, Create::doWork))
			return;
		Create::getClass(sock, str, Create::doPrint);
		return;

	case CREATE_GET_SEX:

		if(!Create::getSex(sock, str, Create::doWork))
			return;
		Create::getClass(sock, str, Create::doPrint);
		return;

	case CREATE_GET_CLASS:

		if(!Create::getClass(sock, str, Create::doWork))
			return;

		if(gConfig->classes[get_class_string(sock->getPlayer()->getClass())]->needsDeity())
			Create::getDeity(sock, str, Create::doPrint);
		else if(Create::getLocation(sock, str, Create::doPrint))
			Create::getStats(sock, str, Create::doPrint);
		return;

	case CREATE_GET_DEITY:

		if(!Create::getDeity(sock, str, Create::doWork))
			return;
		if(Create::getLocation(sock, str, Create::doPrint))
			Create::getStats(sock, str, Create::doPrint);
		return;

	case CREATE_START_LOC:

		if(!Create::getLocation(sock, str, Create::doWork))
			return;
		Create::getStats(sock, str, Create::doPrint);
		return;

	case CREATE_GET_STATS:

		if(!Create::getStats(sock, str, Create::doWork))
			return;

		if(gConfig->getRace(sock->getPlayer()->getRace())->bonusStat())
			Create::getBonusStat(sock, str, Create::doPrint);
		else {
			Create::finishStats(sock);
			Create::startCustom(sock, str, Create::doPrint);
		}
		return;

	case CREATE_BONUS_STAT:

		if(!Create::getBonusStat(sock, str, Create::doWork))
			return;
		Create::getPenaltyStat(sock, str, Create::doPrint);
		return;

	case CREATE_PENALTY_STAT:

		if(!Create::getPenaltyStat(sock, str, Create::doWork))
			return;
		Create::startCustom(sock, str, Create::doPrint);
		return;

	case CREATE_START_CUSTOM:

		if(Create::startCustom(sock, str, Create::doWork))
			Create::getCommunity(sock, str, Create::doPrint);
		else
			Create::getProf(sock, str, Create::doPrint);
		return;

	case CREATE_GET_PROF:

		if(!Create::getProf(sock, str, Create::doWork))
			return;
		if(gConfig->classes[get_class_string(sock->getPlayer()->getClass())]->numProfs()==2)
			Create::getSecondProf(sock, str, Create::doPrint);
		else
			Create::getPassword(sock, str, Create::doPrint);
		return;

	case CREATE_SECOND_PROF:

		if(!Create::getSecondProf(sock, str, Create::doWork))
			return;
		Create::getPassword(sock, str, Create::doPrint);
		return;

	case CREATE_GET_PASSWORD:

		if(!Create::getPassword(sock, str, Create::doWork))
			return;
		Create::done(sock, str, Create::doPrint);
		return;

	case CREATE_DONE:

		Create::done(sock, str, Create::doWork);
		return;




	// handle character customization here:
	case CUSTOM_COMMUNITY:

		if(!Create::getCommunity(sock, str, Create::doWork))
			return;
		Create::getFamily(sock, str, Create::doPrint);
		return;

	case CUSTOM_FAMILY:

		if(!Create::getFamily(sock, str, Create::doWork))
			return;
		Create::getSocial(sock, str, Create::doPrint);
		return;

	case CUSTOM_SOCIAL:

		if(!Create::getSocial(sock, str, Create::doWork))
			return;
		Create::getEducation(sock, str, Create::doPrint);
		return;

	case CUSTOM_EDUCATION:

		if(!Create::getEducation(sock, str, Create::doWork))
			return;
		Create::getHeight(sock, str, Create::doPrint);
		return;

	case CUSTOM_HEIGHT:

		if(!Create::getHeight(sock, str, Create::doWork))
			return;
		Create::getWeight(sock, str, Create::doPrint);
		return;

	case CUSTOM_WEIGHT:

		if(!Create::getWeight(sock, str, Create::doWork))
			return;
		Create::getStats(sock, str, Create::doPrint);
		return;

	}
}


//
// newline function so I don't have to copy this everywhere
//
void Create::newline(Socket* sock) {
	if(sock->color == WANTS_MIRC_COLOR)
		sock->print("\n");
}

//*********************************************************************
//						addStartingItem
//*********************************************************************

void Create::addStartingItem(Player* player, bstring area, int id, bool wear, bool skipUseCheck) {
	CatRef cr;
	cr.setArea(area);
	cr.id = id;

	Object* object=0;
	if(loadObject(cr, &object)) {
		object->setFlag(O_STARTING);
		// if they can't use it, dont even give it to them
		if(!skipUseCheck && !player->canUse(object, true)) {
			delete object;
		} else {
			player->addObj(object);
			if(wear)
				player->equip(object, false);
		}
	}
}

//*********************************************************************
//						addStartingWeapon
//*********************************************************************

void Create::addStartingWeapon(Player* player, bstring weapon) {
	if(weapon == "sword")
		Create::addStartingItem(player, "tut", 28);
	else if(weapon == "great-sword")
		Create::addStartingItem(player, "tut", 21);
	else if(weapon == "polearm")
		Create::addStartingItem(player, "tut", 24);
	else if(weapon == "whip")
		Create::addStartingItem(player, "tut", 29);
	else if(weapon == "rapier")
		Create::addStartingItem(player, "tut", 25);
	else if(weapon == "spear")
		Create::addStartingItem(player, "tut", 26);
	else if(weapon == "axe")
		Create::addStartingItem(player, "tut", 14);
	else if(weapon == "great-axe")
		Create::addStartingItem(player, "tut", 18);
	else if(weapon == "dagger")
		Create::addStartingItem(player, "tut", 17);
	else if(weapon == "staff")
		Create::addStartingItem(player, "tut", 27);
	else if(weapon == "mace")
		Create::addStartingItem(player, "tut", 23);
	else if(weapon == "great-mace")
		Create::addStartingItem(player, "tut", 20);
	else if(weapon == "club")
		Create::addStartingItem(player, "tut", 16);
	else if(weapon == "hammer")
		Create::addStartingItem(player, "tut", 22);
	else if(weapon == "great-hammer")
		Create::addStartingItem(player, "tut", 19);
	else if(weapon == "bow")
		Create::addStartingItem(player, "tut", 15);
	else if(weapon == "crossbow")
		Create::addStartingItem(player, "tut", 30);
	else if(weapon == "thrown")
		Create::addStartingItem(player, "tut", 31);
}


//
// work functions
//


//*********************************************************************
//						getSex
//*********************************************************************

bool Create::getSex(Socket* sock, char* str, int mode) {
	const RaceData* rdata = gConfig->getRace(sock->getPlayer()->getRace());
	if(!rdata->isGendered()) {
		sock->getPlayer()->setSex(SEX_NONE);
		return(true);
	}

	if(mode == Create::doPrint) {

		sock->askFor("Do you wish to be [^WM^x] Male or [^WF^x] Female? ");
		Create::newline(sock);
		sock->setState(CREATE_GET_SEX);

	} else if(mode == Create::doWork) {

		if(low(str[0]) == 'f') {
			sock->getPlayer()->setSex(SEX_FEMALE);
			sock->printColor("You are now ^Wfemale^x.\n");
		} else if(low(str[0]) == 'm') {
			sock->getPlayer()->setSex(SEX_MALE);
			sock->printColor("You are now ^Wmale^x.\n");
		} else {
			sock->askFor("[^WM^x] Male or [^WF^x] Female: ");
			Create::newline(sock);
			sock->setState(CREATE_GET_SEX);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						getRace
//*********************************************************************

#define FBUF	800

bool Create::getRace(Socket* sock, char* str, int mode) {
	std::map<int, RaceData*> choices;
	std::map<int, RaceData*>::iterator it;
	int k=0;

	// figure out what they can play
	for(it = gConfig->races.begin() ; it != gConfig->races.end() ; it++) {
		// if not playable, skip
		// if sub race, skip, they'll choose when they pick parent race
		if((*it).second->isPlayable() && !(*it).second->getParentRace())
			choices[k++] = (*it).second;
	}

	if(mode == Create::doPrint) {

		char file[80];
		int ff=0;

		// show them the race menu header
		sprintf(file, "%s/race_menu.0.txt", CONFPATH);
		viewLoginFile(sock, file);

		// show them the main race menu
		sprintf(file, "%s/race_menu.1.txt", CONFPATH);
		char            buf[FBUF + 1];

		ff = open(file, O_RDONLY, 0);
		k=0;
		if(ff < 0) {
			// we can't load the file? just give them a menu

			for(it = choices.begin() ; it != choices.end() ; it++) {
				sock->printColor("[^W%1c^x] %-16s\n", k + 65, (*it).second->getName().c_str());
				k++;
			}

			return(0);
		} else {
			// display them the file
			int             i, l, n, line;
			long            offset;
			zero(buf, sizeof(buf));

			while(1) {
				n = read(ff, buf, FBUF);
				l = 0;
				for(i=0; i<n; i++) {
					if(buf[i] == '\n') {
						buf[i] = 0;
						if(i != 0 && buf[i-1] == '\r')
							buf[i-1] = 0;
						line++;
						sock->printColor("%s", &buf[l]);

						// print out the next playable race
						if(choices.find(k) != choices.end()) {
							sock->printColor("[^W%1c^x] %-16s", k + 65, choices[k]->getName().c_str());
							k++;
						}
						sock->print("\n");
						offset += (i - l + 1);
						l = i + 1;
					}
				}
				if(l != n) {
					sock->printColor("%s", &buf[l]);
					offset += (i - l);
				}
				if(n < FBUF) {
					close(ff);
					break;
				}
			}
		}
		sock->print("\n\n\n");

		sock->askFor("Choose one: ");
		Create::newline(sock);
		sock->setState(CREATE_GET_RACE);

	} else if(mode == Create::doWork) {
		k = low(str[0]) - 'a';

		if(choices.find(k) != choices.end()) {
			sock->getPlayer()->setRace(choices[k]->getId());
		} else {
			sock->print("\nChoose one: ");
			Create::newline(sock);
			sock->setState(CREATE_GET_RACE);
			return(false);
		}
		if(!sock->getPlayer()->getRace())
			return(false);
		if(!gConfig->getRace(sock->getPlayer()->getRace())->isParent())
			Create::finishRace(sock);
	}
	return(true);
}

//*********************************************************************
//						getSubRace
//*********************************************************************

bool Create::getSubRace(Socket* sock, char* str, int mode) {
	std::map<int, RaceData*> choices;
	std::map<int, RaceData*>::iterator it;
	int k=0;

	// figure out what they can play
	for(it = gConfig->races.begin() ; it != gConfig->races.end() ; it++) {
		if(	(*it).second->isPlayable() &&
			(	(*it).second->getId() == sock->getPlayer()->getRace() ||
				(*it).second->getParentRace() == sock->getPlayer()->getRace()
			)
		)
			choices[k++] = (*it).second;
	}

	k=0;
	if(mode == Create::doPrint) {
		std::ostringstream oStr;
		char c;
		bool	hasChildren = false;

		// set left aligned
		oStr.setf(std::ios::left, std::ios::adjustfield);
		oStr.imbue(std::locale(""));

		oStr << "\nChoose a sub race:\n";

		for(it = choices.begin() ; it != choices.end() ; it++) {
			// self doesn't count when counting children
			if((*it).second->getId() != sock->getPlayer()->getRace())
				hasChildren = true;

			if(k%2==0)
				oStr << "\n" << std::setw(20) << " ";
			c = ++k + 64;
			oStr << "[^W" << c << "^x] " << std::setw(16) << (*it).second->getName();
		}

		// if there's no children, none of the subraces are playable,
		// so they have to choose the parent
		if(!hasChildren) {
			Create::finishRace(sock);
			return(false);
		}

		sock->printColor("%s\n\n", oStr.str().c_str());

		sock->askFor("Choose one: ");
		Create::newline(sock);
		sock->setState(CREATE_GET_SUBRACE);

	} else if(mode == Create::doWork) {

		k = low(str[0]) - 'a';

		if(choices.find(k) != choices.end()) {
			sock->getPlayer()->setRace(choices[k]->getId());
			Create::finishRace(sock);
			return(true);
		}
		return(false);
	}
	return(true);
}

//*********************************************************************
//						finishRace
//*********************************************************************

void Create::finishRace(Socket* sock) {
	const RaceData* race = gConfig->getRace(sock->getPlayer()->getRace());

	sock->printColor("\nYour chosen race: ^W%s^x\n\n", race->getName().c_str());
	sock->getPlayer()->setSize(race->getSize());
	sock->getPlayer()->initLanguages();

	std::list<bstring>::const_iterator it;
	for(it = race->effects.begin() ; it != race->effects.end() ; it++) {
		sock->getPlayer()->addPermEffect((*it));
	}
}

//*********************************************************************
//						getClass
//*********************************************************************

bool Create::getClass(Socket* sock, char* str, int mode) {
	int		l=0, k=0;
	if(mode == Create::doPrint) {

		sock->print("   ____________\n");
		sock->print("  /------------\\            VVVVVVVVVVVVVVVV\n");
		sock->print(" // ___    ___ \\\\   %12s:  Choose A Class\n", gConfig->getRace(sock->getPlayer()->getRace())->getName().c_str());
		sock->print(" \\_/   \\  /   \\_/           ^^^^^^^^^^^^^^^^\n");
		sock->print(" ______/  \\__________________________________________________\n");
		sock->print("<______    ________\\\\\\\\_____\\\\\\\\_____\\\\\\\\_____\\\\\\\\_____\\\\\\\\__]\n");
		sock->print("  _    \\  /    _\n");
		sock->print(" / \\___/  \\___/ \\\n");
		sock->print(" \\\\____________//\n");
		sock->print("  `------------'"," ");

		for(l=1, k=0; l<CLASS_COUNT_MULT; l++) {
			if(gConfig->getRace(sock->getPlayer()->getRace())->allowedClass(l)) {
				if(k%2==0)
					sock->print("\n%20s", " ");
				sock->printColor("[^W%1c^x] %-16s", ++k + 64, allowedClassesStr[l-1]);
			}
		}

		sock->print("\n                                                         |\\\n");
		sock->print("                                                         <<\\         _\n");
		sock->print("                                                          / \\       //\n");
		sock->print(" .--------------------------------------------------------{o}______/|\n");
		sock->print("<       -===========================================:::{*}///////////]\n");
		sock->print(" `--------------------------------------------------------{o}~~~~~~\\|\n");
		sock->print("                                                          \\ /       \\\\\n");
		sock->print("                                                         <</         -\n");
		sock->print("                                                         |/\n");
		sock->askFor("Choose one: ");
		Create::newline(sock);
		sock->setState(CREATE_GET_CLASS);

	} else if(mode == Create::doWork) {

		int 	i=0;
		if(!isalpha(str[0]))
			i = -1;
		else
			i = (int)(up(str[0]) - 64);

		for(l=1, k=0; l<CLASS_COUNT_MULT; l++) {
			if(gConfig->getRace(sock->getPlayer()->getRace())->allowedClass(l)) {
				k++;
				if(k == i)
					setPlyClass(sock, l);
			}
		}
		if(sock->getPlayer()->getClass()) {
			if(sock->getPlayer()->getSecondClass())
				sock->printColor("Your chosen class: ^W%s/%s\n", get_class_string(sock->getPlayer()->getClass()), get_class_string(sock->getPlayer()->getSecondClass()));
			else
				sock->printColor("Your chosen class: ^W%s\n", get_class_string(sock->getPlayer()->getClass()));
		}
		if(!sock->getPlayer()->getClass()) {
			sock->printColor("Invalid selection: ^W%s\n", str);
			sock->askFor("Choose one: ");
			Create::newline(sock);

			sock->setState(CREATE_GET_CLASS);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						getDeity
//*********************************************************************

bool Create::getDeity(Socket* sock, char* str, int mode) {
	int		l=0, k=0;
	const RaceData* race = gConfig->getRace(sock->getPlayer()->getRace());
	if(mode == Create::doPrint) {

		sock->print("Please choose a deity:\n");

		for(l=1, k=0 ; l<DEITY_COUNT ; l++) {
			if(race->allowedDeity(sock->getPlayer()->getClass(), sock->getPlayer()->getSecondClass(), l)) {
				if(k%2==0)
					sock->print("\n%20s", " ");
				sock->printColor("[^W%1c^x] %-16s", ++k + 64, gConfig->getDeity(l)->getName().c_str());
			}
		}
		sock->askFor("\n\nChoose one: ");
		Create::newline(sock);

		sock->setState(CREATE_GET_DEITY);

	} else if(mode == Create::doWork) {

		int		i=0;
		if(!isalpha(str[0]))
			i = -1;
		else
			i = (int)(up(str[0]) - 64);

		for(l=1, k=0; l < CLASS_COUNT+4; l++) {

			if(race->allowedDeity(sock->getPlayer()->getClass(), sock->getPlayer()->getSecondClass(), l)) {
				k++;
				if(k == i)
					setPlyDeity(sock, l);
			}
		}

		if(sock->getPlayer()->getDeity())
			sock->printColor("Your chosen deity: ^W%s\n", gConfig->getDeity(sock->getPlayer()->getDeity())->getName().c_str());
		else {
			sock->printColor("Invalid selection: ^W%s\n", str);
			sock->askFor("Choose one: ");
			Create::newline(sock);

			sock->setState(CREATE_GET_DEITY);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						getLocation
//*********************************************************************

// from start.cpp
bool startingChoices(Player* player, char* str, char* location, bool choose);

bool Create::getLocation(Socket* sock, char* str, int mode) {
	char location[256];
	if(mode == Create::doPrint) {

		if(!startingChoices(sock->getPlayer(), str, location, false)) {
			sock->print("\n\nPlease choose a starting location:");
			sock->printColor("\n   %s\n\n", location);

			// TODO: Dom: HC
			//sock->printColor("^YCaution:^x If you choose Oceancrest as a starting location, you will\n");
			//sock->printColor("automatically be entered into the tournament. See the forum for details.\n");
			//sock->printColor("^Yhttp://forums.rohonline.net/topic/1655/\n\n");
			sock->askFor(": ");
			Create::newline(sock);

			sock->setState(CREATE_START_LOC);
			return(false);
		}

	} else if(mode == Create::doWork) {

		if(!startingChoices(sock->getPlayer(), str, location, true)) {
			sock->print("Invalid selection.\n");
			sock->askFor(": ");
			Create::newline(sock);

			sock->setState(CREATE_START_LOC);
			return(false);
		}

	}

	sock->print("\n\nYour starting location is: ");
	sock->print("\n   %s\n\n", location);
	return(true);
}

//*********************************************************************
//						startCustom
//*********************************************************************

bool Create::startCustom(Socket* sock, char* str, int mode) {
	// still in progress! bypass for now
	return(getProf(sock, str, mode));

	if(mode == Create::doPrint) {

		sock->printColor("\nFor more customization options, press [^WM^x].\n");
		sock->print("To continue with your character, press enter.\n");

		sock->askFor(": ");
		Create::newline(sock);

		sock->setState(CREATE_START_CUSTOM);

	} else if(mode == Create::doWork) {

		if(str[0] != 'm' && str[0] != 'M') {
			// randomly customize them
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						getStats
//*********************************************************************

bool Create::getStats(Socket* sock, char* str, int mode) {
	if(mode == Create::doPrint) {

		sock->print("\nYou have 56 points to distribute among your 5 stats. Please enter your 5");
		sock->print("\nnumbers in the following order: Strength, Dexterity, Constitution,");
		sock->print("\nIntelligence, Piety.  No stat may be smaller than 3 or larger than 18.");
		sock->print("\nUse the following format: ## ## ## ## ##\n\n");

		sock->askFor(": ");
		Create::newline(sock);

		sock->setState(CREATE_GET_STATS);

	} else if(mode == Create::doWork) {

		int		i=0, l=0, k=0, sum=0, num[5], n = strlen(str);

		for(i=0; i<=n; i++) {
			if(str[i]==' ' || str[i]==0) {
				str[i] = 0;
				num[k++] = atoi(&str[l]);
				l = i+1;
			}
			if(k>4)
				break;
		}
		if(k<5) {
			sock->print("Please enter all 5 numbers.\n");
			sock->askFor(": ");
			Create::newline(sock);

			sock->setState(CREATE_GET_STATS);
			return(false);
		}

		for(i=0; i<5; i++) {
			if(num[i] < 3 || num[i] > 18) {
				sock->print("No stats < 3 or > 18 please.\n");
				sock->print(": ");
				Create::newline(sock);
				sock->setState(CREATE_GET_STATS);
				return(false);
			}
			sum += num[i];
		}

		if(sum != 56) {
			sock->print("Stat total must equal 56 points.\n");
			sock->print(": ");
			Create::newline(sock);
			sock->setState(CREATE_GET_STATS);
			return(false);
		}

		sock->getPlayer()->strength.setMax(num[0] * 10);
		sock->getPlayer()->dexterity.setMax(num[1] * 10);
		sock->getPlayer()->constitution.setMax(num[2] * 10);
		sock->getPlayer()->intelligence.setMax(num[3] * 10);
		sock->getPlayer()->piety.setMax(num[4] * 10);

	}
	return(true);
}

//*********************************************************************
//						finishStats
//*********************************************************************

void Create::finishStats(Socket* sock) {
	Player* ply = sock->getPlayer();
	ply->strength.addMax(gConfig->getRace(ply->getRace())->getStatAdj(STR));
	ply->dexterity.addMax(gConfig->getRace(ply->getRace())->getStatAdj(DEX));
	ply->constitution.addMax(gConfig->getRace(ply->getRace())->getStatAdj(CON));
	ply->intelligence.addMax(gConfig->getRace(ply->getRace())->getStatAdj(INT));
	ply->piety.addMax(gConfig->getRace(ply->getRace())->getStatAdj(PTY));

	ply->strength.setMax(MAX(10, ply->strength.getMax()));
	ply->dexterity.setMax(MAX(10, ply->dexterity.getMax()));
	ply->constitution.setMax(MAX(10, ply->constitution.getMax()));
	ply->intelligence.setMax(MAX(10, ply->intelligence.getMax()));
	ply->piety.setMax(MAX(10, ply->piety.getMax()));

	sock->print("Your stats: %d %d %d %d %d\n",
		ply->strength.getMax(),
		ply->dexterity.getMax(),
		ply->constitution.getMax(),
		ply->intelligence.getMax(),
		ply->piety.getMax());
}

//*********************************************************************
//						getBonusStat
//*********************************************************************

bool Create::getBonusStat(Socket* sock, char* str, int mode) {
	if(mode == Create::doPrint) {

		sock->print("\nRaise which stat?\n[A] Strength, [B] Dexterity, [C] Constitution, [D] Intelligence, or [E] Piety.\n : ");
		Create::newline(sock);
		sock->setState(CREATE_BONUS_STAT);

	} else if(mode == Create::doWork) {

		switch(low(str[0])) {
		case 'a':
			sock->getPlayer()->strength.addMax(10);
			break;
		case 'b':
			sock->getPlayer()->dexterity.addMax(10);
			break;
		case 'c':
			sock->getPlayer()->constitution.addMax(10);
			break;
		case 'd':
			sock->getPlayer()->intelligence.addMax(10);
			break;
		case 'e':
			sock->getPlayer()->piety.addMax(10);
			break;
		default:
			sock->print("\nChoose one: ");
			Create::newline(sock);
			sock->setState(CREATE_BONUS_STAT);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						getPenaltyStat
//*********************************************************************

bool Create::getPenaltyStat(Socket* sock, char* str, int mode) {
	if(mode == Create::doPrint) {

		sock->printColor("\nChoose your stat to lower:\n[^WA^x] Strength, [^WB^x] Dexterity, [^WC^x] Constitution, [^WD^x] Intelligence, or [^WE^x] Piety.\n : ");
		Create::newline(sock);
		sock->setState(CREATE_PENALTY_STAT);

	} else if(mode == Create::doWork) {

		switch(low(str[0])) {
		case 'a':
			sock->getPlayer()->strength.addMax(-10);
			break;
		case 'b':
			sock->getPlayer()->dexterity.addMax(-10);
			break;
		case 'c':
			sock->getPlayer()->constitution.addMax(-10);
			break;
		case 'd':
			sock->getPlayer()->intelligence.addMax(-10);
			break;
		case 'e':
			sock->getPlayer()->piety.addMax(-10);
			break;
		default:
			sock->print("\nChoose one: ");
			Create::newline(sock);
			sock->setState(CREATE_PENALTY_STAT);
			return(false);
		}
	}
	return(true);
}

//*********************************************************************
//						handleWeapon
//*********************************************************************

bool Create::handleWeapon(Socket* sock, int mode, char ch) {
	int		i=0;

	if(!isalpha(ch))
		i = -1;
	else
		i = (int)(up(ch) - 64);

	if(mode == Create::doPrint) {
		if(sock->getPlayer()->getClass() == WEREWOLF) {
			sock->printColor("\n\n^WSlashing Weapons^x\n     [^WA^x] Claws\n");
			return(true);
		} else if(sock->getPlayer()->getClass() == MONK) {
			sock->printColor("\n\n^WCrushing Weapons^x\n     [^WA^x] Bare-Handed\n");
			return(true);
		}
	} else {
		if(sock->getPlayer()->getClass() == WEREWOLF && low(ch) == 'a') {
			sock->getPlayer()->setSkill("claw", 1);
			return(true);
		} else if(sock->getPlayer()->getClass() == MONK && low(ch) == 'a') {
			sock->getPlayer()->setSkill("bare-hand", 1);
			return(true);
		} else if(sock->getPlayer()->getClass() == MONK || sock->getPlayer()->getClass() == WEREWOLF) {
			sock->print("Choose a weapon skill:\n");
			sock->setState(CREATE_GET_PROF);
			return(false);
		}
	}
	if(!sock->getPlayer()->knowsSkill("bare-hand"))
		sock->getPlayer()->addSkill("bare-hand", 1);

	std::map<bstring, bstring>::const_iterator sgIt;
	std::map<bstring, Skill*>::const_iterator sIt;
	int k = 0, n = 0;
	bstring curGroup, curGroupDisplay;
	Skill* curSkill;
	for(sgIt = gConfig->skillGroups.begin() ; sgIt != gConfig->skillGroups.end() ; sgIt++) {
		curGroup = (*sgIt).first;
		curGroupDisplay = (*sgIt).second;

		if(curGroup.left(7) != "weapons")
			continue;

		if(sock->getPlayer()->getClass() == CLERIC && sock->getPlayer()->getDeity() == CERIS) {
			if(curGroup.Find("slashing") != -1 || curGroup.Find("piercing") != -1)
				continue;
		}


		if(mode == Create::doPrint) {
			sock->printColor("^W\n\n%s", (*sgIt).second.c_str());
			n = 0;
		}

		for(sIt = gConfig->skills.begin() ; sIt != gConfig->skills.end() ; sIt++) {
			curSkill = (*sIt).second;
			if(curSkill->getGroup() != curGroup)
				continue;

			if(curSkill->getName() == "claw")
				continue;

			if(sock->getPlayer()->getClass() == CLERIC && sock->getPlayer()->getDeity() == CERIS)
				if(curSkill->getName() == "whip")
					continue;

			if(sock->getPlayer()->knowsSkill(curSkill->getName()))
				continue;

			if(mode == Create::doPrint) {
				if(n++%2==0)
					sock->print("\n%5s", " ");

				sock->printColor("[^W%1c^x] %-30s", ++k + 64, curSkill->getDisplayName().c_str());
			} else {
				if(i == ++k) {
					if(sock->getState() == CON_CHOSING_WEAPONS)
						sock->getPlayer()->setSkill(curSkill->getName(), MAX(1, (sock->getPlayer()->getLevel()-1)*10));
					else
						sock->getPlayer()->setSkill(curSkill->getName(), 1);
					Create::addStartingWeapon(sock->getPlayer(), curSkill->getName());
					sock->printColor("You have learned how to use ^W%s^x.\n", curSkill->getDisplayName().c_str());
					return(true);
				}
			}
		}
	}
	if(mode == Create::doPrint) {
		if(k==0)
			return(false);
		else
			return(true);
	}
	return(false);
}

//*********************************************************************
//						cmdWeapons
//*********************************************************************

int cmdWeapons(Player* player, cmd* cmnd) {
	if(player->getWeaponTrains() < 1) {
		player->print("You don't have any weapon trains left!\n");
		return(0);
	}

//	if(!player->getRoom()->findWeaponsTrainer()) {
//		player->print("You can't find anyone here to train you in weapon skills!\n");
//		return(0);
//	}

	player->printColor("You have ^W%d^x weapon skills to choose.\n",
		player->getWeaponTrains());

	if(!Create::handleWeapon(player->getSock(), Create::doPrint, '\0')) {
		player->print("\n\nSorry, couldn't find any weapon skills you don't know that you can learn.\n");
		return(0);
	}
	player->getSock()->setState(CON_CHOSING_WEAPONS);
	player->getSock()->askFor("\n(0 to exit): ");
	return(0);
}

//*********************************************************************
//						convertNewWeaponSkills
//*********************************************************************

void convertNewWeaponSkills(Socket* sock, char *str) {
	if(!isalpha(str[0])) {
		sock->setState(CON_PLAYING);
		return;
	}

	if(Create::handleWeapon(sock, Create::doWork, str[0])) {
		sock->getPlayer()->subWeaponTrains(1);
		if(sock->getPlayer()->getWeaponTrains() == 0) {
			sock->print("Exiting weapon skill selector.\n");
			sock->setState(CON_PLAYING);
			return;
		} else {
			sock->print("You have %d weapon skill(s) left to choose.", sock->getPlayer()->getWeaponTrains());
			if(!Create::handleWeapon(sock, Create::doPrint, str[0])) {
				sock->print("\n\nSorry, couldn't find any weapon skills you don't know that you can learn.\n");
				sock->setState(CON_PLAYING);
				return;
			}
			sock->askFor("\n(0 to exit): ");
		}
	} else {
		sock->print("Please pick: ");
	}
}

//*********************************************************************
//						getProf
//*********************************************************************

bool Create::getProf(Socket* sock, char* str, int mode) {

	if(mode == Create::doPrint) {
		if(gConfig->classes[get_class_string(sock->getPlayer()->getClass())]->numProfs() > 1) {
			sock->print("\nPick %d weapon skills:", gConfig->classes[get_class_string(sock->getPlayer()->getClass())]->numProfs());
		} else {
			sock->print("\nChoose a weapon skill:");
		}

		Create::handleWeapon(sock, mode, str[0]);
		sock->askFor("\n: ");
		Create::newline(sock);
		sock->setState(CREATE_GET_PROF);

	} else if(mode == Create::doWork) {

		if(Create::handleWeapon(sock, mode, str[0]))
			return(true);
		else {
			sock->print("Choose a weapon skill:\n");
			sock->setState(CREATE_GET_PROF);
			return(false);
		}
	}

	return(true);
}

//*********************************************************************
//						getSecondProf
//*********************************************************************

bool Create::getSecondProf(Socket* sock, char* str, int mode) {
	if(mode == Create::doPrint) {

		Create::handleWeapon(sock, mode, str[0]);

		sock->print("\nPick a second proficiency:\n");
		sock->askFor(": ");
		sock->setState(CREATE_SECOND_PROF);

	} else if(mode == Create::doWork) {

		if(Create::handleWeapon(sock, mode, str[0]))
			return(true);
		else {
			sock->print("Pick a second proficiency!\n");
			sock->askFor(": ");
			sock->setState(CREATE_SECOND_PROF);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						getPassword
//*********************************************************************

bool Create::getPassword(Socket* sock, char* str, int mode) {
	if(mode == Create::doPrint) {

		sock->print("\nYou must now choose a password. Remember that it\n");
		sock->print("is YOUR responsibility to remember this password. The staff\n");
		sock->print("at Realms will not give out password information to anyone\n");
		sock->print("at any time. Please write it down someplace, because if you\n");
		sock->print("forget it, you will no longer be able to play this character.\n\n");
		sock->print("Please choose a password (up to 14 chars): ");
		Create::newline(sock);

		sock->setState(CREATE_GET_PASSWORD);

	} else if(mode == Create::doWork) {

		if(!isValidPassword(sock, str)) {
			sock->print("\nChoose a password: ");
			Create::newline(sock);
			sock->setState(CREATE_GET_PASSWORD);
			return(false);
		}

		sock->getPlayer()->setFlag(P_PASSWORD_CURRENT);

		//t = time(0);
		//strcpy(sock->getPlayer()->last_mod, ctime(&t));

		sock->getPlayer()->setPassword(str);

	}
	return(true);
}

//*********************************************************************
//						done
//*********************************************************************

void Create::done(Socket* sock, char* str, int mode) {

	if(mode == Create::doPrint) {

		char file[80];
		sprintf(file, "%s/policy_login.txt", CONFPATH);
		viewLoginFile(sock, file);

		sock->print("[Press Enter to Continue]");
		Create::newline(sock);
		sock->setState(CREATE_DONE);

	} else if(mode == Create::doWork) {
		Player* player = sock->getPlayer();
		long t = time(0);
		int i=0;

		player->setBirthday();
		player->setCreated();

		strcpy(player->name, sock->tempstr[0]);

		if(gServer->checkDuplicateName(sock, false))
			return;
		if(gServer->checkDouble(sock))
			return;
		if(Player::exists(player->name)) {
			sock->printColor("\n\n^ySorry, that player already exists.^x\n\n\n");
			sock->reconnect();
			return;
		}

		player->lasttime[LT_AGE].interval = 0;
		t = time(0);

		for(i=0; i<MAX_LT; i++)
			player->lasttime[i].ltime = t;

		// Moved here so con affects a level 1's hp
		player->adjustStats();
		player->upLevel();

		player->addSkill("defense", 1);
		// Give out parry & block
		switch(player->getClass()) {
		// These classes get block + parry
			case ASSASSIN:
			case BARD:
			case FIGHTER:
			case RANGER:
			case ROGUE:
			case PALADIN:
			case DEATHKNIGHT:
				player->addSkill("block", 1);
				// fall through for parry
			case THIEF:
				player->addSkill("parry", 1);
				break;
			case BERSERKER:
				player->addSkill("block", 1);
				// Zerkers are more brute force than finnese...no parry
				break;
			default:
				break;
		}
		// Give out armor skills here
		switch(player->getClass()) {
			case BARD:
			case BERSERKER:
			case FIGHTER:
			case PALADIN:
			case DEATHKNIGHT:
			case RANGER:
				player->addSkill("plate", 1);
				player->addSkill("chain", 1);
			case ASSASSIN:
			case THIEF:
			case ROGUE:
			case VAMPIRE:
			case DRUID:
			case CLERIC:
				player->addSkill("leather", 1);
			case MAGE:
			case MONK:
			case LICH:
			case WEREWOLF:
			default:
				player->addSkill("cloth", 1);
				break;
		}

		// A few clerics get plate
		if(player->getClass() == CLERIC && !player->getSecondClass()) {
			if(player->getDeity() == ENOCH || player->getDeity() == ARES || player->getDeity() == GRADIUS) {
				player->addSkill("plate", 1);
				player->addSkill("chain", 1);
			}
		}

		// TODO: Dom: make this mage only
		if(player->getClass() != BERSERKER) {
			player->addSkill("abjuration", 1);
			player->addSkill("conjuration", 1);
			player->addSkill("divination", 1);
			player->addSkill("enchantment", 1);
			player->addSkill("evocation", 1);
			player->addSkill("illusion", 1);
			player->addSkill("necromancy", 1);
			player->addSkill("translocation", 1);
			player->addSkill("transmutation", 1);

			player->addSkill("fire", 1);
			player->addSkill("water", 1);
			player->addSkill("earth", 1);
			player->addSkill("air", 1);
			player->addSkill("cold", 1);
			player->addSkill("electric", 1);
		}

		if(player->getClass() == LICH)
			player->learnSpell(S_SAP_LIFE);

		Create::addStartingItem(player, "tut", 10, true);
		Create::addStartingItem(player, "tut", 11, true);
		Create::addStartingItem(player, "tut", 12, true);
		Create::addStartingItem(player, "tut", 13, true);

		player->fd = sock->getFd();
		player->setSock(sock);
		sock->setPlayer(player);
		player->init();

		sock->print("\n");

//		player->adjustStats();

		player->setFlag(P_NO_AUTO_ATTACK);
		player->setFlag(P_LAG_PROTECTION_SET);

		if(player->getClass() == BARD)
			player->learnSong(SONG_HEAL);

		player->save(true);
		gServer->addPlayer(player);

		sock->print("Type 'welcome' at prompt to get more info on the game\nand help you get started.\n");

		sock->setState(CON_PLAYING);
	}
}

//*********************************************************************
//						adjustStats
//*********************************************************************

void Creature::adjustStats() {
	strength.restore();
	dexterity.restore();
	constitution.restore();
	intelligence.restore();
	piety.restore();

	strength.setInitial(strength.getCur());
	dexterity.setInitial(dexterity.getCur());
	constitution.setInitial(constitution.getCur());
	intelligence.setInitial(intelligence.getCur());
	piety.setInitial(piety.getCur());


	if(deity) {
		switch(deity) {
		case ARAMON:
		case ARACHNUS:
			alignment = -100;
			break;
		case ENOCH:
		case LINOTHAN:
		case KAMIRA:
			alignment = 100;
			break;
		}
	}

	if(cClass == LICH)
		alignment = -100;
}

//*********************************************************************
//						CustomCrt
//*********************************************************************

CustomCrt::CustomCrt() {
	community = parents = brothers = sisters = social = education = height = weight = 0;
	hair = eyes = skin = "";
}

//*********************************************************************
//						getCommunity
//*********************************************************************

bool Create::getCommunity(Socket* sock, char* str, int mode) {
	if(mode == Create::doPrint) {

		sock->print("\nYour Community\n\n");
		// these match up with the defines in CustomCrt
		sock->printColor("   [^Wa^x] You lived in the wilderness, shunning contact with most of your community.\n");
		sock->printColor("   [^Wb^x] Your home was a small hamlet far from major cities.\n");
		sock->printColor("   [^Wc^x] You lived in village that saw a fair amount of trading.\n");
		sock->printColor("   [^Wd^x] The large town you grew up in was fairly well known.\n");
		sock->printColor("   [^We^x] You grew up in a major city.\n\n");

		sock->askFor(": ");
		Create::newline(sock);

		sock->setState(CUSTOM_COMMUNITY);

	} else if(mode == Create::doWork) {

		switch(str[0]) {
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
			// these match up with the defines in CustomCrt, so we can just assign
			sock->getPlayer()->custom.community = str[0]-'a'+1;
			break;
		default:
			sock->printColor("Invalid selection: ^W%s\n", str);
			sock->askFor("Choose one: ");
			Create::newline(sock);

			sock->setState(CUSTOM_COMMUNITY);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						doFamily
//*********************************************************************

void Create::doFamily(Player* player, int mode) {

	if(mode == 1) {
		player->custom.parents = CustomCrt::PARENTS_UNKNOWN;
		return;
	}

	// siblings
	int i = 0;
	if(mode == 3)
		i = mrand(1,3);
	else if(mode == 4)
		i = mrand(4, 10);

	while(i) {
		if(mrand(0,1))
			player->custom.sisters++;
		else
			player->custom.brothers++;
		i--;
	}

	switch(mrand(1,6)) {
	case 1:
		player->custom.parents = CustomCrt::PARENTS_DEAD;
		break;
	case 2:
		player->custom.parents = CustomCrt::PARENTS_MOTHER_DEAD;
		break;
	case 3:
		player->custom.parents = CustomCrt::PARENTS_FATHER_DEAD;
		break;
	// 50% chance of them being alive
	default:
		player->custom.parents = CustomCrt::PARENTS_ALIVE;
		break;
	}
}

//*********************************************************************
//						getFamily
//*********************************************************************

bool Create::getFamily(Socket* sock, char* str, int mode) {
	if(mode == Create::doPrint) {

		sock->print("\nYour Family\n\n");
		sock->printColor("   [^Wa^x] You were orphaned as a child and have no family.\n");
		sock->printColor("   [^Wb^x] You are an only child.\n");
		sock->printColor("   [^Wc^x] You grew up in a small family with 1-3 siblings.\n");
		sock->printColor("   [^Wd^x] The grew up in a large family with 4-10 siblings.\n\n");

		sock->askFor(": ");
		Create::newline(sock);

		sock->setState(CUSTOM_FAMILY);

	} else if(mode == Create::doWork) {

		switch(str[0]) {
		case 'a':
		case 'b':
		case 'c':
		case 'd':
			doFamily(sock->getPlayer(), str[0]-'a'+1);
			break;
		default:
			sock->printColor("Invalid selection: ^W%s\n", str);
			sock->askFor("Choose one: ");
			Create::newline(sock);

			sock->setState(CUSTOM_FAMILY);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						getSocial
//*********************************************************************

bool Create::getSocial(Socket* sock, char* str, int mode) {
	CustomCrt *custom = &sock->getPlayer()->custom;

	if(mode == Create::doPrint) {

		sock->print("\nYour Social Status\n\n");
		if(custom->parents == CustomCrt::PARENTS_UNKNOWN)
			sock->printColor("   [^Wa^x] You were an outcast in society.\n");
		else
			sock->printColor("   [^Wa^x] You and your family were outcasts in society.\n");

		if(custom->community != CustomCrt::COMMUNITY_OUTCAST) {
			sock->printColor("   [^Wb^x] You were considered a criminal (justly so or not).\n");
			sock->printColor("   [^Wc^x] You grew up poor and on the lowest rungs of society.\n");
			sock->printColor("   [^Wd^x] You had to work hard to provide for yourself, but were able to manage.\n");

			if(custom->community != CustomCrt::COMMUNITY_HAMLET) {
				if(custom->parents == CustomCrt::PARENTS_UNKNOWN)
					sock->printColor("   [^We^x] Your life was easier than most as you were fairly well off.\n");
				else
					sock->printColor("   [^We^x] Your life was easier than most as you and your family were fairly well off.\n");

				if(custom->community != CustomCrt::COMMUNITY_VILLAGE && custom->parents != CustomCrt::PARENTS_UNKNOWN) {
					sock->printColor("   [^Wf^x] You and your family were well off in society and did not need to worry about much.\n");
					sock->printColor("   [^Wg^x] Being of noble descent, you and your family were well known in the community.\n");
				}
			}
		}
		sock->print("\n");

		sock->askFor(": ");
		Create::newline(sock);

		sock->setState(CUSTOM_SOCIAL);

	} else if(mode == Create::doWork) {

		if(	(str[0] > 'a' && custom->community == CustomCrt::COMMUNITY_OUTCAST) ||
			(str[0] > 'd' && custom->community == CustomCrt::COMMUNITY_HAMLET) ||
			(str[0] > 'e' && (custom->community == CustomCrt::COMMUNITY_VILLAGE || custom->parents == CustomCrt::PARENTS_UNKNOWN))
		)
			str[0] = 'z';

		switch(str[0]) {
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
		case 'f':
		case 'g':
			custom->social = str[0]-'a'+1;
			break;
		default:
			sock->printColor("Invalid selection: ^W%s\n", str);
			sock->askFor("Choose one: ");
			Create::newline(sock);

			sock->setState(CUSTOM_SOCIAL);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						getEducation
//*********************************************************************

bool Create::getEducation(Socket* sock, char* str, int mode) {
	CustomCrt *custom = &sock->getPlayer()->custom;

	if(mode == Create::doPrint) {

		sock->print("\nYour Education\n\n");
		sock->printColor("   [^Wa^x] You have no formal education.\n");

		if(custom->community != CustomCrt::COMMUNITY_OUTCAST && custom->social != CustomCrt::SOCIAL_OUTCAST) {
			sock->printColor("   [^Wb^x] You trained as an apprentice to a trader, crafstman, or farmer.\n");
			sock->printColor("   [^Wc^x] You attended a local school and received a basic education.\n");

			if(custom->community != CustomCrt::COMMUNITY_HAMLET && custom->social > CustomCrt::SOCIAL_LOWER) {
				sock->printColor("   [^Wd^x] You received a decent education or were tutored in several subject areas.\n");
				sock->printColor("   [^We^x] You attended a large university and received an official degree.\n");
			}

		}

		sock->askFor(": ");
		Create::newline(sock);

		sock->setState(CUSTOM_EDUCATION);

	} else if(mode == Create::doWork) {

		if(	(str[0] > 'a' && (custom->community == CustomCrt::COMMUNITY_OUTCAST || custom->social == CustomCrt::SOCIAL_OUTCAST)) ||
			(str[0] > 'c' && (custom->community == CustomCrt::COMMUNITY_HAMLET || custom->social <= CustomCrt::SOCIAL_LOWER))
		)
			str[0] = 'z';

		switch(str[0]) {
		case 'a':
		case 'b':
		case 'c':
		case 'd':
		case 'e':
			custom->education = str[0]-'a'+1;
			break;
		default:
			sock->printColor("Invalid selection: ^W%s\n", str);
			sock->askFor("Choose one: ");
			Create::newline(sock);

			sock->setState(CUSTOM_EDUCATION);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						calcHeight
//*********************************************************************

int Create::calcHeight(int race, int mode) {
	switch(mode) {
	case 1:		// shorter
		return(mrand(1,50));
	case 3:		// taller
		return(mrand(100,150));
	default:	// normal
		return(mrand(50,100));
	}
}

//*********************************************************************
//						getHeight
//*********************************************************************

bool Create::getHeight(Socket* sock, char* str, int mode) {
	if(mode == Create::doPrint) {

		sock->print("\nYour Height\n\n");
		sock->printColor("   [^Wa^x] You are shorter than most members of your race.\n");
		sock->printColor("   [^Wb^x] Your height is average.\n");
		sock->printColor("   [^Wc^x] You are taller than most members of your race.\n\n");

		sock->askFor(": ");
		Create::newline(sock);

		sock->setState(CUSTOM_HEIGHT);

	} else if(mode == Create::doWork) {

		switch(str[0]) {
		case 'a':
		case 'b':
		case 'c':
			sock->getPlayer()->custom.height = Create::calcHeight(sock->getPlayer()->getRace(), str[0]-'a'+1);
			break;
		default:
			sock->printColor("Invalid selection: ^W%s\n", str);
			sock->askFor("Choose one: ");
			Create::newline(sock);

			sock->setState(CUSTOM_HEIGHT);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						calcWeight
//*********************************************************************

int Create::calcWeight(int race, int mode) {
	switch(mode) {
	case 1:		// thinner
		return(mrand(1,50));
	case 3:		// stockier
		return(mrand(100,150));
	default:	// normal
		return(mrand(50,100));
	}
}

//*********************************************************************
//						getWeight
//*********************************************************************

bool Create::getWeight(Socket* sock, char* str, int mode) {
	if(mode == Create::doPrint) {

		sock->print("\nYour Weight\n\n");
		sock->printColor("   [^Wa^x] You are thinner than most members of your race.\n");
		sock->printColor("   [^Wb^x] Your weight is average.\n");
		sock->printColor("   [^Wc^x] You are heavier than most members of your race.\n\n");

		sock->askFor(": ");
		Create::newline(sock);

		sock->setState(CUSTOM_WEIGHT);

	} else if(mode == Create::doWork) {

		switch(str[0]) {
		case 'a':
		case 'b':
		case 'c':
			sock->getPlayer()->custom.weight = Create::calcWeight(sock->getPlayer()->getRace(), str[0]-'a'+1);
			break;
		default:
			sock->printColor("Invalid selection: ^W%s\n", str);
			sock->askFor("Choose one: ");
			Create::newline(sock);

			sock->setState(CUSTOM_WEIGHT);
			return(false);
		}

	}
	return(true);
}

//*********************************************************************
//						nameIsAllowed
//*********************************************************************
// Return: Is the name allowed? true/false
// Parameters:
//	str:  The name we're testing
//	sock: The socket to print error messages to

bool nameIsAllowed(char *str, Socket* sock) {
	int i=0, nonalpha=0, len = strlen(str);

	if(!isalpha(str[0]))
		return(false);

	if(!checkWinFilename(sock, str))
		return(false);

	if(len < 3) {
		sock->print("Name must be at least 3 characters.\n");
		return(false);
	}
	if(len >= 20) {
		sock->print("Name must be less than 20 characters.\n");
		return(false);
	}

	for(i=0; i< (int)strlen(str); i++)
		if(!isalpha(str[i]))
			nonalpha++;

	if(nonalpha && len < 6) {
		sock->print("Name must be at least 6 characters in order to contain a - or '.\n");
		return(false);
	}

	if(nonalpha > 1) {
		sock->print("May not have more than one non-alpha character in your name.\n");
		return(false);
	}

	for(i=0; i<len; i++) {
		if(!isalpha(str[i])) {
			sock->print("Name must be alphabetic.\n");
			return(false);
		}
	}


	if(!parse_name(str)) {
		sock->print("That name is not allowed.\n");
		return(false);
	}
	return(true);
}

//*********************************************************************
//						addDouble
//*********************************************************************

void Config::addDoubleLog(bstring forum1, bstring forum2) {
	if(forum1 == "" || forum2 == "")
		return;
	if(canDoubleLog(forum1, forum2))
		return;

	accountDouble pair;
	pair.first = forum1;
	pair.second = forum2;
	accountDoubleLog.push_back(pair);

	gConfig->saveDoubleLog();
}

//*********************************************************************
//						remDouble
//*********************************************************************

void Config::remDoubleLog(bstring forum1, bstring forum2) {
	std::list<accountDouble>::iterator it;

	if(forum1 == "" || forum2 == "")
		return;

	for(it = accountDoubleLog.begin(); it != accountDoubleLog.end() ; it++) {
		if(	((*it).first == forum1 && (*it).second == forum2) ||
			((*it).first == forum2 && (*it).second == forum1)
		) {
			accountDoubleLog.erase(it);
			gConfig->saveDoubleLog();
			return;
		}
	}
}

//*********************************************************************
//						canDoubleLog
//*********************************************************************

bool Config::canDoubleLog(bstring forum1, bstring forum2) const {
	std::list<accountDouble>::const_iterator it;

	if(forum1 == "" || forum2 == "")
		return(false);

	for(it = accountDoubleLog.begin(); it != accountDoubleLog.end() ; it++) {
		if(	((*it).first == forum1 && (*it).second == forum2) ||
			((*it).first == forum2 && (*it).second == forum1)
		)
			return(true);
	}

	return(false);
}

//*********************************************************************
//						saveDoubleLog
//*********************************************************************

bool Config::loadDoubleLog() {
	xmlDocPtr xmlDoc;
	xmlNodePtr curNode, childNode;
	bstring account = "";

	xmlDoc = xml::loadFile(CONFPATH "doubleLog.xml", "DoubleLog");

	if(xmlDoc == NULL)
		return(false);

	curNode = xmlDocGetRootElement(xmlDoc);
	curNode = curNode->children;
	while(curNode && xmlIsBlankNode(curNode))
		curNode = curNode->next;

	if(curNode == 0) {
		xmlFreeDoc(xmlDoc);
		return(false);
	}

	accountDoubleLog.clear();
	while(curNode != NULL) {
		if(NODE_NAME(curNode, "Accounts")) {
			childNode = curNode->children;
			account = "";
			while(childNode) {
				if(NODE_NAME(childNode, "Forum1") || NODE_NAME(childNode, "Forum2")) {
					if(account == "") {
						// cache!
						xml::copyToBString(account, childNode);
					} else {
						// add!
						addDoubleLog(account, xml::getBString(childNode));
						account = "";
					}
				}
				childNode = childNode->next;
			}
		}
		curNode = curNode->next;
	}
	xmlFreeDoc(xmlDoc);
	xmlCleanupParser();
	return(true);
}

//*********************************************************************
//						saveDoubleLog
//*********************************************************************

void Config::saveDoubleLog() const {
	std::list<accountDouble>::const_iterator it;
	xmlDocPtr	xmlDoc;
	xmlNodePtr		rootNode, curNode;
	char			filename[80];

	xmlDoc = xmlNewDoc(BAD_CAST "1.0");
	rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "DoubleLog", NULL);
	xmlDocSetRootElement(xmlDoc, rootNode);

	for(it = accountDoubleLog.begin(); it != accountDoubleLog.end() ; it++) {
		curNode = xml::newStringChild(rootNode, "Accounts");
		xml::saveNonNullString(curNode, "Forum1", (*it).first);
		xml::saveNonNullString(curNode, "Forum2", (*it).second);
	}

	sprintf(filename, "%s/doubleLog.xml", CONFPATH);
	xml::saveFile(filename, xmlDoc);
	xmlFreeDoc(xmlDoc);
}

//*********************************************************************
//						listDoubleLog
//*********************************************************************

void Config::listDoubleLog(const Player* viewer) const {
	std::list<accountDouble>::const_iterator it;

	viewer->printColor("^YAccounts that may double log:\n");
	for(it = accountDoubleLog.begin(); it != accountDoubleLog.end() ; it++) {
		viewer->print("   %-20s %-20s\n", (*it).first.c_str(), (*it).second.c_str());
	}
}