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/
/*
 * config.cpp
 *   Handles config options for the entire mud
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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 "os.h"
#include "mud.h"
#include "bans.h"
#include "factions.h"
#include "guilds.h"
#include "calendar.h"

//#include "config.h"

// Globals
Config *gConfig = NULL;

// Static initialization
Config* Config::myInstance = NULL;

Config::Config() {
	reset();
	inUse = true;
}

Config::~Config() {
	if(inUse)
		throw new bstring("Error, trying to destroy config\n");
	else
		printf("Properly deconstructing Config class");
}

//--------------------------------------------------------------------
// Instance Functions

//********************************************************************
// Get Instance - Return the static instance of config
//********************************************************************
Config* Config::getInstance() {
	if(myInstance == NULL)
		myInstance = new Config;
	return(myInstance);
}
//********************************************************************
// Destroy Instance - Destroy the static instance
//********************************************************************
void Config::destroyInstance() {
	if(myInstance != NULL) {
		myInstance->cleanUp();
		delete myInstance;
	}
	myInstance = NULL;
}

// End - Instance Functions
//--------------------------------------------------------------------





//--------------------------------------------------------------------
// Memory Functions
void Config::cleanUp() {
	clearClans();
	clearGuildList();
	clearBanList();
	clearFactionList();
	clearSkills();
	calendar->clear();
	clearShips();
	clearClasses();
	clearRaces();
	clearRecipes();
	clearDeities();
	clearAreas();
	clearStartLoc();
	clearLimited();
	clearProperties();
	clearCatRefInfo();
	clearQuests();
	clearAlchemy();
	clearCommands();
	inUse = false;
}


//********************************************************************
// resetConfig
//********************************************************************
// Sets all config options to their default value.
void Config::reset() {
	roomHead =
	roomTail =
	monsterHead =
	monsterTail =
	objectHead =
	objectTail = 0;

	// These options default to true
	logSuicide = true;
	checkDouble = true;
	getHostByName = true;
	saveOnDrop = true;
	logDeath = true;

	// These options default to false
	conjureDisabled = false;
	lessExpLoss = false;
	pkillInCombatDisabled = false;
	autoShutdown = false;
	recordAll = false;
	charCreationDisabled = false;

	// Numerical defaults
	crashes = 0;
	supportRequiredForGuild = 2;
	minBroadcastLevel = 2;
	maxGuilds = 8;
	numGuilds = 0;

	dmPass = "default_dm_pw";
	webserver = qs = userAgent = "";

	lotteryEnabled = true;
	lotteryTicketPrice = 100;
	lotteryTicketsSold = 0;
	lotteryJackpot = 500000;
	lotteryWon = 0;
	lotteryWinnings = 0;
	lotteryRunTime = 0;

	lotteryNumbers[0] =
	lotteryNumbers[1] =
	lotteryNumbers[2] =
	lotteryNumbers[3] =
	lotteryNumbers[4] =
	lotteryNumbers[5] = 0;
	lotteryCycle = 1;

	if(!bHavePort)
		portNum = 3333;

	calendar = NULL;

	foreach(LottoTicket* ticket, tickets) {
		delete ticket;
	}

	tickets.clear();
	defaultArea = "oceancrest";
	movingRoom = roomSearchFailure = doAprilFools = txtOnCrash = someoneFishing = false;
	flashPolicyPort = 0;

	memset(customColors, CUSTOM_COLOR_DEFAULT, sizeof(customColors));
	customColors[CUSTOM_COLOR_SIZE-1] = 0;

	customColors[CUSTOM_COLOR_BROADCAST] = 'x';
	customColors[CUSTOM_COLOR_GOSSIP] = 'M';
	customColors[CUSTOM_COLOR_PTEST] = 'Y';
	customColors[CUSTOM_COLOR_NEWBIE] = 'M';
	customColors[CUSTOM_COLOR_DM] = 'g';
	customColors[CUSTOM_COLOR_ADMIN] = 'g';
	customColors[CUSTOM_COLOR_SEND] = 'Y';
	customColors[CUSTOM_COLOR_MESSAGE] = 'G';
	customColors[CUSTOM_COLOR_WATCHER] = 'C';
	customColors[CUSTOM_COLOR_CLASS] = 'y';
	customColors[CUSTOM_COLOR_RACE] = 'c';
	customColors[CUSTOM_COLOR_CLAN] = 'm';
	customColors[CUSTOM_COLOR_TELL] = 'x';
	customColors[CUSTOM_COLOR_GROUP] = 'g';
	customColors[CUSTOM_COLOR_DAMAGE] = 'm';
	customColors[CUSTOM_COLOR_SELF] = 'w';
	customColors[CUSTOM_COLOR_GUILD] = 'g';

	shopNumObjects = shopNumLines = 0;
}


bool Config::load() {
	printf("Initializing command table ...%s.\n", initCommands() ? "done" : "failed");

	printf("Loading Config...%s.\n", loadConfig() ? "done" : "failed");

	printf("Loading Recipes...%s.\n", loadRecipes() ? "done" : "failed");
	printf("Loading Flags...%s.\n", loadFlags() ? "done" : "failed");
	printf("Saving Spells...%s.\n", saveSpells() ? "done" : "failed");
	printf("Loading Spell List...%s.\n", loadSpellList() ? "done" : "failed");
	printf("Loading Quest Table...%s.\n", loadQuestTable() ? "done" : "failed");
	printf("Loading New Quests...%s.\n", loadQuests() ? "done" : "failed");
	printf("Loading StartLocs...%s.\n", loadStartLoc() ? "done" : "failed");
	printf("Loading Properties...%s.\n", loadProperties() ? "done" : "failed");
	printf("Loading CatRefInfo...%s.\n", loadCatRefInfo() ? "done" : "failed");

	printf("Loading Bans...%s.\n", loadBans() ? "done" : "failed");
	printf("Loading Fishing...%s.\n", loadFishing() ? "done" : "failed");
	printf("Loading Guilds...%s.\n", loadGuilds() ? "done" : "failed");
	printf("Loading Skills...%s.\n", loadSkills() ? "done" : "failed");

	printf("Loading Deities...%s.\n", loadDeities() ? "done" : "failed");
	printf("Loading Clans...%s.\n", loadClans() ? "done" : "failed");
	printf("Loading Classes...%s.\n", loadClasses() ? "done" : "failed");
	printf("Loading Races...%s.\n", loadRaces() ? "done" : "failed");
	printf("Loading Factions...%s.\n", loadFactions() ? "done" : "failed");
	printf("Loading Alchemy...%s.\n", loadAlchemy() ? "done" : "failed");
	printf("Loading Limited Items...%s.\n", loadLimited() ? "done" : "failed");
	printf("Loading Double Log Info...%s.\n", loadDoubleLog() ? "done" : "failed");

	printf("Loading Calendar...");
	loadCalendar();
	printf("done.\n");

	printf("Loading Areas...%s.\n", loadAreas() ? "done" : "failed");
	printf("Loading Ships...%s.\n", loadShips() ? "done" : "failed");

	return(true);
}

bool Config::startFlashPolicy() const {
	return(false);
	char script[256], policy[256], cmd[256];

	if(!flashPolicyPort) {
		broadcast(isDm, "^oNo flash policy port specified.");
		return(false);
	}
	if(flashPolicyPort == portNum) {
		broadcast(isDm, "^oFlash policy port equals main mud port.");
		return(false);
	}

	sprintf(script, "%sflashpolicyd.py", BINPATH);
	if(!file_exists(script)) {
		broadcast(isDm, "^oUnable to find flash policy server.");
		return(false);
	}

	sprintf(policy, "%sflashpolicy.xml", CONFPATH);
	if(!file_exists(policy)) {
		broadcast(isDm, "^oUnable to find flash policy file.");
		return(false);
	}

	if(!fork()) {
		sprintf(cmd, "python %s --file=%s --port=%d", script, policy, flashPolicyPort);
		system(cmd);
		exit(0);
	}
	return(true);
}

bool Config::loadConfig() {
	char filename[256];
	xmlDocPtr	xmlDoc;
	xmlNodePtr	rootNode;
	xmlNodePtr	curNode;

	sprintf(filename, "%s/config.xml", CONFPATH);

	if(!file_exists(filename))
		return(false);

	if((xmlDoc = xml::loadFile(filename, "Config")) == NULL)
		return(false);

	rootNode = xmlDocGetRootElement(xmlDoc);
	curNode = rootNode->children;

	// Reset current config
	reset();
	while(curNode) {
			 if(NODE_NAME(curNode, "General")) loadGeneral(curNode);
		else if(NODE_NAME(curNode, "Lottery")) loadLottery(curNode);

		curNode = curNode->next;
	}

	xmlFreeDoc(xmlDoc);
	xmlCleanupParser();
	return(true);
}

void Config::loadGeneral(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;

	while(curNode) {
			 if(NODE_NAME(curNode, "AutoShutdown")) xml::copyToBool(autoShutdown, curNode);
		else if(NODE_NAME(curNode, "AprilFools")) xml::copyToBool(doAprilFools, curNode);
		else if(NODE_NAME(curNode, "FlashPolicyPort")) xml::copyToNum(flashPolicyPort, curNode);
		else if(NODE_NAME(curNode, "CharCreationDisabled")) xml::copyToBool(charCreationDisabled, curNode);
		else if(NODE_NAME(curNode, "CheckDouble")) xml::copyToBool(checkDouble, curNode);
		else if(NODE_NAME(curNode, "GetHostByName")) xml::copyToBool(getHostByName, curNode);
		else if(NODE_NAME(curNode, "LessExpLoss")) xml::copyToBool(lessExpLoss, curNode);
		else if(NODE_NAME(curNode, "LogDeath")) xml::copyToBool(logDeath, curNode);
		else if(NODE_NAME(curNode, "PkillInCombatDisabled")) xml::copyToBool(pkillInCombatDisabled, curNode);
		else if(NODE_NAME(curNode, "RecordAll")) xml::copyToBool(recordAll, curNode);
		else if(NODE_NAME(curNode, "LogSuicide")) xml::copyToBool(logSuicide, curNode);
		else if(NODE_NAME(curNode, "SaveOnDrop")) xml::copyToBool(saveOnDrop, curNode);
		else if(NODE_NAME(curNode, "MaxGuild")) xml::copyToNum(maxGuilds, curNode);
		else if(NODE_NAME(curNode, "DmPass")) xml::copyToBString(dmPass, curNode);
		else if(NODE_NAME(curNode, "Webserver")) xml::copyToBString(webserver, curNode);
		else if(NODE_NAME(curNode, "QS")) xml::copyToBString(qs, curNode);
		else if(NODE_NAME(curNode, "UserAgent")) xml::copyToBString(userAgent, curNode);
		else if(NODE_NAME(curNode, "ShopNumObjects")) xml::copyToNum(shopNumObjects, curNode);
		else if(NODE_NAME(curNode, "ShopNumLines")) xml::copyToNum(shopNumLines, curNode);
		else if(NODE_NAME(curNode, "CustomColors")) xml::copyToCString(customColors, curNode);
		else if(!bHavePort && NODE_NAME(curNode, "Port")) xml::copyToNum(portNum, curNode);

		curNode = curNode->next;
	}
}


void Config::loadLottery(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;

	while(curNode) {
			 if(NODE_NAME(curNode, "Enabled")) xml::copyToBool(lotteryEnabled, curNode);
		else if(NODE_NAME(curNode, "curNoderentCycle")) xml::copyToNum(lotteryCycle, curNode);
		else if(NODE_NAME(curNode, "curNoderentJackpot")) xml::copyToNum(lotteryJackpot, curNode);
		else if(NODE_NAME(curNode, "TicketPrice")) xml::copyToNum(lotteryTicketPrice, curNode);
		else if(NODE_NAME(curNode, "LotteryWon")) xml::copyToBool(lotteryWon, curNode);
		else if(NODE_NAME(curNode, "TicketsSold")) xml::copyToNum(lotteryTicketsSold, curNode);
		else if(NODE_NAME(curNode, "WinningsThisCycle")) xml::copyToNum(lotteryWinnings, curNode);
		else if(NODE_NAME(curNode, "LotteryRunTime")) xml::copyToNum(lotteryRunTime, curNode);

		else if(NODE_NAME(curNode, "WinningNumbers")) {
			xml::loadNumArray<short>(curNode, lotteryNumbers, "LotteryNum", 6);
		}
		else if(NODE_NAME(curNode, "Tickets")) {
			loadTickets(curNode);
		}

		curNode = curNode->next;
	}
}

void Config::loadTickets(xmlNodePtr rootNode) {
	xmlNodePtr curNode = rootNode->children;
	LottoTicket* ticket=0;

	while(curNode) {
		if(NODE_NAME(curNode, "Ticket")) {
			 if((ticket = new LottoTicket(curNode)) != NULL) {
				 tickets.push_back(ticket);
			 }
		}

		curNode = curNode->next;
	}
}

unsigned long Config::expNeeded(int level) {
	if(level < 1)
		return(0);
	if(level > MAXALVL)
		return(MAXINT);
	return(needed_exp[level-1]);
}

bool Config::save() const {
	saveConfig();
	return(true);
}

// Functions to get configured options
bool Config::saveConfig() const {
	xmlDocPtr	xmlDoc;
	xmlNodePtr		rootNode, curNode;
	char			filename[256];

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

	// Make general section
	curNode = xmlNewChild(rootNode, NULL, BAD_CAST "General", NULL);
	if(!bHavePort)
		xml::saveNonZeroNum(curNode, "Port", portNum);

	xml::saveNonNullString(curNode, "DmPass", dmPass);
	xml::saveNonNullString(curNode, "Webserver", webserver);
	xml::saveNonNullString(curNode, "QS", qs);
	xml::saveNonNullString(curNode, "UserAgent", userAgent);
	xml::saveNonNullString(curNode, "CustomColors", customColors);

	xml::newBoolChild(curNode, "AprilFools", doAprilFools);
	xml::saveNonZeroNum(curNode, "FlashPolicyPort", flashPolicyPort);
	xml::newBoolChild(curNode, "AutoShutdown", autoShutdown);
	xml::newBoolChild(curNode, "CharCreationDisabled", charCreationDisabled);
	xml::newBoolChild(curNode, "CheckDouble", checkDouble);
	xml::newBoolChild(curNode, "GetHostByName", getHostByName);
	xml::newBoolChild(curNode, "LessExpLoss", lessExpLoss);
	xml::newBoolChild(curNode, "LogDeath", logDeath);
	xml::newBoolChild(curNode, "PkillInCombatDisabled", pkillInCombatDisabled);
	xml::newBoolChild(curNode, "RecordAll", recordAll);
	xml::newBoolChild(curNode, "LogSuicide", logSuicide);
	xml::newBoolChild(curNode, "SaveOnDrop", saveOnDrop);
	xml::newBoolChild(curNode, "MaxGuild", maxGuilds);

	xml::saveNonZeroNum(curNode, "ShopNumObjects", shopNumObjects);
	xml::saveNonZeroNum(curNode, "ShopNumLines", shopNumLines);

	// Lottery Section
	curNode = xmlNewChild(rootNode, NULL, BAD_CAST "Lottery", NULL);
	xml::saveNonZeroNum(curNode, "CurrentCycle", lotteryCycle);
	xml::saveNonZeroNum(curNode, "CurrentJackpot", lotteryJackpot);
	xml::newBoolChild(curNode, "Enabled", BAD_CAST iToYesNo(lotteryEnabled));
	xml::saveNonZeroNum(curNode, "TicketPrice", lotteryTicketPrice);
	xml::saveNonZeroNum(curNode, "TicketsSold", lotteryTicketsSold);
	xml::saveNonZeroNum(curNode, "LotteryWon", lotteryWon);
	xml::saveNonZeroNum(curNode, "WinningsThisCycle", lotteryWinnings);
	xml::saveNonZeroNum(curNode, "LotteryRunTime", lotteryRunTime);
	saveShortIntArray(curNode, "WinningNumbers", "LotteryNum", lotteryNumbers, 6);
	xmlNodePtr ticketsNode = xml::newStringChild(curNode, "Tickets");
	foreach(LottoTicket* ticket, tickets) {
		ticket->saveToXml(ticketsNode);
	}

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

	return(true);
}

int Config::getPortNum() const {
	return(portNum);
}
void Config::setPortNum(int pPort) {
	portNum = pPort;
}
int getPkillInCombatDisabled() {
	return(gConfig->pkillInCombatDisabled);
}

bstring Config::getMonthDay() const {
	long	t = time(0);
	bstring str = ctime(&t);
	return(str.substr(4,6));
}

bool Config::isAprilFools() const { return(doAprilFools && getMonthDay() == "Apr  1"); }
bool Config::willAprilFools() const { return(doAprilFools); }
int Config::getFlashPolicyPort() const { return(flashPolicyPort); }

bool Config::sendTxtOnCrash() const { return(txtOnCrash); }
void Config::toggleTxtOnCrash() { txtOnCrash = !txtOnCrash; }

int Config::getShopNumObjects() const { return(shopNumObjects ? shopNumObjects : 400); }
int Config::getShopNumLines() const { return(shopNumLines ? shopNumLines : 150); }

const cWeather* Config::getWeather() const { return(calendar->getCurSeason()->getWeather()); }

bstring Config::getDmPass() const { return(dmPass); }
bstring Config::getWebserver() const { return(webserver); }
bstring Config::getQS() const { return(qs); }
bstring Config::getUserAgent() const { return(userAgent); }

#include "specials.h"

bstring Config::getSpecialFlag(int index) {
	if(index >= SA_MAX_FLAG || index <= SA_NO_FLAG )
		return("Invalid Flag");

	return(specialFlags[index].name);
}
#include "version.h"
bstring Config::getVersion() {
	return(VERSION);
}
// End Config Functions
//--------------------------------------------------------------------