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