roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
/*
 * playerClass.cpp
 *	 Player Class
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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-2012 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"


//*********************************************************************
//						PlayerClass
//*********************************************************************

PlayerClass::PlayerClass(xmlNodePtr rootNode) {
	needDeity = false;
	numProf = 1;
	hasAutomaticStats = false;
	baseStrength=-1;
	baseDexterity=-1;
	baseConstitution=-1;
	baseIntelligence=-1;
	basePiety=-1;
	unarmedWeaponSkill = "bare-hand";
	load(rootNode);
}

PlayerClass::~PlayerClass() {
	std::list<SkillGain*>::iterator bsIt;
	std::map<int, LevelGain*>::iterator lgIt;
	std::map<int, PlayerTitle*>::iterator tt;
	SkillGain* sGain;
	LevelGain* lGain;

	for(bsIt = baseSkills.begin() ; bsIt != baseSkills.end() ; bsIt++) {
		sGain = (*bsIt);
		delete sGain;
	}
	baseSkills.clear();
	for(lgIt = levels.begin() ; lgIt != levels.end() ; lgIt++) {
		lGain = (*lgIt).second;
		delete lGain;
	}
	levels.clear();

	for(tt = titles.begin() ; tt != titles.end() ; tt++) {
		PlayerTitle* p = (*tt).second;
		delete p;
	}
	titles.clear();
}

//*********************************************************************
//						load
//*********************************************************************

void PlayerClass::load(xmlNodePtr rootNode) {
//	// Stuff gained on each additional level
//	std::map<int, LevelGain*> levels;

	id = xml::getIntProp(rootNode, "id");
	xml::copyPropToBString(name, rootNode, "Name");

	xmlNodePtr curNode = rootNode->children;

	while(curNode) {
		if(NODE_NAME(curNode, "Title")) {
			titles[1] = new PlayerTitle;
			titles[1]->load(curNode);
		}
		else if(NODE_NAME(curNode, "UnarmedWeaponSkill")) xml::copyToBString(unarmedWeaponSkill, curNode);
		else if(NODE_NAME(curNode, "NumProfs")) xml::copyToNum(numProf, curNode);
		else if(NODE_NAME(curNode, "NeedsDeity")) {
			int i=0;
			xml::copyToNum(i, curNode);
			if(i)
				needDeity = true;
		} else if(NODE_NAME(curNode, "Base")) {
			xmlNodePtr baseNode = curNode->children;
			while(baseNode) {
				if(NODE_NAME(baseNode, "Stats")) {
					xmlNodePtr statNode = baseNode->children;
					while(statNode) {
						if(NODE_NAME(statNode, "Hp")) {
							xml::copyToNum(baseHp, statNode);
						} else if(NODE_NAME(statNode, "Mp")) {
							xml::copyToNum(baseMp, statNode);
						} else if(NODE_NAME(statNode, "Strength")) {
							xml::copyToNum(baseStrength, statNode);
							checkAutomaticStats();
						} else if(NODE_NAME(statNode, "Dexterity")) {
							xml::copyToNum(baseDexterity, statNode);
							checkAutomaticStats();
						} else if(NODE_NAME(statNode, "Constitution")) {
							xml::copyToNum(baseConstitution, statNode);
							checkAutomaticStats();
						} else if(NODE_NAME(statNode, "Intelligence")) {
							xml::copyToNum(baseIntelligence, statNode);
							checkAutomaticStats();
						} else if(NODE_NAME(statNode, "Piety")) {
							xml::copyToNum(basePiety, statNode);
							checkAutomaticStats();
						}
						statNode = statNode->next;
					}
				} else if(NODE_NAME(baseNode, "Dice")) damage.load(baseNode);
				else if(NODE_NAME(baseNode, "Skills")) {
					xmlNodePtr skillNode = baseNode->children;
					while(skillNode) {
						if(NODE_NAME(skillNode, "Skill")) {
							SkillGain* skillGain = new SkillGain(skillNode);
							baseSkills.push_back(skillGain);
						}
						skillNode = skillNode->next;
					}
				}
				baseNode = baseNode->next;
			}
		} else if(NODE_NAME(curNode, "Levels")) {
			xmlNodePtr levelNode = curNode->children;
			int lvl;
			while(levelNode) {
				if(NODE_NAME(levelNode, "Level")) {
					lvl = xml::getIntProp(levelNode, "Num");
					if(lvl > 0) {
						levels[lvl] = new LevelGain(levelNode);
					}

					xmlNodePtr childNode = levelNode->children;
					while(childNode) {
						if(NODE_NAME(childNode, "Title")) {
							titles[lvl] = new PlayerTitle;
							titles[lvl]->load(childNode);
						}
						childNode = childNode->next;
					}
				}
				levelNode = levelNode->next;
			}
		}

		curNode = curNode->next;

	}
}

//*********************************************************************
//						getId
//*********************************************************************

int PlayerClass::getId() const { return(id); }

//*********************************************************************
//						getName
//*********************************************************************

bstring PlayerClass::getName() const { return(name); }

//*********************************************************************
//						getUnarmedWeaponSkill
//*********************************************************************

bstring PlayerClass::getUnarmedWeaponSkill() const { return(unarmedWeaponSkill); }

//*********************************************************************
//						getSkillBegin
//*********************************************************************

std::list<SkillGain*>::const_iterator PlayerClass::getSkillBegin() { return(baseSkills.begin()); }

//*********************************************************************
//						getSkillEnd
//*********************************************************************

std::list<SkillGain*>::const_iterator PlayerClass::getSkillEnd() { return(baseSkills.end()); }

//*********************************************************************
//						getLevelBegin
//*********************************************************************

std::map<int, LevelGain*>::const_iterator PlayerClass::getLevelBegin() { return(levels.begin()); }

//*********************************************************************
//						getLevelEnd
//*********************************************************************

std::map<int, LevelGain*>::const_iterator PlayerClass::getLevelEnd() { return(levels.end()); }

//*********************************************************************
//						getBaseHp
//*********************************************************************

short PlayerClass::getBaseHp() { return(baseHp); }

//*********************************************************************
//						getBaseMp
//*********************************************************************

short PlayerClass::getBaseMp() { return(baseMp); }

//*********************************************************************
//						needsDeity
//*********************************************************************

bool PlayerClass::needsDeity() { return(needDeity); }

//*********************************************************************
//						numProfs
//*********************************************************************

short PlayerClass::numProfs() { return(numProf); }

//*********************************************************************
//						getLevelGain
//*********************************************************************

LevelGain* PlayerClass::getLevelGain(int lvl) { return(levels[lvl]); }

//*********************************************************************
//						hasDefaultStats
//*********************************************************************
bool PlayerClass::hasDefaultStats() { return(hasAutomaticStats); }

//*********************************************************************
//						setDefaultStats
//*********************************************************************
bool PlayerClass::setDefaultStats(Player* player) {
	if(!hasDefaultStats() || !player)
		return(false);

	player->strength.setInitial(baseStrength * 10);
	player->dexterity.setInitial(baseDexterity * 10);
	player->constitution.setInitial(baseConstitution * 10);
	player->intelligence.setInitial(baseIntelligence * 10);
	player->piety.setInitial(basePiety * 10);

	return(true);
}
//*********************************************************************
//						checkAutomaticStats
//*********************************************************************
void PlayerClass::checkAutomaticStats() {
	if(baseStrength != -1 && baseDexterity != -1 && baseConstitution != -1 && baseIntelligence != -1 && basePiety != -1) {
		std::cout << "Automatic stats registered for " << this->getName() << std::endl;
		hasAutomaticStats = true;
	}
}
//*********************************************************************
//						loadClasses
//*********************************************************************

bool Config::loadClasses() {
	xmlDocPtr xmlDoc;
	xmlNodePtr curNode;

	char filename[80];
	snprintf(filename, 80, "%s/classes.xml", Path::Game);
	xmlDoc = xml::loadFile(filename, "Classes");

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

	clearClasses();
	bstring className = "";
	while(curNode != NULL) {
		if(NODE_NAME(curNode, "Class")) {
			xml::copyPropToBString( className, curNode, "Name");
			if(className != "") {
				if(classes.find(className) == classes.end()) {
					//printf("\n\tLoaded %s", className.c_str());
					classes[className] = new PlayerClass(curNode);
				} else {
					printf("Error: Duplicate class: %s\n", className.c_str());
				}
			}
		}
		curNode = curNode->next;
	}
	xmlFreeDoc(xmlDoc);
	xmlCleanupParser();
	//printf("\n");
	return(true);
}

//*********************************************************************
//						clearClasses
//*********************************************************************

void Config::clearClasses() {
	std::map<bstring, PlayerClass*>::iterator pcIt;

	for(pcIt = classes.begin() ; pcIt != classes.end() ; pcIt++) {
		//printf("Erasing class %s\n", ((*pcIt).first).c_str());
		PlayerClass* pClass = (*pcIt).second;
		delete pClass;
	}
	classes.clear();
}

//*********************************************************************
//						dmShowClasses
//*********************************************************************

int dmShowClasses(Player* admin, cmd* cmnd) {

	bool	more = admin->isDm() && cmnd->num > 1 && !strcmp(cmnd->str[1], "more");
	bool	all = admin->isDm() && cmnd->num > 1 && !strcmp(cmnd->str[1], "all");

	std::map<bstring, PlayerClass*>::iterator cIt;
	PlayerClass* pClass;
	SkillGain* sGain;
	bstring tmp;

	admin->printColor("Displaying Classes:%s\n",
		admin->isDm() ? "  Type ^y*classlist more^x to view more, ^y*classlist all^x to view all information." : "");
	for(cIt = gConfig->classes.begin() ; cIt != gConfig->classes.end() ; cIt++) {
		pClass = (*cIt).second;
		admin->printColor("Id: ^c%-2d^x   Name: ^c%s\n", pClass->getId(), (*cIt).first.c_str());
		if(more || all) {
			std::ostringstream cStr;
			std::map<int, PlayerTitle*>::iterator tt;

			//cStr << "Class: " << (*cIt).first << "\n";
			cStr << "    Base: " << pClass->getBaseHp() << "hp, " << pClass->getBaseMp() << "mp, "
				 << "Dice: " << pClass->damage.str() << "\n"
				 << "    NumProfs: " << pClass->numProfs() << "   NeedsDeity: " << (pClass->needsDeity() ? "^gYes" : "^rNo") << "^x\n";
			std::list<SkillGain*>::const_iterator sgIt;
			if(all) {
				cStr << "    Skills: ";
				for(sgIt = pClass->getSkillBegin() ; sgIt != pClass->getSkillEnd() ; sgIt++) {
					sGain = *sgIt;
					cStr << gConfig->getSkillDisplayName(sGain->getName()) << "(" << sGain->getGained() << ") ";
				}
				std::map<int, LevelGain*>::const_iterator lgIt;

				cStr << "\n    Levels: ";
				for(lgIt = pClass->getLevelBegin() ; lgIt != pClass->getLevelEnd() ; lgIt ++) {
					LevelGain* lGain = (*lgIt).second;
					int lvl = (*lgIt).first;
					if(!lGain) {
						cStr << "\n ERROR: No level gain information found for " << pClass->getName() << " : " << lvl << ".";
						continue;
					}

					cStr << "\n        " << lvl << ": " << lGain->getHp() << "HP, " << lGain->getMp() << "MP, St:" << lGain->getStatStr() << ", Sa:" << lGain->getSaveStr();
					if(lGain->hasSkills()) {
						cStr << "\n        Skills:";
						for(sgIt = lGain->getSkillBegin() ; sgIt != lGain->getSkillEnd() ; sgIt++) {
							sGain = *sgIt;
							cStr << "\n            " << gConfig->getSkillDisplayName(sGain->getName()) << "(" << sGain->getGained() << ") ";
						}
					}
				}
				cStr << "\n    Titles: ";
				for(tt = pClass->titles.begin() ; tt != pClass->titles.end(); tt++) {
					PlayerTitle* title = (*tt).second;
					cStr << "\n        Level: ^c" << (*tt).first << "^x"
						<< "   Male: ^c" << title->getTitle(true) << "^x"
						<< "   Female: ^c" << title->getTitle(false) << "^x";
				}
			}
			cStr << "\n";
			tmp = cStr.str();
			admin->printColor("%s", tmp.c_str());
			gServer->processOutput();
		}
	}
	return(0);
}