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/
/*
 * catRefInfo.h
 *	 Category Reference info
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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"
#include "calendar.h"

#include <sstream>
#include <iomanip>
#include <locale>
#include <iostream>
#include <fstream>

//*********************************************************************
//						CatRefInfo
//*********************************************************************

CatRefInfo::CatRefInfo() { clear(); }
CatRefInfo::~CatRefInfo() { clear(); }

void CatRefInfo::clear() {
	id=0;
	parent = name = worldName = area = yearsSince = fishing = "";
	limbo = recall = 0;
	teleportWeight = teleportZone = trackZone = 0;
	yearOffset = 0;

	std::map<Season,cSeason*>::iterator st;
	cSeason *season=0;
	for(st = seasons.begin() ; st != seasons.end() ; st++) {
		season = (*st).second;
		delete season;
	}
	seasons.clear();
}

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

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

//*********************************************************************
//						getArea
//*********************************************************************

bstring CatRefInfo::getArea() const {
	return(area);
}

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

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

//*********************************************************************
//						getWorldName
//*********************************************************************

bstring CatRefInfo::getWorldName() const {
	return(worldName);
}

//*********************************************************************
//						getYearsSince
//*********************************************************************

bstring CatRefInfo::getYearsSince() const {
	return(yearsSince);
}

//*********************************************************************
//						getParent
//*********************************************************************

bstring CatRefInfo::getParent() const {
	return(parent);
}

//*********************************************************************
//						getYearOffset
//*********************************************************************

int CatRefInfo::getYearOffset() const {
	return(yearOffset);
}

//*********************************************************************
//						getLimbo
//*********************************************************************

int CatRefInfo::getLimbo() const {
	return(limbo);
}

//*********************************************************************
//						getRecall
//*********************************************************************

int CatRefInfo::getRecall() const {
	return(recall);
}

//*********************************************************************
//						getTeleportWeight
//*********************************************************************

int CatRefInfo::getTeleportWeight() const {
	return(teleportWeight);
}

//*********************************************************************
//						getTeleportZone
//*********************************************************************

int CatRefInfo::getTeleportZone() const {
	return(teleportZone);
}

//*********************************************************************
//						getTrackZone
//*********************************************************************

int CatRefInfo::getTrackZone() const {
	return(trackZone);
}

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

void CatRefInfo::load(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;

	id = xml::getIntProp(rootNode, "id");
	while(curNode) {
			 if(NODE_NAME(curNode, "Area")) xml::copyToBString(area, curNode);
		else if(NODE_NAME(curNode, "Name")) xml::copyToBString(name, curNode);
		else if(NODE_NAME(curNode, "Fishing")) xml::copyToBString(fishing, curNode);
		else if(NODE_NAME(curNode, "WorldName")) xml::copyToBString(worldName, curNode);
		else if(NODE_NAME(curNode, "YearsSince")) xml::copyToBString(yearsSince, curNode);
		else if(NODE_NAME(curNode, "Parent")) xml::copyToBString(parent, curNode);
		else if(NODE_NAME(curNode, "Limbo")) xml::copyToNum(limbo, curNode);
		else if(NODE_NAME(curNode, "YearOffset")) xml::copyToNum(yearOffset, curNode);
		else if(NODE_NAME(curNode, "Recall")) xml::copyToNum(recall, curNode);
		else if(NODE_NAME(curNode, "TeleportWeight")) xml::copyToNum(teleportWeight, curNode);
		else if(NODE_NAME(curNode, "TeleportZone")) xml::copyToNum(teleportZone, curNode);
		else if(NODE_NAME(curNode, "TrackZone")) xml::copyToNum(trackZone, curNode);
		else if(NODE_NAME(curNode, "Seasons")) loadSeasons(curNode);
		curNode = curNode->next;
	}

	// this would make an infinite loop
	if(parent == area)
		parent = "";
}

//*********************************************************************
//						save
//*********************************************************************

void CatRefInfo::save(xmlNodePtr curNode) const {
	xmlNodePtr deepNode,subNode,childNode = xml::newStringChild(curNode, "Info");
	xml::newNumProp(childNode, "id", id);

	xml::saveNonNullString(childNode, "Area", area);
	xml::saveNonNullString(childNode, "Name", name);
	xml::saveNonNullString(childNode, "WorldName", worldName);
	xml::saveNonNullString(childNode, "YearsSince", yearsSince);
	xml::saveNonNullString(childNode, "Parent", parent);
	xml::saveNonZeroNum(childNode, "Limbo", limbo);
	xml::saveNonZeroNum(childNode, "YearOffset", yearOffset);
	xml::saveNonZeroNum(childNode, "Recall", recall);
	xml::saveNonZeroNum(childNode, "TeleportWeight", teleportWeight);
	xml::saveNonZeroNum(childNode, "TeleportZone", teleportZone);
	xml::saveNonZeroNum(childNode, "Track", trackZone);

	subNode = xml::newStringChild(childNode, "Seasons");
	std::map<Season,cSeason*>::const_iterator st;
	for(st = seasons.begin() ; st != seasons.end() ; st++) {
		deepNode = xml::newStringChild(subNode, "Season");
		(*st).second->save(deepNode);
	}
}

//*********************************************************************
//						loadSeasons
//*********************************************************************

void CatRefInfo::loadSeasons(xmlNodePtr curNode) {
	xmlNodePtr childNode = curNode->children;
	cSeason* season=0;

	while(childNode) {
		if(NODE_NAME(childNode, "Season")) {
			season = new cSeason;
			season->load(childNode);
			if(seasons[season->getId()])
				delete seasons[season->getId()];
			seasons[season->getId()] = season;
		}
		childNode = childNode->next;
	}
}

//*********************************************************************
//						getWeather
//*********************************************************************

const cWeather* CatRefInfo::getWeather() const {
	std::map<Season,cSeason*>::const_iterator st;
	st = seasons.find(gConfig->getCalendar()->getCurSeason()->getId());
	if(st != seasons.end())
		return((*st).second->getWeather());
	return(0);
}

//*********************************************************************
//						str
//*********************************************************************

bstring CatRefInfo::str() const {
	std::ostringstream oStr;
	oStr << area;
	if(area == "area")
		oStr << " " << id;
	return(oStr.str());
}


//*********************************************************************
//						loadCatRefInfo
//*********************************************************************

bool Config::loadCatRefInfo() {
	xmlDocPtr xmlDoc;
	xmlNodePtr curNode;
	CatRefInfo *cri=0;
	const CatRefInfo *parent=0;

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

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

	curNode = xmlDocGetRootElement(xmlDoc);

	bstring d = "";
	xml::copyPropToBString(d, curNode, "default");
	if(d != "")
		gConfig->defaultArea = d;

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

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

	clearCatRefInfo();
	while(curNode != NULL) {
		if(NODE_NAME(curNode, "Info")) {
			cri = new CatRefInfo;
			cri->load(curNode);
			catRefInfo.push_back(cri);
		}
		curNode = curNode->next;
	}
	xmlFreeDoc(xmlDoc);
	xmlCleanupParser();

	// propogate: this happens once, so if we ever need to know info from the
	// parent, we never need to look for it
	std::list<CatRefInfo*>::iterator it;
	for(it = catRefInfo.begin() ; it != catRefInfo.end() ; it++) {
		cri = (*it);
		if(cri->getParent() != "") {
			parent = getCatRefInfo(cri->getParent(), 0, true);
			if(parent)
				cri->copyVars(parent);
		}
	}
	return(true);
}

//*********************************************************************
//						catRefName
//*********************************************************************

bstring Config::catRefName(bstring area) const {
	const CatRefInfo* cri = gConfig->getCatRefInfo(area);
	if(cri)
		return(cri->getName());
	return("");
}

//*********************************************************************
//						copyVars
//*********************************************************************
// only copy the vars it inherits from the parent

void CatRefInfo::copyVars(const CatRefInfo* cri) {
	teleportZone = cri->teleportZone;
	trackZone = cri->trackZone;
}

//*********************************************************************
//						copyVars
//*********************************************************************

void Config::clearCatRefInfo() {
	CatRefInfo* cr;

	while(!catRefInfo.empty()) {
		cr = catRefInfo.front();
		delete cr;
		catRefInfo.pop_front();
	}
	catRefInfo.clear();
}


//*********************************************************************
//						saveCatRefInfo
//*********************************************************************

void Config::saveCatRefInfo() const {
	std::list<CatRefInfo*>::const_iterator it;
	xmlDocPtr	xmlDoc;
	xmlNodePtr	rootNode;
	char			filename[80];

	xmlDoc = xmlNewDoc(BAD_CAST "1.0");
	rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "CatRefInfo", NULL);
	xmlDocSetRootElement(xmlDoc, rootNode);
	xml::newProp(rootNode, "default", defaultArea.c_str());

	for(it = catRefInfo.begin() ; it != catRefInfo.end() ; it++)
		(*it)->save(rootNode);

	sprintf(filename, "%s/catRefInfo.xml", Path::Game);
	xml::saveFile(filename, xmlDoc);
	xmlFreeDoc(xmlDoc);
}

//*********************************************************************
//						getCatRefInfo
//*********************************************************************

const CatRefInfo* Config::getCatRefInfo(bstring area, int id, int shouldGetParent) const {
	std::list<CatRefInfo*>::const_iterator it;

	// prevent infinite loops from bad config files
	if(shouldGetParent > 30) {
		broadcast(isCt, "^yConfig::getCatRefInfo is terminating because it is looping too long.\nCheck the catrefinfo config file for possible looping issues.\n");
		return(0);
	}
	for(it = catRefInfo.begin() ; it != catRefInfo.end() ; it++) {
		if(area == (*it)->getArea() && id == (*it)->getId()) {
			if(shouldGetParent && (*it)->getParent() != "")
				return(getCatRefInfo((*it)->getParent(), 0, shouldGetParent+1));
			return(*it);
		}
	}

	return(0);
}

//*********************************************************************
//						getCatRefInfo
//*********************************************************************

const CatRefInfo* Config::getCatRefInfo(const BaseRoom* room, int shouldGetParent) const {
	const AreaRoom* aRoom=0;
	const UniqueRoom* uRoom=0;
	int id = 0;
	bstring area = "";

	if(room) {
		uRoom = room->getAsConstUniqueRoom();
		aRoom = room->getAsConstAreaRoom();
	}

	if(uRoom) {
		area = uRoom->info.area;
	} else if(aRoom) {
		area = "area";
		id = aRoom->area->id;
	} else {
		area = "misc";
	}

	return(getCatRefInfo(area, id, shouldGetParent));
}

//*********************************************************************
//						getRandomCatRefInfo
//*********************************************************************
// used by teleport spell, so check teleportZone

const CatRefInfo* Config::getRandomCatRefInfo(int zone) const {
	std::list<CatRefInfo*>::const_iterator it;
	int total=0, pick=0;

	for(it = catRefInfo.begin() ; it != catRefInfo.end() ; it++) {
		if(!zone || zone == (*it)->getTeleportZone())
			total += (*it)->getTeleportWeight();
	}
	if(!total)
		return(0);

	pick = mrand(1, total);
	total = 0;

	for(it = catRefInfo.begin() ; it != catRefInfo.end() ; it++) {
		if(!zone || zone == (*it)->getTeleportZone()) {
			total += (*it)->getTeleportWeight();
			if(total >= pick)
				return(*it);
		}
	}
	return(0);
}

//*********************************************************************
//						dmCatRefInfo
//*********************************************************************

int dmCatRefInfo(Player* player, cmd* cmnd) {
	std::list<CatRefInfo*>::const_iterator it;
	std::ostringstream oStr;
	const CatRefInfo *cri=0;
	int i=0;

	oStr.setf(std::ios::left, std::ios::adjustfield);
	oStr << "^yCatRefInfo List^x\n";

	for(it = gConfig->catRefInfo.begin() ; it != gConfig->catRefInfo.end() ; it++) {
		cri = (*it);
		i = 20;
		if(cri->getName().getAt(0) == '^')
			i += 2;
		oStr << "  Area: ^c" << std::setw(10) << cri->str()
			 << "^x Name: ^c" << std::setw(i)
			 << cri->getName() << "^x ";
		if(cri->getParent() == "") {
			oStr << "TeleportZone: ^c" << std::setw(4) << cri->getTeleportZone() << "^x "
				 << "TrackZone: ^c" << std::setw(4) << cri->getTrackZone() << "^x "
				 << "TeleportWeight: ^c" << cri->getTeleportWeight();
			if(cri->getFishing() != "")
				oStr << " Fishing: ^c" << cri->getFishing();
			oStr << "^x\n"
				 << "                                              "
				 << "Limbo: ^c" << cri->getLimbo() << "^x    Recall: ^c" << cri->getRecall() << "^x\n";
		} else {
			oStr << "Parent: ^c" << cri->getParent() << "^x "
				 << "TeleportWeight: ^c" << cri->getTeleportWeight();
			if(cri->getFishing() != "")
				oStr << " Fishing: ^c" << cri->getFishing();
			oStr << "^x\n";
		}
	}

	player->printColor("%s\n", oStr.str().c_str());
	return(0);
}