/* * files-xml-save.cpp * Used to serialize structures (object, creature, room, etc) to xml files * ____ _ * | _ \ ___ __ _| |_ __ ___ ___ * | |_) / _ \/ _` | | '_ ` _ \/ __| * | _ < __/ (_| | | | | | | \__ \ * |_| \_\___|\__,_|_|_| |_| |_|___/ * * Permission to use, modify and distribute is granted via the * Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License * http://creativecommons.org/licenses/by-nc-sa/3.0/ * * Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell * Contributions by Tim Callahan, Jonathan Hseu * Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman * */ /* Web Editor * _ _ ____ _______ ______ * | \ | |/ __ \__ __| ____| * | \| | | | | | | | |__ * | . ` | | | | | | | __| * | |\ | |__| | | | | |____ * |_| \_|\____/ |_| |______| * * If you change anything here, make sure the changes are reflected in the web * editor! Either edit the PHP yourself or tell Dominus to make the changes. */ #include "mud.h" #include "version.h" #include "effects.h" #include "bans.h" #include "guilds.h" #include "factions.h" #include "specials.h" #include "calendar.h" #include "quests.h" #include "unique.h" #include "alchemy.h" #include "socials.h" xmlNodePtr saveObjRefFlags(xmlNodePtr parentNode, const char* name, int maxBit, const char *bits); // Object flags to be saved for object refs int objRefSaveFlags[] = { O_PERM_ITEM, O_HIDDEN, O_CURSED, O_WORN, O_TEMP_ENCHANT, O_WAS_SHOPLIFTED, O_ENVENOMED, O_JUST_BOUGHT, O_NO_DROP, O_BROKEN_BY_CMD, O_BEING_PREPARED, O_UNIQUE, O_KEEP, O_DARKNESS, O_RECLAIMED, -1 }; //********************************************************************* // saveToFile //********************************************************************* // This function will write the supplied player to Player.xml // NOTE: For now, it will ignore equiped equipment, so be sure to // remove the equiped equipment and put it in the inventory before // calling this function otherwise it will be lost int Player::saveToFile(LoadType saveType) { xmlDocPtr xmlDoc; xmlNodePtr rootNode; char filename[256]; ASSERTLOG( this != NULL ); ASSERTLOG( !getName().empty() ); ASSERTLOG( isPlayer() ); if(getName()[0] == '\0') { printf("Invalid player passed to save\n"); return(-1); } gServer->saveIds(); xmlDoc = xmlNewDoc(BAD_CAST "1.0"); rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "Player", NULL); xmlDocSetRootElement(xmlDoc, rootNode); escapeText(); saveToXml(rootNode, ALLITEMS, LS_FULL); if(saveType == LS_BACKUP) { sprintf(filename, "%s/%s.bak.xml", Path::PlayerBackup, getCName()); } else { sprintf(filename, "%s/%s.xml", Path::Player, getCName()); } xml::saveFile(filename, xmlDoc); xmlFreeDoc(xmlDoc); return(0); } //********************************************************************* // saveToFile //********************************************************************* // This function will write the supplied room to ROOM_PATH/r#####.xml // It will most likely only be called from *save r int UniqueRoom::saveToFile(int permOnly, LoadType saveType) { xmlDocPtr xmlDoc; xmlNodePtr rootNode; char filename[256]; ASSERTLOG( this != NULL ); ASSERTLOG( info.id >= 0 ); if(saveType == LS_BACKUP) Path::checkDirExists(info.area, roomBackupPath); else Path::checkDirExists(info.area, roomPath); gServer->saveIds(); xmlDoc = xmlNewDoc(BAD_CAST "1.0"); rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "Room", NULL); xmlDocSetRootElement(xmlDoc, rootNode); escapeText(); saveToXml(rootNode, permOnly); if(saveType == LS_BACKUP) strcpy(filename, roomBackupPath(info)); else strcpy(filename, roomPath(info)); xml::saveFile(filename, xmlDoc); xmlFreeDoc(xmlDoc); return(0); } //********************************************************************* // saveToFile //********************************************************************* // This function will write the supplied creature to the proper // m##.xml file - To accomplish this it parse the proper m##.xml file if // available and walk down the tree to the proper place in numerical order // if the file does not exist it will create it with only that monster in it. // It will most likely only be called from *save c int Monster::saveToFile() { xmlDocPtr xmlDoc; xmlNodePtr rootNode; char filename[256]; // If we can't clean the monster properly, don't save anything if(cleanMobForSaving() != 1) return(-1); // Invalid Number if(info.id < 0) return(-1); Path::checkDirExists(info.area, monsterPath); gServer->saveIds(); xmlDoc = xmlNewDoc(BAD_CAST "1.0"); rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "Creature", NULL); xmlDocSetRootElement(xmlDoc, rootNode); escapeText(); bstring idTemp = id; id = "-1"; saveToXml(rootNode, ALLITEMS, LS_FULL); id = idTemp; strcpy(filename, monsterPath(info)); xml::saveFile(filename, xmlDoc); xmlFreeDoc(xmlDoc); return(0); } //********************************************************************* // saveObject //********************************************************************* // This function will write the supplied object to the proper // o##.xml file - To accomplish this it parse the proper o##.xml file if // available and walk down the tree to the proper place in numerical order // if the file does not exist it will create it with only that object in it. // It will most likely only be called from *save o int Object::saveToFile() { xmlDocPtr xmlDoc; xmlNodePtr rootNode; char filename[256]; ASSERTLOG( this ); // Invalid Number if(info.id < 0) return(-1); Path::checkDirExists(info.area, objectPath); gServer->saveIds(); xmlDoc = xmlNewDoc(BAD_CAST "1.0"); rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "Object", NULL); xmlDocSetRootElement(xmlDoc, rootNode); // make sure uniqueness stays intact setFlag(O_UNIQUE); if(!gConfig->getUnique(this)) clearFlag(O_UNIQUE); escapeText(); saveToXml(rootNode, ALLITEMS, LS_PROTOTYPE, false); strcpy(filename, objectPath(info)); xml::saveFile(filename, xmlDoc); xmlFreeDoc(xmlDoc); return(0); } //********************************************************************* // saveGuilds //********************************************************************* // Causes the guilds structure to be generated into an xml tree and saved bool Config::saveGuilds() const { GuildCreation * gcp; xmlDocPtr xmlDoc; xmlNodePtr rootNode; //xmlNodePtr curNode, bankNode, membersNode; char filename[80]; //int i; xmlDoc = xmlNewDoc(BAD_CAST "1.0"); rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "Guilds", NULL); xmlDocSetRootElement(xmlDoc, rootNode); xml::newNumProp(rootNode, "NextGuildId", nextGuildId); std::map<int, Guild*>::const_iterator it; const Guild *guild; for(it = guilds.begin() ; it != guilds.end() ; it++) { guild = (*it).second; if(guild->getNum() == 0) continue; guild->saveToXml(rootNode); } std::list<GuildCreation*>::const_iterator gcIt; for(gcIt = guildCreations.begin() ; gcIt != guildCreations.end() ; gcIt++) { gcp = (*gcIt); gcp->saveToXml(rootNode); } sprintf(filename, "%s/guilds.xml", Path::PlayerData); xml::saveFile(filename, xmlDoc); xmlFreeDoc(xmlDoc); return(true); } //********************************************************************* // saveBans //********************************************************************* bool Config::saveBans() const { int found=0; xmlDocPtr xmlDoc; xmlNodePtr rootNode; xmlNodePtr curNode; char filename[80]; xmlDoc = xmlNewDoc(BAD_CAST "1.0"); rootNode = xmlNewDocNode(xmlDoc, NULL,BAD_CAST "Bans", NULL); xmlDocSetRootElement(xmlDoc, rootNode); std::list<Ban*>::const_iterator it; Ban* ban; for(it = bans.begin() ; it != bans.end() ; it++) { found++; ban = (*it); curNode = xmlNewChild(rootNode, NULL, BAD_CAST "Ban", NULL); // Site xmlNewChild(curNode, NULL, BAD_CAST "Site", BAD_CAST ban->site.c_str()); // Duration //sprintf(buf, "%d", ban->duration); xml::newNumChild(curNode, "Duration", ban->duration); // Unban Time //sprintf(buf, "%ld", ban->unbanTime); xml::newNumChild(curNode, "UnbanTime", ban->unbanTime); // Banned By xmlNewChild(curNode, NULL, BAD_CAST "BannedBy", BAD_CAST ban->by.c_str()); // Ban Time xmlNewChild(curNode, NULL, BAD_CAST "BanTime", BAD_CAST ban->time.c_str()); // Reason xmlNewChild(curNode, NULL, BAD_CAST "Reason", BAD_CAST ban->reason.c_str()); // Password xmlNewChild(curNode, NULL, BAD_CAST "Password", BAD_CAST ban->password.c_str()); // Suffix xmlNewChild(curNode, NULL, BAD_CAST "Suffix", BAD_CAST iToYesNo(ban->isSuffix)); // Prefix xmlNewChild(curNode, NULL, BAD_CAST "Prefix", BAD_CAST iToYesNo(ban->isPrefix)); } sprintf(filename, "%s/bans.xml", Path::Config); xml::saveFile(filename, xmlDoc); xmlFreeDoc(xmlDoc); return(true); } //********************************************************************* // saveToXml //********************************************************************* // This will save the entire creature with anything non zero to the given // node which should be a creature or player node int Creature::saveToXml(xmlNodePtr rootNode, int permOnly, LoadType saveType, bool saveID) const { // xmlNodePtr rootNode; xmlNodePtr curNode; xmlNodePtr childNode; int i; if(getName()[0] == '\0' || rootNode == NULL) return(-1); const Player *pPlayer = getAsConstPlayer(); const Monster *mMonster = getAsConstMonster(); if(pPlayer) { xml::newProp(rootNode, "Name", pPlayer->getName()); xml::newProp(rootNode, "Password", pPlayer->getPassword()); xml::newNumProp(rootNode, "LastLogin", pPlayer->getLastLogin()); } else if(mMonster) { // Saved for LS_REF and LS_FULL xml::newNumProp(rootNode, "Num", mMonster->info.id); xml::saveNonNullString(rootNode, "Name", mMonster->getName()); xml::newProp(rootNode, "Area", mMonster->info.area); } if(saveID == true) xml::saveNonNullString(rootNode, "Id", getId()); else xml::newProp(rootNode, "ID", "-1"); // For the future, when we change things, can read them in based on the version they // were saved in before or do modifications based on the new version xml::newProp(rootNode, "Version", VERSION); if(pPlayer) { if(pPlayer->inAreaRoom()) { curNode = xml::newStringChild(rootNode, "AreaRoom"); pPlayer->getConstAreaRoomParent()->mapmarker.save(curNode); //pPlayer->currentLocation.mapmarker.save(curNode); } else pPlayer->currentLocation.room.save(rootNode, "Room", true); } // Saved for LS_REF and LS_FULL xml::saveNonZeroNum(rootNode, "Race", race); xml::saveNonZeroNum(rootNode, "Class", cClass); if(pPlayer) { xml::saveNonZeroNum(rootNode, "Class2", pPlayer->getSecondClass()); } else if(mMonster) { // TODO: Dom: for compatability, remove when possible xml::saveNonZeroNum(rootNode, "Class2", mMonster->getMobTrade()); xml::saveNonZeroNum(rootNode, "MobTrade", mMonster->getMobTrade()); } xml::saveNonZeroNum(rootNode, "Level", level); xml::saveNonZeroNum(rootNode, "Type", (int)type); xml::saveNonZeroNum(rootNode, "Experience", experience); coins.save("Coins", rootNode); xml::saveNonZeroNum(rootNode, "Alignment", alignment); curNode = xml::newStringChild(rootNode, "Stats"); strength.save(curNode, "Strength"); dexterity.save(curNode, "Dexterity"); constitution.save(curNode, "Constitution"); intelligence.save(curNode, "Intelligence"); piety.save(curNode, "Piety"); hp.save(curNode, "Hp"); mp.save(curNode, "Mp"); if(pPlayer) pPlayer->focus.save(curNode, "Focus"); // Only saved for LS_FULL saves, or player saves if(saveType == LS_FULL || pPlayer) { xml::saveNonNullString(rootNode, "Description", description); // Keys curNode = xml::newStringChild(rootNode, "Keys"); for(i=0; i<3; i++) { if(key[i][0] == 0) continue; childNode = xml::newStringChild(curNode, "Key", key[i]); xml::newNumProp(childNode, "Num", i); } // MoveTypes curNode = xml::newStringChild(rootNode, "MoveTypes"); for(i=0; i<3; i++) { if(movetype[i][0] == 0) continue; childNode = xml::newStringChild(curNode, "MoveType", movetype[i]); xml::newNumProp(childNode, "Num", i); } xml::saveNonZeroNum(rootNode, "Armor", armor); xml::saveNonZeroNum(rootNode, "Deity", deity); saveULongArray(rootNode, "Realms", "Realm", realm, MAX_REALM-1); saveLongArray(rootNode, "Proficiencies", "Proficiency", proficiency, 6); damage.save(rootNode, "Dice"); xml::saveNonZeroNum(rootNode, "Clan", clan); xml::saveNonZeroNum(rootNode, "PoisonDuration", poison_dur); xml::saveNonZeroNum(rootNode, "PoisonDamage", poison_dmg); xml::saveNonZeroNum(rootNode, "Size", size); if(pPlayer) pPlayer->saveXml(rootNode); else if(mMonster) mMonster->saveXml(rootNode); saveFactions(rootNode); saveSkills(rootNode); hooks.save(rootNode, "Hooks"); effects.save(rootNode, "Effects"); saveAttacks(rootNode); if(!minions.empty()) { curNode = xml::newStringChild(rootNode, "Minions"); std::list<bstring>::const_iterator mIt; for(mIt = minions.begin() ; mIt != minions.end() ; mIt++) { childNode = xml::newStringChild(curNode, "Minion", (*mIt)); } } // saveShortIntArray(rootNode, "Factions", "Faction", faction, MAX_FACTION); // Save dailys curNode = xml::newStringChild(rootNode, "DailyTimers"); for(i=0; i<DAILYLAST+1; i++) saveDaily(curNode, i, daily[i]); // Save saving throws curNode = xml::newStringChild(rootNode, "SavingThrows"); for(i=0; i<MAX_SAVE; i++) saveSavingThrow(curNode, i, saves[i]); // Perhaps change this into saveInt/CharArray saveBits(rootNode, "Spells", MAXSPELL, spells); saveBits(rootNode, "Quests", MAXSPELL, quests); xml::saveNonZeroNum(rootNode, "CurrentLanguage", current_language); saveBits(rootNode, "Languages", LANGUAGE_COUNT, languages); } // Saved for LS_FULL and LS_REF saveBits(rootNode, "Flags", pPlayer ? MAX_PLAYER_FLAGS : MAX_MONSTER_FLAGS, flags); // Save lasttimes for(i=0; i<TOTAL_LTS; i++) { // this nested loop means we won't create an xml node if we don't have to if(lasttime[i].interval || lasttime[i].ltime || lasttime[i].misc) { curNode = xml::newStringChild(rootNode, "LastTimes"); for(; i<TOTAL_LTS; i++) saveLastTime(curNode, i, lasttime[i]); } } curNode = xml::newStringChild(rootNode, "Inventory"); saveObjectsXml(curNode, objects, permOnly); // We want quests saved after inventory so when they are loaded we can calculate // if the quest is complete or not and store it in the appropriate variables if(pPlayer) pPlayer->saveQuests(rootNode); return(0); } //********************************************************************* // saveXml //********************************************************************* void Monster::saveXml(xmlNodePtr curNode) const { xmlNodePtr childNode, subNode; // record monsters saved during swap if(gConfig->swapIsInteresting(this)) gConfig->swapLog((bstring)"m" + info.rstr(), false); xml::saveNonNullString(curNode, "Plural", plural); xml::saveNonZeroNum(curNode, "SkillLevel", skillLevel); xml::saveNonZeroNum(curNode, "UpdateAggro", updateAggro); xml::saveNonZeroNum(curNode, "LoadAggro", loadAggro); // Attacks childNode = xml::newStringChild(curNode, "Attacks"); for(int i=0; i<3; i++) { if(attack[i][0] == 0) continue; subNode = xml::newStringChild(childNode, "Attack", attack[i]); xml::newNumProp(subNode, "Num", i); } xml::saveNonNullString(curNode, "LastMod", last_mod); xml::saveNonNullString(curNode, "Talk", talk); xmlNodePtr talkNode = xml::newStringChild(curNode, "TalkResponses"); for(TalkResponse * talkResponse : responses) talkResponse->saveToXml(talkNode); xml::saveNonNullString(curNode, "TradeTalk", ttalk); xml::saveNonZeroNum(curNode, "NumWander", numwander); xml::saveNonZeroNum(curNode, "MagicResistance", magicResistance); xml::saveNonZeroNum(curNode, "DefenseSkill", defenseSkill); xml::saveNonZeroNum(curNode, "AttackPower", attackPower); xml::saveNonZeroNum(curNode, "WeaponSkill", weaponSkill); saveCarryArray(curNode, "CarriedItems", "Carry", carry, 10); saveCatRefArray(curNode, "AssistMobs", "Mob", assist_mob, NUM_ASSIST_MOB); saveCatRefArray(curNode, "EnemyMobs", "Mob", enemy_mob, NUM_ENEMY_MOB); xml::saveNonNullString(curNode, "PrimeFaction", primeFaction); xml::saveNonNullString(curNode, "AggroString", aggroString); jail.save(curNode, "Jail", false); xml::saveNonZeroNum(curNode, "WeaponSkill", maxLevel); xml::saveNonZeroNum(curNode, "Cast", cast); saveCatRefArray(curNode, "Rescue", "Mob", rescue, NUM_RESCUE); saveBits(curNode, "ClassAggro", 32, cClassAggro); saveBits(curNode, "RaceAggro", 32, raceAggro); saveBits(curNode, "DeityAggro", 32, deityAggro); } //********************************************************************* // saveXml //********************************************************************* void Player::saveXml(xmlNodePtr curNode) const { xmlNodePtr childNode; int i; // record people logging off during swap if(gConfig->swapIsInteresting(this)) gConfig->swapLog((bstring)"p" + getName(), false); bank.save("Bank", curNode); xml::saveNonZeroNum(curNode, "WeaponTrains", weaponTrains); xml::saveNonNullString(curNode, "Surname", surname); xml::saveNonNullString(curNode, "Forum", forum); xml::newNumChild(curNode, "Wrap", wrap); bound.save(curNode, "BoundRoom"); previousRoom.save(curNode, "PreviousRoom"); // monster do not save PreviousRoom statistics.save(curNode, "Statistics"); xml::saveNonZeroNum(curNode, "ActualLevel", actual_level); xml::saveNonZeroNum(curNode, "Created", created); xml::saveNonNullString(curNode, "OldCreated", oldCreated); xml::saveNonZeroNum(curNode, "Guild", guild); if(title != " ") xml::saveNonNullString(curNode, "Title", title); xml::saveNonZeroNum(curNode, "GuildRank", guildRank); if(isStaff()) { childNode = xml::newStringChild(curNode, "Ranges"); for(i=0; i<MAX_BUILDER_RANGE; i++) { // empty range, skip it if(!bRange[i].low.id && !bRange[i].high) continue; bRange[i].save(childNode, "Range", i); } } xml::saveNonZeroNum(curNode, "NegativeLevels", negativeLevels); xml::saveNonZeroNum(curNode, "LastInterest", lastInterest); xml::saveNonZeroNum(curNode, "TickDmg", tickDmg); xml::saveNonNullString(curNode, "CustomColors", customColors); xml::saveNonZeroNum(curNode, "Thirst", thirst); saveBits(curNode, "Songs", gConfig->getMaxSong(), songs); std::list<CatRef>::const_iterator it; if(!storesRefunded.empty()) { childNode = xml::newStringChild(curNode, "StoresRefunded"); for(it = storesRefunded.begin() ; it != storesRefunded.end() ; it++) { (*it).save(childNode, "Store", true); } } if(!roomExp.empty()) { childNode = xml::newStringChild(curNode, "RoomExp"); for(it = roomExp.begin() ; it != roomExp.end() ; it++) { (*it).save(childNode, "Room", true); } } if(!objIncrease.empty()) { childNode = xml::newStringChild(curNode, "ObjIncrease"); for(it = objIncrease.begin() ; it != objIncrease.end() ; it++) { (*it).save(childNode, "Object", true); } } if(!lore.empty()) { childNode = xml::newStringChild(curNode, "Lore"); for(it = lore.begin() ; it != lore.end() ; it++) { (*it).save(childNode, "Info", true); } } std::list<int>::const_iterator rt; if(!recipes.empty()) { childNode = xml::newStringChild(curNode, "Recipes"); for(rt = recipes.begin() ; rt != recipes.end() ; rt++) { xml::newNumChild(childNode, "Recipe", (*rt)); } } // Save any Anchors for(i=0; i<MAX_DIMEN_ANCHORS; i++) { if(anchor[i]) { childNode = xml::newStringChild(curNode, "Anchors"); for(; i<MAX_DIMEN_ANCHORS; i++) if(anchor[i]) { xmlNodePtr subNode = xml::newStringChild(childNode, "Anchor"); xml::newNumProp(subNode, "Num", i); anchor[i]->save(subNode); } break; } } xml::saveNonZeroNum(curNode, "Wimpy", wimpy); childNode = xml::newStringChild(curNode, "Pets"); savePets(childNode); if(birthday) { childNode = xml::newStringChild(curNode, "Birthday"); birthday->save(childNode); } // childNode = xml::newStringChild(curNode, "Deaths", NULL); // for(i=0; i<LUCKY_DEATHS; i++) { // if(lastDeath[i]) { // subNode = xml::newStringChild(childNode, "Death", NULL); // xml::saveNonZeroInt(subNode, "Time", lastDeath[i]); // xml::saveNonNullString(subNode, "Text", killedBy[i]); // } // } xml::saveNonNullString(curNode, "LastPassword", lastPassword); xml::saveNonNullString(curNode, "PoisonedBy", poisonedBy); xml::saveNonNullString(curNode, "AfflictedBy", afflictedBy); } //********************************************************************* // saveQuests //********************************************************************* void Player::saveQuests(xmlNodePtr rootNode) const { xmlNodePtr questNode; questNode = xml::newStringChild(rootNode, "QuestsInProgress"); for(std::pair<int, QuestCompletion*> p : questsInProgress) { p.second->save(questNode); } questNode = xml::newStringChild(rootNode, "QuestsCompleted"); if(!questsCompleted.empty()) { xmlNodePtr completionNode; for(std::pair<int,int> qp : questsCompleted) { completionNode = xml::newStringChild(questNode, "Quest"); xml::newNumChild(completionNode, "Id", qp.first); xml::newNumChild(completionNode, "Num", qp.second); } } // for(it = questsCompleted.begin() ; it != questsCompleted.end() ; it++) { // xml::newNumChild(questNode, "Quest", *it); // } } //********************************************************************* // saveFactions //********************************************************************* void Creature::saveFactions(xmlNodePtr rootNode) const { xmlNodePtr curNode = xml::newStringChild(rootNode, "Factions"); xmlNodePtr factionNode; std::map<bstring, long>::const_iterator fIt; for(fIt = factions.begin() ; fIt != factions.end() ; fIt++) { factionNode = xml::newStringChild(curNode, "Faction"); xml::newStringChild(factionNode, "Name", (*fIt).first); xml::newNumChild(factionNode, "Regard", (*fIt).second); } } //********************************************************************* // saveSkills //********************************************************************* void Creature::saveSkills(xmlNodePtr rootNode) const { xmlNodePtr curNode = xml::newStringChild(rootNode, "Skills"); std::map<bstring, Skill*>::const_iterator sIt; for(sIt = skills.begin() ; sIt != skills.end() ; sIt++) { (*sIt).second->save(curNode); } } //********************************************************************* // save //********************************************************************* void Effects::save(xmlNodePtr rootNode, const char* name) const { xmlNodePtr curNode = xml::newStringChild(rootNode, name); EffectList::const_iterator eIt; for(eIt = effectList.begin() ; eIt != effectList.end() ; eIt++) { (*eIt)->save(curNode); } } //********************************************************************* // save //********************************************************************* void EffectInfo::save(xmlNodePtr rootNode) const { xmlNodePtr effectNode = xml::newStringChild(rootNode, "Effect"); xml::newStringChild(effectNode, "Name", name); xml::newNumChild(effectNode, "Duration", duration); xml::newNumChild(effectNode, "Strength", strength); xml::newNumChild(effectNode, "Extra", extra); xml::newNumChild(effectNode, "PulseModifier", pulseModifier); } //********************************************************************* // saveAttacks //********************************************************************* void Creature::saveAttacks(xmlNodePtr rootNode) const { xmlNodePtr curNode = xml::newStringChild(rootNode, "SpecialAttacks"); std::list<SpecialAttack*>::const_iterator eIt; for(eIt = specials.begin() ; eIt != specials.end() ; eIt++) { (*eIt)->save(curNode); } } //********************************************************************* // save //********************************************************************* void Skill::save(xmlNodePtr rootNode) const { xmlNodePtr skillNode = xml::newStringChild(rootNode, "Skill"); xml::newStringChild(skillNode, "Name", getName()); xml::newNumChild(skillNode, "Gained", getGained()); xml::newNumChild(skillNode, "GainBonus", getGainBonus()); } int AlchemyEffect::saveToXml(xmlNodePtr rootNode) { if(rootNode == NULL) return(-1); xml::newStringChild(rootNode, "Effect", effect); xml::newNumChild(rootNode, "Duration", duration); xml::newNumChild(rootNode, "Strength", strength); xml::newNumChild(rootNode, "Quality", quality); return(0); } //********************************************************************* // saveToXml //********************************************************************* // This function will save the entire object except 0 values to the // given node which should be an object node unless saveType is REF // in which case it will only save fields that are changed in the // ordinary course of the game int Object::saveToXml(xmlNodePtr rootNode, int permOnly, LoadType saveType, int quantity, bool saveId, std::list<bstring> *idList) const { // xmlNodePtr rootNode; xmlNodePtr curNode; xmlNodePtr childNode; int i=0; if(rootNode == NULL) return(-1); ASSERTLOG( info.id >= 0 ); ASSERTLOG( info.id < OMAX ); // If the object's index is 0, then we have to do a full save if(!info.id && saveType != LS_FULL && saveType != LS_PROTOTYPE) { // We should never get here...if it's a 0 index, should have O_SAVE_FULL set printf("ERROR: Forcing full save.\n"); saveType = LS_FULL; } // record objects saved during swap if(gConfig->swapIsInteresting(this)) gConfig->swapLog((bstring)"o" + info.rstr(), false); xml::newNumProp(rootNode, "Num", info.id); xml::newProp(rootNode, "Area", info.area); xml::newProp(rootNode, "Version", VERSION); if(quantity > 1) { xml::newNumProp(rootNode, "Quantity", quantity); curNode = xml::newStringChild(rootNode, "IdList"); if(idList != 0) { std::list<bstring>::iterator idIt = idList->begin(); while(idIt != idList->end()) { xml::newStringChild(curNode, "Id", (*idIt++)); } } } else { if(saveId == true) xml::saveNonNullString(rootNode, "Id", getId()); else xml::newProp(rootNode, "ID", "-1"); } // These are saved for full and reference xml::saveNonNullString(rootNode, "Name", getName()); if(saveType != LS_PROTOTYPE) { droppedBy.save(rootNode); xml::saveNonZeroNum(rootNode, "ShopValue", shopValue); } xml::saveNonNullString(rootNode, "Plural", plural); xml::saveNonZeroNum(rootNode, "Adjustment", adjustment); xml::saveNonZeroNum(rootNode, "ShotsMax", shotsMax); xml::saveNonZeroNum(rootNode, "ChargesMax", chargesMax); // NOTE: This is saved even if zero so that it loads broken items // properly. xml::newNumChild(rootNode, "ShotsCur", shotsCur); xml::newNumChild(rootNode, "ChargesCur", chargesCur); xml::saveNonZeroNum(rootNode, "Armor", armor); xml::saveNonZeroNum(rootNode, "NumAttacks", numAttacks); xml::saveNonZeroNum(rootNode, "Delay", delay); xml::saveNonZeroNum(rootNode, "Extra", extra); xml::saveNonZeroNum(rootNode, "LotteryCycle", lotteryCycle); if(type == LOTTERYTICKET) { // Lottery tickets have a custom description so be sure to save it xml::saveNonNullString(rootNode, "Description", description); saveShortIntArray(rootNode, "LotteryNumbers", "LotteryNum", lotteryNumbers, 6); } damage.save(rootNode, "Dice"); value.save("Value", rootNode); hooks.save(rootNode, "Hooks"); // Save the keys in case they were modified // Keys curNode = xml::newStringChild(rootNode, "Keys"); for(i=0; i<3; i++) { if(key[i][0] == 0) continue; childNode = xml::newStringChild(curNode, "Key", key[i]); xml::newNumProp(childNode, "Num", i); } for(i=0; i<4; i++) { // this nested loop means we won't create an xml node if we don't have to if(lasttime[i].interval || lasttime[i].ltime || lasttime[i].misc) { curNode = xml::newStringChild(rootNode, "LastTimes"); for(; i<4; i++) saveLastTime(curNode, i, lasttime[i]); } } xml::saveNonNullString(rootNode, "Effect", effect); xml::saveNonZeroNum(rootNode, "EffectDuration", effectDuration); xml::saveNonZeroNum(rootNode, "EffectStrength", effectStrength); xml::saveNonZeroNum(rootNode, "Recipe", recipe); xml::saveNonZeroNum(rootNode, "Made", made); xml::saveNonNullString(rootNode, "Owner", questOwner); if(saveType != LS_FULL && saveType != LS_PROTOTYPE) { // Save only a subset of flags for obj references saveObjRefFlags(rootNode, "Flags", MAX_OBJECT_FLAGS, flags); } if(saveType == LS_FULL || saveType == LS_PROTOTYPE) { saveBits(rootNode, "Flags", MAX_OBJECT_FLAGS, flags); // These are only saved for full objects if(type != LOTTERYTICKET) xml::saveNonNullString(rootNode, "Description", description); if(!alchemyEffects.empty()) { curNode = xml::newStringChild(rootNode, "AlchemyEffects"); for(std::pair<int, AlchemyEffect> p : alchemyEffects) { childNode = xml::newStringChild(curNode, "AlchemyEffect"); p.second.saveToXml(childNode); xml::newNumProp(childNode, "Num", p.first); } } xml::saveNonNullString(rootNode, "UseOutput", use_output); xml::saveNonNullString(rootNode, "UseAttack", use_attack); xml::saveNonNullString(rootNode, "LastMod", lastMod); xml::saveNonZeroNum(rootNode, "Weight", weight); xml::saveNonZeroNum(rootNode, "Type", type); xml::saveNonNullString(rootNode, "SubType", subType); xml::saveNonZeroNum(rootNode, "WearFlag", wearflag); xml::saveNonZeroNum(rootNode, "MagicPower", magicpower); xml::saveNonZeroNum(rootNode, "Level", level); xml::saveNonZeroNum(rootNode, "Quality", quality); xml::saveNonZeroNum(rootNode, "RequiredSkill", requiredSkill); xml::saveNonZeroNum(rootNode, "Clan", clan); xml::saveNonZeroNum(rootNode, "Special", special); xml::saveNonZeroNum(rootNode, "QuestNum", questnum); xml::saveNonZeroNum(rootNode, "Bulk", bulk); xml::saveNonZeroNum(rootNode, "Size", size); xml::saveNonZeroNum(rootNode, "MaxBulk", maxbulk); xml::saveNonZeroNum(rootNode, "CoinCost", coinCost); deed.save(rootNode, "Deed", false); xml::saveNonZeroNum(rootNode, "KeyVal", keyVal); xml::saveNonZeroNum(rootNode, "Material", (int)material); xml::saveNonZeroNum(rootNode, "MinStrength", minStrength); saveCatRefArray(rootNode, "InBag", "Obj", in_bag, 3); std::list<CatRef>::const_iterator it; if(!randomObjects.empty()) { curNode = xml::newStringChild(rootNode, "RandomObjects"); for(it = randomObjects.begin() ; it != randomObjects.end() ; it++) { (*it).save(curNode, "RandomObject", false); } } } if(compass) { curNode = xml::newStringChild(rootNode, "Compass"); compass->save(curNode); } if(increase) { curNode = xml::newStringChild(rootNode, "ObjIncrease"); increase->save(curNode); } // Save contained items for both full and reference saves // Also check for container flag if(saveType != LS_PROTOTYPE && !objects.empty()) { curNode = xml::newStringChild(rootNode, "SubItems"); // If we're a permenant container, always save the items inside of it if(type == CONTAINER && flagIsSet(O_PERM_ITEM)) permOnly = ALLITEMS; saveObjectsXml(curNode, objects, permOnly); } return(0); } //********************************************************************* // saveToXml //********************************************************************* int UniqueRoom::saveToXml(xmlNodePtr rootNode, int permOnly) const { std::map<int, crlasttime>::const_iterator it; xmlNodePtr curNode; int i; if(!this || getName()[0] == '\0' || rootNode == NULL) return(-1); // record rooms saved during swap if(gConfig->swapIsInteresting(this)) gConfig->swapLog((bstring)"r" + info.rstr(), false); xml::newNumProp(rootNode, "Num", info.id); xml::newProp(rootNode, "Version", VERSION); xml::newProp(rootNode, "Area", info.area); xml::saveNonNullString(rootNode, "Name", getName()); xml::saveNonNullString(rootNode, "ShortDescription", short_desc); xml::saveNonNullString(rootNode, "LongDescription", long_desc); xml::saveNonNullString(rootNode, "Fishing", fishing); xml::saveNonNullString(rootNode, "Faction", faction); xml::saveNonNullString(rootNode, "LastModBy", last_mod); // TODO: Change this into a TimeStamp xml::saveNonNullString(rootNode, "LastModTime", lastModTime); xml::saveNonNullString(rootNode, "LastPlayer", lastPly); // TODO: Change this into a TimeStamp xml::saveNonNullString(rootNode, "LastPlayerTime", lastPlyTime); xml::saveNonZeroNum(rootNode, "LowLevel", lowLevel); xml::saveNonZeroNum(rootNode, "HighLevel", highLevel); xml::saveNonZeroNum(rootNode, "MaxMobs", maxmobs); xml::saveNonZeroNum(rootNode, "Trap", trap); trapexit.save(rootNode, "TrapExit", false); xml::saveNonZeroNum(rootNode, "TrapWeight", trapweight); xml::saveNonZeroNum(rootNode, "TrapStrength", trapstrength); xml::saveNonZeroNum(rootNode, "BeenHere", beenhere); xml::saveNonZeroNum(rootNode, "RoomExp", roomExp); saveBits(rootNode, "Flags", MAX_ROOM_FLAGS, flags); curNode = xml::newStringChild(rootNode, "Wander"); wander.save(curNode); if(track.getDirection() != "") { curNode = xml::newStringChild(rootNode, "Track"); track.save(curNode); } xml::saveNonZeroNum(rootNode, "Size", size); effects.save(rootNode, "Effects"); hooks.save(rootNode, "Hooks"); // Save Perm Mobs curNode = xml::newStringChild(rootNode, "PermMobs"); for(it = permMonsters.begin(); it != permMonsters.end() ; it++) { saveCrLastTime(curNode, (*it).first, (*it).second); } // Save Perm Objs curNode = xml::newStringChild(rootNode, "PermObjs"); for(it = permObjects.begin(); it != permObjects.end() ; it++) { saveCrLastTime(curNode, (*it).first, (*it).second); } // Save LastTimes -- Dunno if we need this? for(i=0; i<16; i++) { // this nested loop means we won't create an xml node if we don't have to if(lasttime[i].interval || lasttime[i].ltime || lasttime[i].misc) { curNode = xml::newStringChild(rootNode, "LastTimes"); for(; i<16; i++) saveLastTime(curNode, i, lasttime[i]); } } // Save Objects curNode = xml::newStringChild(rootNode, "Objects"); saveObjectsXml(curNode, objects, permOnly); // Save Creatures curNode = xml::newStringChild(rootNode, "Creatures"); saveCreaturesXml(curNode, monsters, permOnly); // Save Exits curNode = xml::newStringChild(rootNode, "Exits"); saveExitsXml(curNode); return(0); } //********************************************************************* // saveToXml //********************************************************************* int Exit::saveToXml(xmlNodePtr parentNode) const { xmlNodePtr rootNode; xmlNodePtr curNode; xmlNodePtr childNode; int i; if(this == NULL || parentNode == NULL || flagIsSet(X_PORTAL)) return(-1); rootNode = xml::newStringChild(parentNode, "Exit"); xml::newProp(rootNode, "Name", getName()); // Exit Keys curNode = xml::newStringChild(rootNode, "Keys"); for(i=0; i<3; i++) { if(desc_key[i][0] == 0) continue; childNode = xml::newStringChild(curNode, "Key", desc_key[i]); xml::newNumProp(childNode, "Num",i); } target.save(rootNode, "Target"); xml::saveNonZeroNum(rootNode, "Toll", toll); xml::saveNonZeroNum(rootNode, "Level", level); xml::saveNonZeroNum(rootNode, "Trap", trap); xml::saveNonZeroNum(rootNode, "Key", key); xml::saveNonNullString(rootNode, "KeyArea", keyArea); xml::saveNonZeroNum(rootNode, "Size", size); xml::saveNonZeroNum(rootNode, "Direction", (int)direction); xml::saveNonNullString(rootNode, "PassPhrase", passphrase); xml::saveNonZeroNum(rootNode, "PassLang", passlang); xml::saveNonNullString(rootNode, "Description", description); xml::saveNonNullString(rootNode, "Enter", enter); xml::saveNonNullString(rootNode, "Open", open); effects.save(rootNode, "Effects"); saveBits(rootNode, "Flags", MAX_EXIT_FLAGS, flags); saveLastTime(curNode, 0, ltime); hooks.save(rootNode, "Hooks"); return(0); } //********************************************************************* // saveExitsXml //********************************************************************* int BaseRoom::saveExitsXml(xmlNodePtr curNode) const { for(Exit* exit : exits) { exit->saveToXml(curNode); } return(0); } //********************************************************************* // saveObjectsXml //********************************************************************* int saveObjectsXml(xmlNodePtr parentNode, const ObjectSet& set, int permOnly) { xmlNodePtr curNode; int quantity=0; LoadType lt; ObjectSet::const_iterator it; const Object* obj; std::list<bstring> *idList = 0; for( it = set.begin() ; it != set.end() ; ) { obj = (*it++); if( obj && ( permOnly == ALLITEMS || (permOnly == PERMONLY && obj->flagIsSet(O_PERM_ITEM)) )) { if(obj->flagIsSet(O_CUSTOM_OBJ) || obj->flagIsSet(O_SAVE_FULL) || !obj->info.id) { // If it's a custom or has the save flag set, save the entire object curNode = xml::newStringChild(parentNode, "Object"); lt = LS_FULL; } else { // Just save a reference and any changed fields curNode = xml::newStringChild(parentNode, "ObjRef"); lt = LS_REF; } // TODO: Modify this to work with object ids // quantity code reduces filesize for player shops, storage rooms, and // inventories (which tend of have a lot of identical items in them) quantity = 1; idList = new std::list<bstring>; idList->push_back(obj->getId()); while(it != set.end() && *(*it) == *obj) { idList->push_back((*it)->getId()); quantity++; it++; } obj->saveToXml(curNode, permOnly, lt, quantity, true, idList); delete idList; idList = 0; } } return(0); } //********************************************************************* // saveCreaturesXml //********************************************************************* int saveCreaturesXml(xmlNodePtr parentNode, const MonsterSet& set, int permOnly) { xmlNodePtr curNode; for(const Monster* mons : set) { if( mons && mons->isMonster() && ( (permOnly == ALLITEMS && !mons->isPet()) || (permOnly == PERMONLY && mons->flagIsSet(M_PERMENANT_MONSTER)) ) ) { if(mons->flagIsSet(M_SAVE_FULL)) { // Save a fully copy of the mob to the node curNode = xml::newStringChild(parentNode, "Creature"); mons->saveToXml(curNode, permOnly, LS_FULL); } else { // Just save a reference curNode = xml::newStringChild(parentNode, "CrtRef"); mons->saveToXml(curNode, permOnly, LS_REF); } } } return(0); } //********************************************************************* // savePets //********************************************************************* void Creature::savePets(xmlNodePtr parentNode) const { xmlNodePtr curNode; for(const Monster* pet : pets) { // Only save pets, not creatures just following if(!pet->isPet()) continue; curNode = xml::newStringChild(parentNode, "Creature"); pet->saveToXml(curNode, ALLITEMS, LS_FULL); } return; } //********************************************************************* // saveToXml //********************************************************************* bool Guild::saveToXml(xmlNodePtr rootNode) const { xmlNodePtr curNode, membersNode; curNode = xml::newStringChild(rootNode, "Guild"); // xml::newStringChild(curNode, "", ); // xml::newIntChild(curNode, "", guild->); xml::newNumProp(curNode, "ID", num); xml::newStringChild(curNode, "Name", name); xml::newStringChild(curNode, "Leader", leader); xml::newNumChild(curNode, "Level", level); xml::newNumChild(curNode, "NumMembers", numMembers); membersNode = xml::newStringChild(curNode, "Members"); std::list<bstring>::const_iterator mIt; for(mIt = members.begin() ; mIt != members.end() ; mIt++) { xml::newStringChild(membersNode, "Member", *mIt); } xml::newNumChild(curNode, "PkillsWon", pkillsWon); xml::newNumChild(curNode, "PkillsIn", pkillsIn); xml::newNumChild(curNode,"Points", points); bank.save("Bank", curNode); return(true); } bool Config::saveSocials() { xmlDocPtr xmlDoc; xmlNodePtr rootNode; xmlDoc = xmlNewDoc(BAD_CAST "1.0"); rootNode = xmlNewDocNode(xmlDoc, NULL, BAD_CAST "Socials", NULL); xmlDocSetRootElement(xmlDoc, rootNode); for(SocialMap::value_type p : socials) { p.second->saveToXml(rootNode); } bstring filename = bstring(Path::Code) + "/" + "socials.xml"; xml::saveFile(filename.c_str(), xmlDoc); xmlFreeDoc(xmlDoc); return(true); } bool SocialCommand::saveToXml(xmlNodePtr rootNode) const { xmlNodePtr curNode; curNode = xml::newStringChild(rootNode, "Social"); xml::newStringChild(curNode, "Name", name); if(wakeTarget) xml::newBoolChild(curNode, "WakeTarget", wakeTarget); if(rudeWakeTarget) xml::newBoolChild(curNode, "RudeWakeTarget", rudeWakeTarget); if(wakeRoom) xml::newBoolChild(curNode, "WakeRoom", wakeRoom); xml::saveNonNullString(curNode, "Description", description); xml::saveNonZeroNum(curNode, "Priority", priority); xml::saveNonNullString(curNode, "SelfNoTarget", selfNoTarget); xml::saveNonNullString(curNode, "RoomNoTarget", roomNoTarget); xml::saveNonNullString(curNode, "SelfOnTarget", selfOnTarget); xml::saveNonNullString(curNode, "RoomOnTarget", roomOnTarget); xml::saveNonNullString(curNode, "VictimOnTarget", victimOnTarget); xml::saveNonNullString(curNode, "SelfOnSelf", selfOnSelf); xml::saveNonNullString(curNode, "RoomOnSelf", roomOnSelf); return(true); } //********************************************************************* // saveToXml //********************************************************************* bool GuildCreation::saveToXml(xmlNodePtr rootNode) const { xmlNodePtr childNode, curNode = xml::newStringChild(rootNode, "GuildCreation"); xml::newStringChild(curNode, "Name", name); xml::newStringChild(curNode, "Leader", leader); xml::newStringChild(curNode, "LeaderIp", leaderIp); xml::newNumChild(curNode, "Status", status); // Supporters std::map<bstring, bstring>::const_iterator sIt; for(sIt = supporters.begin() ; sIt != supporters.end() ; sIt++) { childNode = xml::newStringChild(curNode, "Supporter", (*sIt).first); xml::newProp(childNode, "Ip", (*sIt).second); } return(true); } void DroppedBy::save(xmlNodePtr rootNode) const { xmlNodePtr curNode = xml::newStringChild(rootNode, "DroppedBy"); xml::newStringChild(curNode, "Name", name); xml::saveNonNullString(curNode, "Index", index); xml::saveNonNullString(curNode, "ID", id); xml::newStringChild(curNode, "Type", type); } #define BIT_ISSET(p,f) ((p)[(f)/8] & 1<<((f)%8)) #define BIT_SET(p,f) ((p)[(f)/8] |= 1<<((f)%8)) #define BIT_CLEAR(p,f) ((p)[(f)/8] &= ~(1<<((f)%8))) //********************************************************************* // save //********************************************************************* void Stat::save(xmlNodePtr parentNode, const char* statName) const { xmlNodePtr curNode = xml::newStringChild(parentNode, "Stat"); xml::newProp(curNode, "Name", statName); // xml::newNumChild(curNode, "Current", cur); // xml::newNumChild(curNode, "Max", max); xml::newNumChild(curNode, "Initial", initial); xmlNodePtr modNode = xml::newStringChild(curNode, "Modifiers"); for(ModifierMap::value_type p: modifiers) { p.second->save(modNode); } } void StatModifier::save(xmlNodePtr parentNode) { xmlNodePtr curNode = xml::newStringChild(parentNode, "StatModifier"); xml::newStringChild(curNode, "Name", name); xml::newNumChild(curNode, "ModAmt", modAmt); xml::newNumChild(curNode, "ModType", modType); } //********************************************************************* // saveDaily //********************************************************************* xmlNodePtr saveDaily(xmlNodePtr parentNode, int i, struct daily pDaily) { // Avoid writing un-used daily timers if(pDaily.max == 0 && pDaily.cur == 0 && pDaily.ltime == 0) return(NULL); xmlNodePtr curNode = xml::newStringChild(parentNode, "Daily"); xml::newNumProp(curNode, "Num", i); xml::newNumChild(curNode, "Max", pDaily.max); xml::newNumChild(curNode, "Current", pDaily.cur); xml::newNumChild(curNode, "LastTime", pDaily.ltime); return(curNode); } //********************************************************************* // saveCrLastTime //********************************************************************* xmlNodePtr saveCrLastTime(xmlNodePtr parentNode, int i, struct crlasttime pCrLastTime) { // Avoid writing un-used last times if(!pCrLastTime.interval && !pCrLastTime.ltime && !pCrLastTime.cr.id) return(NULL); if(i < 0 || i >= NUM_PERM_SLOTS) return(NULL); xmlNodePtr curNode = xml::newStringChild(parentNode, "LastTime"); xml::newNumProp(curNode, "Num", i); xml::newNumChild(curNode, "Interval", pCrLastTime.interval); xml::newNumChild(curNode, "LastTime", pCrLastTime.ltime); pCrLastTime.cr.save(curNode, "Misc", false); return(curNode); } //********************************************************************* // saveLastTime //********************************************************************* xmlNodePtr saveLastTime(xmlNodePtr parentNode, int i, struct lasttime pLastTime) { // Avoid writing un-used last times if(!pLastTime.interval && !pLastTime.ltime && !pLastTime.misc) return(NULL); xmlNodePtr curNode = xml::newStringChild(parentNode, "LastTime"); xml::newNumProp(curNode, "Num", i); xml::newNumChild(curNode, "Interval", pLastTime.interval); xml::newNumChild(curNode, "LastTime", pLastTime.ltime); xml::newNumChild(curNode, "Misc", pLastTime.misc); return(curNode); } //********************************************************************* // saveSavingThrow //********************************************************************* xmlNodePtr saveSavingThrow(xmlNodePtr parentNode, int i, struct saves pSavingThrow) { xmlNodePtr curNode = xml::newStringChild(parentNode, "SavingThrow"); xml::newNumProp(curNode, "Num", i); xml::newNumChild(curNode, "Chance", pSavingThrow.chance); xml::newNumChild(curNode, "Gained", pSavingThrow.gained); xml::newNumChild(curNode, "Misc", pSavingThrow.misc); return(curNode); } //********************************************************************* // saveObjRefFlags //********************************************************************* xmlNodePtr saveObjRefFlags(xmlNodePtr parentNode, const char* name, int maxBit, const char *bits) { xmlNodePtr curNode=NULL; // this nested loop means we won't create an xml node if we don't have to for(int i=0; objRefSaveFlags[i] != -1; i++) { if(BIT_ISSET(bits, objRefSaveFlags[i])) { curNode = xml::newStringChild(parentNode, name); for(; objRefSaveFlags[i] != -1; i++) { if(BIT_ISSET(bits, objRefSaveFlags[i])) saveBit(curNode, objRefSaveFlags[i]); } return(curNode); } } return(curNode); } //********************************************************************* // saveBits //********************************************************************* xmlNodePtr saveBits(xmlNodePtr parentNode, const char* name, int maxBit, const char *bits) { xmlNodePtr curNode=NULL; // this nested loop means we won't create an xml node if we don't have to for(int i=0; i<maxBit; i++) { if(BIT_ISSET(bits, i)) { curNode = xml::newStringChild(parentNode, name); for(; i<maxBit; i++) { if(BIT_ISSET(bits, i)) saveBit(curNode, i); } return(curNode); } } return(curNode); } //********************************************************************* // saveBit //********************************************************************* xmlNodePtr saveBit(xmlNodePtr parentNode, int bit) { xmlNodePtr curNode; curNode = xml::newStringChild(parentNode, "Bit"); xml::newNumProp(curNode, "Num", bit); return(curNode); } //********************************************************************* // saveLongArray //********************************************************************* xmlNodePtr saveLongArray(xmlNodePtr parentNode, const char* rootName, const char* childName, const long array[], int arraySize) { xmlNodePtr childNode, curNode=NULL; // this nested loop means we won't create an xml node if we don't have to for(int i=0; i<arraySize; i++) { if(!array[i]) { curNode = xml::newStringChild(parentNode, rootName); for(; i<arraySize; i++) { if(array[i]) { childNode = xml::newNumChild(curNode, childName, array[i]); xml::newNumProp(childNode, "Num", i); } } return(curNode); } } return(curNode); } //********************************************************************* // saveULongArray //********************************************************************* xmlNodePtr saveULongArray(xmlNodePtr parentNode, const char* rootName, const char* childName, const unsigned long array[], int arraySize) { xmlNodePtr childNode, curNode=NULL; // this nested loop means we won't create an xml node if we don't have to for(int i=0; i<arraySize; i++) { if(array[i]) { curNode = xml::newStringChild(parentNode, rootName); for(; i<arraySize; i++) { if(array[i]) { childNode = xml::newNumChild(curNode, childName, array[i]); xml::newNumProp(childNode, "Num", i); } } return(curNode); } } return(curNode); } //********************************************************************* // saveCatRefArray //********************************************************************* xmlNodePtr saveCatRefArray(xmlNodePtr parentNode, const char* rootName, const char* childName, const std::map<int, CatRef>& array, int arraySize) { xmlNodePtr curNode=NULL; std::map<int, CatRef>::const_iterator it; // this nested loop means we won't create an xml node if we don't have to for(it = array.begin(); it != array.end() ; it++) { if((*it).second.id) { curNode = xml::newStringChild(parentNode, rootName); for(; it != array.end() ; it++) { if((*it).second.id) (*it).second.save(curNode, childName, false, (*it).first); } return(curNode); } } return(curNode); } //********************************************************************* // saveCatRefArray //********************************************************************* xmlNodePtr saveCatRefArray(xmlNodePtr parentNode, const char* rootName, const char* childName, const CatRef array[], int arraySize) { xmlNodePtr curNode=NULL; // this nested loop means we won't create an xml node if we don't have to for(int i=0; i<arraySize; i++) { if(array[i].id) { curNode = xml::newStringChild(parentNode, rootName); for(; i<arraySize; i++) { if(array[i].id) array[i].save(curNode, childName, false, i); } return(curNode); } } return(curNode); } //********************************************************************* // saveCarryArray //********************************************************************* xmlNodePtr saveCarryArray(xmlNodePtr parentNode, const char* rootName, const char* childName, const Carry array[], int arraySize) { xmlNodePtr curNode=NULL; // this nested loop means we won't create an xml node if we don't have to for(int i=0; i<arraySize; i++) { if(array[i].info.id) { curNode = xml::newStringChild(parentNode, rootName); for(; i<arraySize; i++) { if(array[i].info.id) array[i].save(curNode, childName, false, i); } return(curNode); } } return(curNode); } //********************************************************************* // saveShortIntArray //********************************************************************* xmlNodePtr saveShortIntArray(xmlNodePtr parentNode, const char* rootName, const char* childName, const short array[], int arraySize) { xmlNodePtr childNode, curNode=NULL; // this nested loop means we won't create an xml node if we don't have to for(int i=0; i<arraySize; i++) { if(array[i]) { curNode = xml::newStringChild(parentNode, rootName); for(; i<arraySize; i++) { if(array[i]) { childNode = xml::newNumChild(curNode, childName, array[i]); xml::newNumProp(childNode, "Num", i); } } return(curNode); } } return(curNode); } #undef BIT_ISSET #undef BIT_SET #undef BIT_CLEAR