/*
* data.cpp
* Data storage file
* ____ _
* | _ \ ___ __ _| |_ __ ___ ___
* | |_) / _ \/ _` | | '_ ` _ \/ __|
* | _ < __/ (_| | | | | | | \__ \
* |_| \_\___|\__,_|_|_| |_| |_|___/
*
* 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 "calendar.h"
//#include "factions.h"
//#include "commands.h"
#include <sstream>
#include <iomanip>
#include <locale>
//*********************************************************************
// moCopy
//*********************************************************************
void MudObject::moCopy(const MudObject& mo) {
strcpy(name, mo.name);
hooks = mo.hooks;
}
//*********************************************************************
// Hook
//*********************************************************************
// Available Hooks:
// onSocialInteraction
// beforeAddObject beforeAddRoom
// afterAddObject afterAddRoom
// beforeDeleteFromObject beforeDeleteFromRoom
// afterDeleteFromObject afterDeleteFromRoom
Hooks::Hooks() {
parent = 0;
}
//*********************************************************************
// Hook
//*********************************************************************
void Hooks::setParent(MudObject* target) {
parent = target;
}
//*********************************************************************
// addHook
//*********************************************************************
void Hooks::addHook(const bstring& event, const bstring& code) {
hooks.insert(MultiMap::value_type(event, code));
}
//*********************************************************************
// load
//*********************************************************************
void Hooks::load(xmlNodePtr curNode) {
xmlNodePtr childNode = curNode->children;
bstring event, code;
while(childNode) {
if(NODE_NAME(curNode, "Hook")) {
xml::copyPropToBString(event, childNode, "event");
xml::copyToBString(code, childNode);
addHook(event, code);
}
childNode = childNode->next;
}
}
//*********************************************************************
// save
//*********************************************************************
void Hooks::save(xmlNodePtr curNode, const char* name) const {
xmlNodePtr childNode, subNode;
MultiMap::const_iterator it = hooks.begin();
if(it == hooks.end())
return;
childNode = xml::newStringChild(curNode, name);
for(; it != hooks.end(); it++) {
subNode = xml::newStringChild(childNode, "Hook", (*it).second);
xml::newProp(subNode, "event", (*it).first);
}
}
//*********************************************************************
// execute
//*********************************************************************
bool Hooks::execute(const bstring& event, MudObject* target) const {
std::pair<MultiMap::const_iterator, MultiMap::const_iterator> p = hooks.equal_range(event);
bool ran = false;
//broadcast(isDm, "^orunning hook %s: %s on %s", event.c_str(), parent->name, target->name);
for(MultiMap::const_iterator it = p.first; it != p.second; ++it) {
ran = true;
//broadcast(isDm, " :: %s", (*it).second.c_str());
//gServer->runPython((*it).second);
}
return(ran);
}
//*********************************************************************
// MudFlag
//*********************************************************************
MudFlag::MudFlag() {
id = 0;
name = desc = "";
}
//*********************************************************************
// 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();
}
//*********************************************************************
// 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;
xmlDoc = xml::loadFile(CONFPATH "catRefInfo.xml", "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->parent != "") {
parent = getCatRefInfo(cri->parent, 0, true);
if(parent)
cri->copyVars(parent);
}
}
return(true);
}
//*********************************************************************
// 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", CONFPATH);
xml::saveFile(filename, xmlDoc);
xmlFreeDoc(xmlDoc);
}
//*********************************************************************
// getCatRefInfo
//*********************************************************************
const CatRefInfo* Config::getCatRefInfo(bstring area, int id, int getParent) const {
std::list<CatRefInfo*>::const_iterator it;
// prevent infinite loops from bad config files
if(getParent > 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)->area && id == (*it)->id) {
if(getParent && (*it)->parent != "")
return(getCatRefInfo((*it)->parent, 0, getParent+1));
return(*it);
}
}
return(0);
}
//*********************************************************************
// getCatRefInfo
//*********************************************************************
const CatRefInfo* Config::getCatRefInfo(const BaseRoom* room, int getParent) const {
const AreaRoom* aRoom=0;
const Room* uRoom=0;
int id = 0;
bstring area = "";
if(room) {
uRoom = room->getConstUniqueRoom();
aRoom = room->getConstAreaRoom();
}
if(uRoom) {
area = uRoom->info.area;
} else if(aRoom) {
area = "area";
id = aRoom->area->id;
} else {
area = "misc";
}
return(getCatRefInfo(area, id, getParent));
}
//*********************************************************************
// 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)->teleportZone)
total += (*it)->teleportWeight;
}
if(!total)
return(0);
pick = mrand(1, total);
total = 0;
for(it = catRefInfo.begin() ; it != catRefInfo.end() ; it++) {
if(!zone || zone == (*it)->teleportZone) {
total += (*it)->teleportWeight;
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->name.getAt(0) == '^')
i += 2;
oStr << " Area: ^c" << std::setw(10) << cri->str()
<< "^x Name: ^c" << std::setw(i)
<< cri->name << "^x ";
if(cri->parent == "") {
oStr << "TeleportZone: ^c" << std::setw(4) << cri->teleportZone << "^x "
<< "TrackZone: ^c" << std::setw(4) << cri->trackZone << "^x "
<< "TeleportWeight: ^c" << cri->teleportWeight;
if(cri->getFishing() != "")
oStr << " Fishing: ^c" << cri->getFishing();
oStr << "^x\n"
<< " "
<< "Limbo: ^c" << cri->limbo << "^x Recall: ^c" << cri->recall << "^x\n";
} else {
oStr << "Parent: ^c" << cri->parent << "^x "
<< "TeleportWeight: ^c" << cri->teleportWeight;
if(cri->getFishing() != "")
oStr << " Fishing: ^c" << cri->getFishing();
oStr << "^x\n";
}
}
player->printColor("%s\n", oStr.str().c_str());
return(0);
}
//*********************************************************************
// Range
//*********************************************************************
Range::Range() {
high = 0;
}
Range& Range::operator=(const Range& r) {
low = r.low;
high = r.high;
return(*this);
}
bool Range::operator==(const Range& r) const {
if( low != r.low ||
high != r.high
)
return(false);
return(true);
}
bool Range::operator!=(const Range& r) const {
return(!(*this==r));
}
//*********************************************************************
// load
//*********************************************************************
void Range::load(xmlNodePtr curNode) {
xmlNodePtr childNode = curNode->children;
while(childNode) {
if(NODE_NAME(childNode, "Low")) low.load(childNode);
else if(NODE_NAME(childNode, "High")) xml::copyToNum(high, childNode);
childNode = childNode->next;
}
if(!high && low.id)
high = low.id;
}
//*********************************************************************
// save
//*********************************************************************
xmlNodePtr Range::save(xmlNodePtr rootNode, const char* childName, int pos) const {
if(!low.id && !high)
return(NULL);
xmlNodePtr curNode = xml::newStringChild(rootNode, childName);
if(pos)
xml::newNumProp(curNode, "Num", pos);
low.save(curNode, "Low", false);
xml::newNumChild(curNode, "High", high);
return(curNode);
}
//*********************************************************************
// belongs
//*********************************************************************
bool Range::belongs(CatRef cr) const {
return( low.isArea(cr.area) && (
(cr.id >= low.id && cr.id <= high) ||
(low.id == -1 && high == -1)
));
}
//*********************************************************************
// str
//*********************************************************************
bstring Range::str() const {
std::ostringstream oStr;
oStr << low.area << ":";
if(high == -1 && low.id == -1)
oStr << "entire range";
else if(high == low.id)
oStr << low.id;
else
oStr << low.id << "-" << high;
return(oStr.str());
}
//*********************************************************************
// isArea
//*********************************************************************
bool Range::isArea(bstring c) const {
return(low.isArea(c));
}
//*********************************************************************
// CatRef
//*********************************************************************
CatRef::CatRef() {
clear();
if(gConfig)
setArea(gConfig->defaultArea);
else
setArea("misc");
}
void CatRef::setDefault(const Creature* target) {
clear();
setArea(gConfig->defaultArea);
if(target) {
if(target->parent_rom) {
setArea(target->parent_rom->info.area);
} else if(target->area_room) {
const CatRefInfo* cri = gConfig->getCatRefInfo("area", target->area_room->area->id, true);
if(cri)
setArea(cri->area);
}
}
}
void CatRef::clear() {
area = "";
id = 0;
}
CatRef& CatRef::operator=(const CatRef& cr) {
area = cr.area;
id = cr.id;
return(*this);
}
bool CatRef::operator==(const CatRef& cr) const {
return(area == cr.area && id == cr.id);
}
bool CatRef::operator!=(const CatRef& cr) const {
return(!(*this == cr));
}
//*********************************************************************
// str
//*********************************************************************
// version of string for reloading
bstring CatRef::rstr() const {
std::ostringstream oStr;
oStr << area << "." << id;
return(oStr.str());
}
bstring CatRef::str(bstring current, char color) const {
std::ostringstream oStr;
// if we're in an area already, we can chop off some text because they
// already know what the area is
if( id &&
area != "" &&
(current == "" || area != current)
) {
if(color)
oStr << "^" << color << area << ":^x" << id;
else
oStr << id << " - " << area;
} else
oStr << id;
return(oStr.str());
}
//*********************************************************************
// setArea
//*********************************************************************
void CatRef::setArea(bstring c) {
if(c.getLength() > 20)
c = c.left(20);
area = c.toLower();
}
//*********************************************************************
// isArea
//*********************************************************************
bool CatRef::isArea(bstring c) const {
return(area == c);
}
//*********************************************************************
// load
//*********************************************************************
void CatRef::load(xmlNodePtr curNode) {
xml::copyPropToBString(area, curNode, "Area");
xml::copyToNum(id, curNode);
}
//*********************************************************************
// save
//*********************************************************************
xmlNodePtr CatRef::save(xmlNodePtr curNode, const char* childName, bool saveNonZero, int pos) const {
if(!saveNonZero && !id)
return(NULL);
curNode = xml::newNumChild(curNode, childName, id);
xml::newProp(curNode, "Area", area.c_str());
if(pos)
xml::newNumProp(curNode, "Num", pos);
return(curNode);
}
//*********************************************************************
// Carry
//*********************************************************************
Carry::Carry() {
numTrade = 0;
}
Carry& Carry::operator=(const Carry& cry) {
info = cry.info;
numTrade = cry.numTrade;
return(*this);
}
bool Carry::operator==(const Carry& cry) const {
return(info == cry.info && numTrade == cry.numTrade);
}
bool Carry::operator!=(const Carry& cry) const {
return(!(*this == cry));
}
//*********************************************************************
// load
//*********************************************************************
void Carry::load(xmlNodePtr curNode) {
info.load(curNode);
numTrade = xml::getIntProp(curNode, "NumTrade");
}
//*********************************************************************
// save
//*********************************************************************
xmlNodePtr Carry::save(xmlNodePtr curNode, const char* childName, bool saveNonZero, int pos) const {
curNode = info.save(curNode, childName, saveNonZero, pos);
if(curNode && numTrade)
xml::newNumProp(curNode, "NumTrade", numTrade);
return(curNode);
}
//*********************************************************************
// str
//*********************************************************************
bstring Carry::str(bstring current, char color) const {
std::ostringstream oStr;
oStr << info.str(current, color);
if(numTrade)
oStr << " (" << numTrade << ")";
return(oStr.str());
}
//*********************************************************************
// Location
//*********************************************************************
Location::Location() { }
void Location::save(xmlNodePtr rootNode, bstring name) const {
xmlNodePtr curNode = xml::newStringChild(rootNode, name);
room.save(curNode, "Room", false);
if(mapmarker.getArea()) {
xmlNodePtr childNode = xml::newStringChild(curNode, "MapMarker");
mapmarker.save(childNode);
}
}
void Location::load(xmlNodePtr curNode) {
xmlNodePtr childNode = curNode->children;
while(childNode) {
if(NODE_NAME(childNode, "Room")) room.load(childNode);
else if(NODE_NAME(childNode, "MapMarker")) mapmarker.load(childNode);
childNode = childNode->next;
}
}
bstring Location::str() const {
if(room.id)
return(room.str());
return(mapmarker.str());
}
bool Location::operator==(const Location& l) const {
return( ( (room.id == 0 && l.room.id == 0) || // if rooms are empty, don't care about area
(room == l.room) // same room
) &&
mapmarker == l.mapmarker
);
}
bool Location::operator!=(const Location& l) const {
return(!(*this == l));
}
BaseRoom* Location::loadRoom(Player* player) const {
Room* uRoom=0;
if(room.id && ::loadRoom(room, &uRoom))
return(uRoom);
Area* area = gConfig->getArea(mapmarker.getArea());
if(area) {
AreaRoom* aRoom = area->loadRoom(player, &mapmarker, false);
return(aRoom);
}
return(0);
}
short Location::getId() const {
if(room.id)
return(room.id);
return(mapmarker.getArea());
}
//*********************************************************************
// PlayerTitle
//*********************************************************************
PlayerTitle::PlayerTitle() {
male = "";
female = "";
}
void PlayerTitle::load(xmlNodePtr rootNode) {
xmlNodePtr curNode = rootNode->children;
while(curNode) {
if(NODE_NAME(curNode, "Female")) xml::copyToBString(female, curNode);
else if(NODE_NAME(curNode, "Male")) xml::copyToBString(male, curNode);
curNode = curNode->next;
}
}
bstring PlayerTitle::getTitle(bool sexMale) const {
return(sexMale ? male : female);
}
//*********************************************************************
// raceCount
//*********************************************************************
unsigned short Config::raceCount() {
return(races.size());
}
unsigned short Config::getPlayableRaceCount() {
std::pair<int, RaceData*> rp;
RaceData* curRace;
int numPlayableRaces = 0;
foreach(rp, races) {
curRace = rp.second;
if(!curRace) continue;
if(curRace->isPlayable())
numPlayableRaces++;
}
return(numPlayableRaces);
}
//*********************************************************************
// RaceData
//*********************************************************************
RaceData::RaceData(xmlNodePtr rootNode) {
Sex sex;
Dice dice;
char sizeTxt[20];
int i=0;
short n=0;
bstring str;
id = 0;
name = adjective = abbr = "";
infra = bonus = 0;
startAge = parentRace = porphyriaResistance = 0;
size = NO_SIZE;
isParentRace = false;
playable = gendered = true;
zero(stats, sizeof(stats));
zero(saves, sizeof(saves));
zero(classes, sizeof(classes));
zero(multiClerDeities, sizeof(multiClerDeities));
zero(clerDeities, sizeof(clerDeities));
zero(palDeities, sizeof(palDeities));
zero(dkDeities, sizeof(dkDeities));
id = xml::getIntProp(rootNode, "id");
xml::copyPropToBString(name, rootNode, "name");
xmlNodePtr subNode, childNode, curNode = rootNode->children;
while(curNode) {
if(NODE_NAME(curNode, "Adjective")) xml::copyToBString(adjective, curNode);
else if(NODE_NAME(curNode, "Abbr")) xml::copyToBString(abbr, curNode);
else if(NODE_NAME(curNode, "NotPlayable")) playable = false;
else if(NODE_NAME(curNode, "ParentRace")) {
xml::copyToNum(parentRace, curNode);
if(gConfig->races.find(parentRace) != gConfig->races.end())
gConfig->races[parentRace]->makeParent();
}
else if(NODE_NAME(curNode, "Data")) {
childNode = curNode->children;
while(childNode) {
if(NODE_NAME(childNode, "Size")) {
xml::copyToCString(sizeTxt, childNode);
size = ::getSize(sizeTxt);
}
else if(NODE_NAME(childNode, "BaseHeight")) {
sex = (Sex)xml::getIntProp(childNode, "Sex");
xml::copyToNum(n, childNode);
baseHeight[sex] = n;
}
else if(NODE_NAME(childNode, "BaseWeight")) {
sex = (Sex)xml::getIntProp(childNode, "Sex");
xml::copyToNum(n, childNode);
baseWeight[sex] = n;
}
else if(NODE_NAME(childNode, "VarHeight")) {
sex = (Sex)xml::getIntProp(childNode, "Sex");
dice.load(childNode);
varHeight[sex] = dice;
}
else if(NODE_NAME(childNode, "VarWeight")) {
sex = (Sex)xml::getIntProp(childNode, "Sex");
dice.load(childNode);
varWeight[sex] = dice;
}
else if(NODE_NAME(childNode, "Gendered")) xml::copyToBool(gendered, childNode);
else if(NODE_NAME(childNode, "BonusStat")) {
xml::copyToNum(i, childNode);
if(i)
bonus = true;
}
else if(NODE_NAME(childNode, "StartAge")) xml::copyToNum(startAge, childNode);
else if(NODE_NAME(childNode, "PorphyriaResistance")) xml::copyToNum(porphyriaResistance, childNode);
else if(NODE_NAME(childNode, "Infravision")) xml::copyToBool(infra, childNode);
else if(NODE_NAME(childNode, "Stats")) {
subNode = childNode->children;
while(subNode) {
if(NODE_NAME(subNode, "Stat")) {
xml::copyPropToBString(str, subNode, "id");
xml::copyToNum(stats[gConfig->stattoNum(str)], subNode);
}
subNode = subNode->next;
}
}
else if(NODE_NAME(childNode, "Classes")) {
subNode = childNode->children;
while(subNode) {
if(NODE_NAME(subNode, "Class")) {
xml::copyPropToBString(str, subNode, "id");
classes[gConfig->classtoNum(str)] = true;
}
subNode = subNode->next;
}
}
else if(NODE_NAME(childNode, "MultiClericDeities")) {
subNode = childNode->children;
while(subNode) {
if(NODE_NAME(subNode, "Deity")) {
xml::copyPropToBString(str, subNode, "id");
multiClerDeities[gConfig->deitytoNum(str)] = true;
}
subNode = subNode->next;
}
}
else if(NODE_NAME(childNode, "ClericDeities")) {
subNode = childNode->children;
while(subNode) {
if(NODE_NAME(subNode, "Deity")) {
xml::copyPropToBString(str, subNode, "id");
clerDeities[gConfig->deitytoNum(str)] = true;
}
subNode = subNode->next;
}
}
else if(NODE_NAME(childNode, "PaladinDeities")) {
subNode = childNode->children;
while(subNode) {
if(NODE_NAME(subNode, "Deity")) {
xml::copyPropToBString(str, subNode, "id");
palDeities[gConfig->deitytoNum(str)] = true;
}
subNode = subNode->next;
}
}
else if(NODE_NAME(childNode, "DeathknightDeities")) {
subNode = childNode->children;
while(subNode) {
if(NODE_NAME(subNode, "Deity")) {
xml::copyPropToBString(str, subNode, "id");
dkDeities[gConfig->deitytoNum(str)] = true;
}
subNode = subNode->next;
}
}
else if(NODE_NAME(childNode, "SavingThrows")) {
subNode = childNode->children;
while(subNode) {
if(NODE_NAME(subNode, "SavingThrow")) {
xml::copyPropToBString(str, subNode, "id");
xml::copyToNum(saves[gConfig->savetoNum(str)], subNode);
}
subNode = subNode->next;
}
}
else if(NODE_NAME(childNode, "Effects")) {
subNode = childNode->children;
while(subNode) {
if(NODE_NAME(subNode, "Effect")) {
xml::copyToBString(str, subNode);
effects.push_back(str);
}
subNode = subNode->next;
}
} else if(NODE_NAME(childNode, "Skills")) {
xmlNodePtr skillNode = childNode->children;
while(skillNode) {
if(NODE_NAME(skillNode, "Skill")) {
SkillGain* skillGain = new SkillGain(skillNode);
baseSkills.push_back(skillGain);
}
skillNode = skillNode->next;
}
}
childNode = childNode->next;
}
}
curNode = curNode->next;
}
}
int Config::stattoNum(bstring str) {
if(str == "Str") return(STR);
if(str == "Con") return(CON);
if(str == "Dex") return(DEX);
if(str == "Int") return(INT);
if(str == "Pty") return(PTY);
return(0);
}
int Config::savetoNum(bstring str) {
if(str == "Poi") return(POI);
if(str == "Dea") return(DEA);
if(str == "Bre") return(BRE);
if(str == "Men") return(MEN);
if(str == "Spl") return(SPL);
return(0);
}
int Config::classtoNum(bstring str) {
if(str == "Assassin") return(ASSASSIN);
if(str == "Berserker") return(BERSERKER);
if(str == "Cleric") return(CLERIC);
if(str == "Fighter") return(FIGHTER);
if(str == "Mage") return(MAGE);
if(str == "Paladin") return(PALADIN);
if(str == "Ranger") return(RANGER);
if(str == "Thief") return(THIEF);
if(str == "Vampire") return(VAMPIRE);
if(str == "Monk") return(MONK);
if(str == "Deathknight") return(DEATHKNIGHT);
if(str == "Druid") return(DRUID);
if(str == "Lich") return(LICH);
if(str == "Werewolf") return(WEREWOLF);
if(str == "Bard") return(BARD);
if(str == "Rogue") return(ROGUE);
if(str == "Fighter/Mage") return(MULTI_BASE+0);
if(str == "Fighter/Thief") return(MULTI_BASE+1);
if(str == "Cleric/Assassin") return(MULTI_BASE+2);
if(str == "Mage/Thief") return(MULTI_BASE+3);
if(str == "Thief/Mage") return(MULTI_BASE+4);
if(str == "Cleric/Fighter") return(MULTI_BASE+5);
if(str == "Mage/Assassin") return(MULTI_BASE+6);
return(0);
}
int Config::racetoNum(bstring str) {
for(unsigned i=0; i<races.size(); i++) {
if(!races[i])
continue;
if(str == races[i]->getName() || str == races[i]->getAdjective())
return(i);
}
return(-1);
}
int Config::deitytoNum(bstring str) {
for(unsigned i=0; i<deities.size(); i++) {
if(!deities[i])
continue;
if(str == deities[i]->getName())
return(i);
}
return(-1);
}
//**********************************************************************
// loadRaces
//**********************************************************************
bool Config::loadRaces() {
xmlDocPtr xmlDoc;
xmlNodePtr curNode;
int i=0;
xmlDoc = xml::loadFile(CONFPATH "races.xml", "Races");
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);
}
clearRaces();
while(curNode != NULL) {
if(NODE_NAME(curNode, "Race")) {
i = xml::getIntProp(curNode, "id");
if(races.find(i) == races.end())
races[i] = new RaceData(curNode);
}
curNode = curNode->next;
}
xmlFreeDoc(xmlDoc);
xmlCleanupParser();
return(true);
}
//**********************************************************************
// loadDeities
//**********************************************************************
bool Config::loadDeities() {
xmlDocPtr xmlDoc;
xmlNodePtr curNode;
int i=0;
xmlDoc = xml::loadFile(CONFPATH "deities.xml", "Deities");
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);
}
clearDeities();
while(curNode != NULL) {
if(NODE_NAME(curNode, "Deity")) {
i = xml::getIntProp(curNode, "id");
if(deities.find(i) == deities.end())
deities[i] = new DeityData(curNode);
}
curNode = curNode->next;
}
xmlFreeDoc(xmlDoc);
xmlCleanupParser();
return(true);
}
//**********************************************************************
// loadFlags
//**********************************************************************
bool Config::loadFlags() {
xmlDocPtr xmlDoc;
xmlNodePtr curNode, childNode;
xmlDoc = xml::loadFile(CONFPATH "flags.xml", "Flags");
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);
}
clearFlags();
while(curNode != NULL) {
childNode = curNode->children;
while(childNode) {
if(NODE_NAME(childNode, "Flag")) {
MudFlag f;
f.id = xml::getIntProp(childNode, "id");
xml::copyPropToBString(f.name, childNode, "Name");
xml::copyToBString(f.desc, childNode);
if(NODE_NAME(curNode, "Rooms")) {
rflags[f.id] = f;
} else if(NODE_NAME(curNode, "Exits")) {
xflags[f.id] = f;
} else if(NODE_NAME(curNode, "Players")) {
pflags[f.id] = f;
} else if(NODE_NAME(curNode, "Monsters")) {
mflags[f.id] = f;
} else if(NODE_NAME(curNode, "Objects")) {
oflags[f.id] = f;
} else if(NODE_NAME(curNode, "SpecialAttacks")) {
specialFlags[f.id] = f;
} else if(NODE_NAME(curNode, "PropStorage")) {
propStorFlags[f.id] = f;
} else if(NODE_NAME(curNode, "PropShop")) {
propShopFlags[f.id] = f;
} else if(NODE_NAME(curNode, "PropHouse")) {
propHouseFlags[f.id] = f;
} else if(NODE_NAME(curNode, "PropGuild")) {
propGuildFlags[f.id] = f;
}
}
childNode = childNode->next;
}
curNode = curNode->next;
}
xmlFreeDoc(xmlDoc);
xmlCleanupParser();
return(true);
}
//**********************************************************************
// clearFlags
//**********************************************************************
void Config::clearFlags() {
rflags.clear();
xflags.clear();
pflags.clear();
mflags.clear();
oflags.clear();
specialFlags.clear();
propStorFlags.clear();
propShopFlags.clear();
propHouseFlags.clear();
propGuildFlags.clear();
}
//**********************************************************************
// clearRaces
//**********************************************************************
void Config::clearRaces() {
std::map<int, RaceData*>::iterator it;
for(it = races.begin() ; it != races.end() ; it++) {
RaceData* r = (*it).second;
delete r;
}
races.clear();
}
//**********************************************************************
// clearDeities
//**********************************************************************
void Config::clearDeities() {
std::map<int, DeityData*>::iterator it;
std::map<int, PlayerTitle*>::iterator tt;
for(it = deities.begin() ; it != deities.end() ; it++) {
DeityData* d = (*it).second;
for(tt = d->titles.begin() ; tt != d->titles.end() ; tt++) {
PlayerTitle* p = (*tt).second;
delete p;
}
d->titles.clear();
delete d;
}
deities.clear();
}
//**********************************************************************
// getRace
//**********************************************************************
const RaceData* Config::getRace(bstring race) const {
std::map<int, RaceData*>::const_iterator it;
RaceData* data=0;
int len = race.getLength();
race = race.toLower();
for(it = races.begin() ; it != races.end() ; it++) {
// exact match
if((*it).second->getName().toLower() == race)
return((*it).second);
if((*it).second->getName().substr(0, len) == race) {
// not unique
if(data)
return(0);
data = (*it).second;
}
}
return(data);
}
//**********************************************************************
// getRace
//**********************************************************************
const RaceData* Config::getRace(int id) const {
std::map<int, RaceData*>::const_iterator it = races.find(id);
if(it == races.end())
it = races.begin();
return((*it).second);
}
//**********************************************************************
// getDeity
//**********************************************************************
const DeityData* Config::getDeity(int id) const {
std::map<int, DeityData*>::const_iterator it = deities.find(id);
if(it == deities.end())
it = deities.begin();
return((*it).second);
}
//*********************************************************************
// dmShowRaces
//*********************************************************************
int dmShowRaces(Player* player, cmd* cmnd) {
std::map<int, RaceData*>::const_iterator it;
RaceData* data=0;
bool all = player->isDm() && cmnd->num > 1 && !strcmp(cmnd->str[1], "all");
std::map<Sex, short>::const_iterator bIt;
std::map<Sex, Dice>::const_iterator dIt;
player->printColor("Displaying Races:%s\n",
player->isDm() && !all ? " Type ^y*racelist all^x to view all information." : "");
for(it = gConfig->races.begin() ; it != gConfig->races.end() ; it++) {
data = (*it).second;
player->printColor("Id: ^c%-2d^x Name: ^c%s\n", data->getId(), data->getName().c_str());
if(all) {
if(data->bonusStat())
player->printColor(" ^mThis race picks a bonus and a penalty stat.\n");
else
player->printColor(" Str: ^m%-2d^x Dex: ^m%-2d^x Con: ^m%-2d^x Int: ^m%-2d^x Pty: ^m%-2d^x\n",
data->getStatAdj(STR), data->getStatAdj(DEX), data->getStatAdj(CON),
data->getStatAdj(INT), data->getStatAdj(PTY));
player->printColor(" Infravision: %-3s^x Size: %s isParent: %-3s\n",
data->hasInfravision() ? "^gYes" : "^rNo",
getSizeName(data->getSize()).c_str(),
data->isParent() ? "^gYes" : "^rNo");
if(data->getParentRace())
player->print(" Parent Race: %s", gConfig->getRace(data->getParentRace())->getName().c_str());
if(data->getPorphyriaResistance())
player->print(" Porphyria Resistance: %d", data->getPorphyriaResistance());
player->printColor(" Playable: %s\n", data->isPlayable() ? "^gYes" : "^rNo");
// base weight for all genders
for(bIt = data->baseHeight.begin() ; bIt != data->baseHeight.end() ; bIt++) {
player->printColor(" BaseHeight: %s: ^c%d", getSexName((*bIt).first).c_str(), (*bIt).second);
}
if(data->baseHeight.size())
player->print("\n");
// variable weight for all genders
for(dIt = data->varHeight.begin() ; dIt != data->varHeight.end() ; dIt++) {
player->printColor(" VarHeight: %s: ^c%s", getSexName((*dIt).first).c_str(), (*dIt).second.str().c_str());
}
if(data->varHeight.size())
player->print("\n");
// base height for all genders
for(bIt = data->baseWeight.begin() ; bIt != data->baseWeight.end() ; bIt++) {
player->printColor(" BaseWeight: %s: ^c%d", getSexName((*bIt).first).c_str(), (*bIt).second);
}
if(data->baseWeight.size())
player->print("\n");
// variable height for all genders
for(dIt = data->varWeight.begin() ; dIt != data->varWeight.end() ; dIt++) {
player->printColor(" VarWeight: %s: ^c%s", getSexName((*dIt).first).c_str(), (*dIt).second.str().c_str());
}
if(data->varWeight.size())
player->print("\n");
}
}
player->print("\n");
return(0);
}
//*********************************************************************
// dmShowDeities
//*********************************************************************
int dmShowDeities(Player* player, cmd* cmnd) {
std::map<int, DeityData*>::iterator it;
std::map<int, PlayerTitle*>::iterator tt;
DeityData* data=0;
PlayerTitle* title=0;
bool all = player->isDm() && cmnd->num > 1 && !strcmp(cmnd->str[1], "all");
player->printColor("Displaying Deities:%s\n",
player->isDm() && !all ? " Type ^y*deitylist all^x to view all information." : "");
for(it = gConfig->deities.begin() ; it != gConfig->deities.end() ; it++) {
data = (*it).second;
player->printColor("Id: ^c%-2d^x Name: ^c%s\n", data->getId(), data->getName().c_str());
if(all) {
for(tt = data->titles.begin() ; tt != data->titles.end(); tt++) {
title = (*tt).second;
player->printColor(" Level: ^c%-2d^x Male: ^c%s^x Female: ^c%s\n",
(*tt).first, title->getTitle(true).c_str(), title->getTitle(false).c_str());
}
player->print("\n");
}
}
player->print("\n");
return(0);
}
std::list<SkillGain*>::const_iterator RaceData::getSkillBegin() const {
return(baseSkills.begin());
}
std::list<SkillGain*>::const_iterator RaceData::getSkillEnd() const {
return(baseSkills.end());
}
int RaceData::getId() const { return(id); }
bstring RaceData::getName(int tryToShorten) const {
if(!tryToShorten)
return(name);
bstring txt = name;
if(txt.length() > (unsigned)tryToShorten)
txt.Replace("Half-", "H-");
return(txt);
}
bstring RaceData::getAdjective() const { return(adjective); }
bstring RaceData::getAbbr() const { return(abbr); }
int RaceData::getParentRace() const { return(parentRace); }
short RaceData::getPorphyriaResistance() const { return(porphyriaResistance); }
void RaceData::makeParent() { isParentRace = true; }
bool RaceData::isParent() const { return(isParentRace); }
bool RaceData::isPlayable() const { return(playable); }
bool RaceData::isGendered() const { return(gendered); }
bool RaceData::hasInfravision() const { return(infra); }
bool RaceData::bonusStat() const { return(bonus); }
Size RaceData::getSize() const { return(size); }
int RaceData::getStartAge() const { return(startAge); }
int RaceData::getStatAdj(int stat) const { return(stats[stat]); }
int RaceData::getSave(int save) const { return(saves[save]); }
bool RaceData::allowedClass(int cls) const { return(classes[cls]); }
bool RaceData::allowedDeity(int cls, int cls2, int dty) const {
return( (cls == CLERIC && !cls2 && allowedClericDeity(dty)) ||
(cls == PALADIN && !cls2 && allowedPaladinDeity(dty)) ||
(cls == DEATHKNIGHT && !cls2 && allowedDeathknightDeity(dty)) ||
(cls == CLERIC && cls2 && allowedMultiClericDeity(dty))
);
}
bool RaceData::allowedMultiClericDeity(int dty) const { return(multiClerDeities[dty]); }
bool RaceData::allowedClericDeity(int dty) const { return(clerDeities[dty]); }
bool RaceData::allowedPaladinDeity(int dty) const { return(palDeities[dty]); }
bool RaceData::allowedDeathknightDeity(int dty) const { return(dkDeities[dty]); }
DeityData::DeityData(xmlNodePtr rootNode) {
int lvl=0;
id = 0;
name = "";
xmlNodePtr curNode, childNode;
id = xml::getIntProp(rootNode, "id");
xml::copyPropToBString(name, rootNode, "name");
curNode = rootNode->children;
while(curNode) {
if(NODE_NAME(curNode, "Titles")) {
childNode = curNode->children;
while(childNode) {
if(NODE_NAME(childNode, "Title")) {
lvl = xml::getIntProp(childNode, "level");
titles[lvl] = new PlayerTitle;
titles[lvl]->load(childNode);
}
childNode = childNode->next;
}
}
curNode = curNode->next;
}
}
int DeityData::getId() const {
return(id);
}
bstring DeityData::getName() const {
return(name);
}
bstring getTitle(const std::map<int, PlayerTitle*>& titles, int lvl, bool male, bool ignoreCustom) {
std::map<int, PlayerTitle*>::const_iterator it;
if(lvl < 1)
lvl = 1;
if(lvl > MAXALVL)
lvl = MAXALVL;
while( lvl > 1 && (
(it = titles.find(lvl)) == titles.end() ||
( ignoreCustom &&
(*it).second->getTitle(male) == "[custom]"
)
)
)
lvl--;
it = titles.find(lvl);
return((*it).second->getTitle(male));
}
bstring DeityData::getTitle(int lvl, bool male, bool ignoreCustom) const {
return(::getTitle(titles, lvl, male, ignoreCustom));
}
bstring PlayerClass::getTitle(int lvl, bool male, bool ignoreCustom) const {
return(::getTitle(titles, lvl, male, ignoreCustom));
}