bool Items::loadFromXml() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/items/items.xml"); if (!result) { printXMLError("Error - Items::loadFromXml", "data/items/items.xml", result); return false; } for (pugi::xml_node itemNode = doc.child("items").first_child(); itemNode; itemNode = itemNode.next_sibling()) { pugi::xml_attribute idAttribute = itemNode.attribute("id"); if (idAttribute) { parseItemNode(itemNode, pugi::cast<uint16_t>(idAttribute.value())); } else { pugi::xml_attribute fromIdAttribute = itemNode.attribute("fromid"); if (fromIdAttribute) { pugi::xml_attribute toIdAttribute = itemNode.attribute("toid"); if (toIdAttribute) { uint16_t id = pugi::cast<uint16_t>(fromIdAttribute.value()); uint16_t toId = pugi::cast<uint16_t>(toIdAttribute.value()); while (id <= toId) { parseItemNode(itemNode, id++); } } else { std::cout << "[Warning - Items::loadFromXml] fromid (" << fromIdAttribute.value() << ") without toid" << std::endl; } } else { std::cout << "[Warning - Items::loadFromXml] No itemid found" << std::endl; } } } return true; }
bool BaseEvents::loadFromXml() { if (m_loaded) { std::cout << "[Error - BaseEvents::loadFromXml] It's already loaded." << std::endl; return false; } std::string scriptsName = getScriptBaseName(); std::string basePath = "data/" + scriptsName + "/"; if (getScriptInterface().loadFile(basePath + "lib/" + scriptsName + ".lua") == -1) { std::cout << "[Warning - BaseEvents::loadFromXml] Can not load " << scriptsName << " lib/" << scriptsName << ".lua" << std::endl; } std::string filename = basePath + scriptsName + ".xml"; pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(filename.c_str()); if (!result) { printXMLError("Error - BaseEvents::loadFromXml", filename, result); return false; } m_loaded = true; for (auto node : doc.child(scriptsName.c_str()).children()) { Event* event = getEvent(node.name()); if (!event) { continue; } if (!event->configureEvent(node)) { std::cout << "[Warning - BaseEvents::loadFromXml] Failed to configure event" << std::endl; delete event; continue; } bool success; pugi::xml_attribute scriptAttribute = node.attribute("script"); if (scriptAttribute) { std::string scriptFile = "scripts/" + std::string(scriptAttribute.as_string()); success = event->checkScript(basePath, scriptsName, scriptFile) && event->loadScript(basePath + scriptFile); } else { success = event->loadFunction(node.attribute("function")); } if (!success || !registerEvent(event, node)) { delete event; } } return true; }
bool Commands::loadFromXml() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/XML/commands.xml"); if (!result) { printXMLError("Error - Commands::loadFromXml", "data/XML/commands.xml", result); return false; } for (auto commandNode : doc.child("commands").children()) { pugi::xml_attribute cmdAttribute = commandNode.attribute("cmd"); if (!cmdAttribute) { std::cout << "[Warning - Commands::loadFromXml] Missing cmd" << std::endl; continue; } auto it = commandMap.find(cmdAttribute.as_string()); if (it == commandMap.end()) { std::cout << "[Warning - Commands::loadFromXml] Unknown command " << cmdAttribute.as_string() << std::endl; continue; } Command* command = it->second; pugi::xml_attribute groupAttribute = commandNode.attribute("group"); if (groupAttribute) { command->groupId = pugi::cast<uint32_t>(groupAttribute.value()); } else { std::cout << "[Warning - Commands::loadFromXml] Missing group for command " << it->first << std::endl; } pugi::xml_attribute acctypeAttribute = commandNode.attribute("acctype"); if (acctypeAttribute) { command->accountType = static_cast<AccountType_t>(pugi::cast<uint32_t>(acctypeAttribute.value())); } else { std::cout << "[Warning - Commands::loadFromXml] Missing acctype for command " << it->first << std::endl; } pugi::xml_attribute logAttribute = commandNode.attribute("log"); if (logAttribute) { command->log = booleanString(logAttribute.as_string()); } else { std::cout << "[Warning - Commands::loadFromXml] Missing log for command " << it->first << std::endl; } g_game.addCommandTag(it->first.front()); } return true; }
bool Chat::load() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/chatchannels/chatchannels.xml"); if (!result) { printXMLError("Error - Chat::load", "data/chatchannels/chatchannels.xml", result); return false; } std::forward_list<uint16_t> removedChannels; for (auto& channelEntry : normalChannels) { ChatChannel& channel = channelEntry.second; channel.onSpeakEvent = -1; channel.canJoinEvent = -1; channel.onJoinEvent = -1; channel.onLeaveEvent = -1; removedChannels.push_front(channelEntry.first); } for (auto channelNode : doc.child("channels").children()) { ChatChannel channel(pugi::cast<uint16_t>(channelNode.attribute("id").value()), channelNode.attribute("name").as_string()); channel.publicChannel = channelNode.attribute("public").as_bool(); pugi::xml_attribute scriptAttribute = channelNode.attribute("script"); if (scriptAttribute) { if (m_scriptInterface.loadFile("data/chatchannels/scripts/" + std::string(scriptAttribute.as_string())) == 0) { channel.onSpeakEvent = m_scriptInterface.getEvent("onSpeak"); channel.canJoinEvent = m_scriptInterface.getEvent("canJoin"); channel.onJoinEvent = m_scriptInterface.getEvent("onJoin"); channel.onLeaveEvent = m_scriptInterface.getEvent("onLeave"); } else { std::cout << "[Warning - Chat::load] Can not load script: " << scriptAttribute.as_string() << std::endl; } } removedChannels.remove(channel.id); normalChannels[channel.id] = channel; } for (uint16_t channelId : removedChannels) { normalChannels.erase(channelId); } return true; }
bool Quests::loadFromXml() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/XML/quests.xml"); if (!result) { printXMLError("Error - Quests::loadFromXml", "data/XML/quests.xml", result); return false; } uint16_t id = 0; for (auto questNode : doc.child("quests").children()) { quests.emplace_back( questNode.attribute("name").as_string(), ++id, pugi::cast<int32_t>(questNode.attribute("startstorageid").value()), pugi::cast<int32_t>(questNode.attribute("startstoragevalue").value()) ); Quest& quest = quests.back(); for (auto missionNode : questNode.children()) { std::string mainDescription = missionNode.attribute("description").as_string(); quest.missions.emplace_back( missionNode.attribute("name").as_string(), pugi::cast<int32_t>(missionNode.attribute("storageid").value()), pugi::cast<int32_t>(missionNode.attribute("startvalue").value()), pugi::cast<int32_t>(missionNode.attribute("endvalue").value()), missionNode.attribute("ignoreendvalue").as_bool() ); Mission& mission = quest.missions.back(); if (mainDescription.empty()) { for (auto missionStateNode : missionNode.children()) { int32_t missionId = pugi::cast<int32_t>(missionStateNode.attribute("id").value()); mission.descriptions.emplace(missionId, missionStateNode.attribute("description").as_string()); } } else { mission.mainDescription = mainDescription; } } } return true; }
bool Outfits::loadFromXml() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/XML/outfits.xml"); if (!result) { printXMLError("Error - Outfits::loadFromXml", "data/XML/outfits.xml", result); return false; } for (auto outfitNode : doc.child("outfits").children()) { pugi::xml_attribute attr; if ((attr = outfitNode.attribute("enabled")) && !attr.as_bool()) { continue; } if (!(attr = outfitNode.attribute("type"))) { std::cout << "[Warning - Outfits::loadFromXml] Missing outfit type." << std::endl; continue; } uint16_t type = pugi::cast<uint16_t>(attr.value()); if (type > PLAYERSEX_LAST) { std::cout << "[Warning - Outfits::loadFromXml] Invalid outfit type " << type << "." << std::endl; continue; } pugi::xml_attribute lookTypeAttribute = outfitNode.attribute("looktype"); if (!lookTypeAttribute) { std::cout << "[Warning - Outfits::loadFromXml] Missing looktype on outfit." << std::endl; continue; } outfits[type].emplace_back( outfitNode.attribute("name").as_string(), pugi::cast<uint16_t>(lookTypeAttribute.value()), outfitNode.attribute("premium").as_bool(), outfitNode.attribute("unlocked").as_bool(true) ); } return true; }
bool Raid::loadFromXml(const std::string& filename) { if (isLoaded()) { return true; } pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(filename.c_str()); if (!result) { printXMLError("Error - Raid::loadFromXml", filename, result); return false; } for (auto eventNode : doc.child("raid").children()) { RaidEvent* event; if (strcasecmp(eventNode.name(), "announce") == 0) { event = new AnnounceEvent(); } else if (strcasecmp(eventNode.name(), "singlespawn") == 0) { event = new SingleSpawnEvent(); } else if (strcasecmp(eventNode.name(), "areaspawn") == 0) { event = new AreaSpawnEvent(); } else if (strcasecmp(eventNode.name(), "script") == 0) { event = new ScriptEvent(&g_game.raids.getScriptInterface()); } else { continue; } if (event->configureRaidEvent(eventNode)) { raidEvents.push_back(event); } else { std::cout << "[Error - Raid::loadFromXml] In file (" << filename << "), eventNode: " << eventNode.name() << std::endl; delete event; } } //sort by delay time std::sort(raidEvents.begin(), raidEvents.end(), RaidEvent::compareEvents); loaded = true; return true; }
bool Groups::load() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/XML/groups.xml"); if (!result) { printXMLError("Error - Groups::load", "data/XML/groups.xml", result); return false; } for (pugi::xml_node groupNode = doc.child("groups").first_child(); groupNode; groupNode = groupNode.next_sibling()) { Group group; group.id = pugi::cast<uint32_t>(groupNode.attribute("id").value()); group.name = groupNode.attribute("name").as_string(); group.flags = pugi::cast<uint64_t>(groupNode.attribute("flags").value()); group.access = groupNode.attribute("access").as_bool(); group.maxDepotItems = pugi::cast<uint32_t>(groupNode.attribute("maxdepotitems").value()); group.maxVipEntries = pugi::cast<uint32_t>(groupNode.attribute("maxvipentries").value()); groups.push_back(group); } return true; }
bool Mounts::loadFromXml() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/XML/mounts.xml"); if (!result) { printXMLError("Error - Mounts::loadFromXml", "data/XML/mounts.xml", result); return false; } for (auto mountNode : doc.child("mounts").children()) { mounts.emplace_back( static_cast<uint8_t>(pugi::cast<uint16_t>(mountNode.attribute("id").value())), pugi::cast<uint16_t>(mountNode.attribute("clientid").value()), mountNode.attribute("name").as_string(), pugi::cast<int32_t>(mountNode.attribute("speed").value()), mountNode.attribute("premium").as_bool() ); } mounts.shrink_to_fit(); return true; }
bool Monsters::loadFromXml(bool reloading /*= false*/) { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/monster/monsters.xml"); if (!result) { printXMLError("Error - Monsters::loadFromXml", "data/monster/monsters.xml", result); return false; } loaded = true; std::list<std::pair<MonsterType*, std::string>> monsterScriptList; for (auto monsterNode : doc.child("monsters").children()) { loadMonster("data/monster/" + std::string(monsterNode.attribute("file").as_string()), monsterNode.attribute("name").as_string(), monsterScriptList, reloading); } if (!monsterScriptList.empty()) { if (!scriptInterface) { scriptInterface.reset(new LuaScriptInterface("Monster Interface")); scriptInterface->initState(); } for (const auto& scriptEntry : monsterScriptList) { MonsterType* mType = scriptEntry.first; if (scriptInterface->loadFile("data/monster/scripts/" + scriptEntry.second) == 0) { mType->scriptInterface = scriptInterface.get(); mType->creatureAppearEvent = scriptInterface->getEvent("onCreatureAppear"); mType->creatureDisappearEvent = scriptInterface->getEvent("onCreatureDisappear"); mType->creatureMoveEvent = scriptInterface->getEvent("onCreatureMove"); mType->creatureSayEvent = scriptInterface->getEvent("onCreatureSay"); mType->thinkEvent = scriptInterface->getEvent("onThink"); } else { std::cout << "[Warning - Monsters::loadMonster] Can not load script: " << scriptEntry.second << std::endl; std::cout << scriptInterface->getLastLuaError() << std::endl; } } } return true; }
bool Items::loadFromXml() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/items/items.xml"); if (!result) { printXMLError("Error - Items::loadFromXml", "data/items/items.xml", result); return false; } for (auto itemNode : doc.child("items").children()) { pugi::xml_attribute idAttribute = itemNode.attribute("id"); if (idAttribute) { parseItemNode(itemNode, pugi::cast<uint16_t>(idAttribute.value())); continue; } pugi::xml_attribute fromIdAttribute = itemNode.attribute("fromid"); if (!fromIdAttribute) { std::cout << "[Warning - Items::loadFromXml] No item id found" << std::endl; continue; } pugi::xml_attribute toIdAttribute = itemNode.attribute("toid"); if (!toIdAttribute) { std::cout << "[Warning - Items::loadFromXml] fromid (" << fromIdAttribute.value() << ") without toid" << std::endl; continue; } uint16_t id = pugi::cast<uint16_t>(fromIdAttribute.value()); uint16_t toId = pugi::cast<uint16_t>(toIdAttribute.value()); while (id <= toId) { parseItemNode(itemNode, id++); } } buildInventoryList(); return true; }
bool GameserverConfig::load() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("gameservers.xml"); if (!result) { printXMLError("Error - GameserverConfig::load", "gameservers.xml", result); return false; } gameservers.clear(); for (auto catNode : doc.child("servers").children()) { GameServer gs; gs.name = catNode.attribute("name").as_string(); gs.ip = catNode.attribute("ip").as_string(); gs.port = pugi::cast<uint16_t>(catNode.attribute("port").value()); gs.worldid = pugi::cast<uint16_t>(catNode.attribute("id").value()); gameservers.push_back(gs); } loaded = true; return true; }
bool Spawns::loadFromXml(const std::string& filename) { if (loaded) { return true; } pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(filename.c_str()); if (!result) { printXMLError("Error - Spawns::loadFromXml", filename, result); return false; } this->filename = filename; loaded = true; for (auto spawnNode : doc.child("spawns").children()) { Position centerPos( pugi::cast<uint16_t>(spawnNode.attribute("centerx").value()), pugi::cast<uint16_t>(spawnNode.attribute("centery").value()), pugi::cast<uint16_t>(spawnNode.attribute("centerz").value()) ); int32_t radius; pugi::xml_attribute radiusAttribute = spawnNode.attribute("radius"); if (radiusAttribute) { radius = pugi::cast<int32_t>(radiusAttribute.value()); } else { radius = -1; } spawnList.emplace_front(centerPos, radius); Spawn& spawn = spawnList.front(); for (auto childNode : spawnNode.children()) { if (strcasecmp(childNode.name(), "monster") == 0) { pugi::xml_attribute nameAttribute = childNode.attribute("name"); if (!nameAttribute) { continue; } Direction dir; pugi::xml_attribute directionAttribute = childNode.attribute("direction"); if (directionAttribute) { dir = static_cast<Direction>(pugi::cast<uint16_t>(directionAttribute.value())); } else { dir = DIRECTION_NORTH; } Position pos( centerPos.x + pugi::cast<uint16_t>(childNode.attribute("x").value()), centerPos.y + pugi::cast<uint16_t>(childNode.attribute("y").value()), centerPos.z ); uint32_t interval = pugi::cast<uint32_t>(childNode.attribute("spawntime").value()) * 1000; if (interval > MINSPAWN_INTERVAL) { spawn.addMonster(nameAttribute.as_string(), pos, dir, interval); } else { std::cout << "[Warning - Spawns::loadFromXml] " << nameAttribute.as_string() << ' ' << pos << " spawntime can not be less than " << MINSPAWN_INTERVAL / 1000 << " seconds." << std::endl; } } else if (strcasecmp(childNode.name(), "npc") == 0) { pugi::xml_attribute nameAttribute = childNode.attribute("name"); if (!nameAttribute) { continue; } Npc* npc = Npc::createNpc(nameAttribute.as_string()); if (!npc) { continue; } pugi::xml_attribute directionAttribute = childNode.attribute("direction"); if (directionAttribute) { npc->setDirection(static_cast<Direction>(pugi::cast<uint16_t>(directionAttribute.value()))); } npc->setMasterPos(Position( centerPos.x + pugi::cast<uint16_t>(childNode.attribute("x").value()), centerPos.y + pugi::cast<uint16_t>(childNode.attribute("y").value()), centerPos.z ), radius); npcList.push_front(npc); } } } return true; }
bool Events::load() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/events/events.xml"); if (!result) { printXMLError("Error - Events::load", "data/events/events.xml", result); return false; } clear(); std::set<std::string> classes; for (auto eventNode : doc.child("events").children()) { if (!eventNode.attribute("enabled").as_bool()) { continue; } const std::string& className = eventNode.attribute("class").as_string(); auto res = classes.insert(className); if (res.second) { const std::string& lowercase = asLowerCaseString(className); if (scriptInterface.loadFile("data/events/scripts/" + lowercase + ".lua") != 0) { std::cout << "[Warning - Events::load] Can not load script: " << lowercase << ".lua" << std::endl; std::cout << scriptInterface.getLastLuaError() << std::endl; } } const std::string& methodName = eventNode.attribute("method").as_string(); const int32_t event = scriptInterface.getMetaEvent(className, methodName); if (className == "Creature") { if (methodName == "onChangeOutfit") { creatureOnChangeOutfit = event; } else if (methodName == "onAreaCombat") { creatureOnAreaCombat = event; } else if (methodName == "onTargetCombat") { creatureOnTargetCombat = event; } else { std::cout << "[Warning - Events::load] Unknown creature method: " << methodName << std::endl; } } else if (className == "Party") { if (methodName == "onJoin") { partyOnJoin = event; } else if (methodName == "onLeave") { partyOnLeave = event; } else if (methodName == "onDisband") { partyOnDisband = event; } else { std::cout << "[Warning - Events::load] Unknown party method: " << methodName << std::endl; } } else if (className == "Player") { if (methodName == "onLook") { playerOnLook = event; } else if (methodName == "onLookInBattleList") { playerOnLookInBattleList = event; } else if (methodName == "onLookInTrade") { playerOnLookInTrade = event; } else if (methodName == "onTradeRequest") { playerOnTradeRequest = event; } else if (methodName == "onTradeAccept") { playerOnTradeAccept = event; } else if (methodName == "onMoveItem") { playerOnMoveItem = event; } else if (methodName == "onMoveCreature") { playerOnMoveCreature = event; } else if (methodName == "onTurn") { playerOnTurn = event; } else if (methodName == "onGainExperience") { playerOnGainExperience = event; } else if (methodName == "onLoseExperience") { playerOnLoseExperience = event; } else if (methodName == "onGainSkillTries") { playerOnGainSkillTries = event; } else { std::cout << "[Warning - Events::load] Unknown player method: " << methodName << std::endl; } } else { std::cout << "[Warning - Events::load] Unknown class: " << className << std::endl; } } return true; }
bool Raids::loadFromXml() { if (isLoaded()) { return true; } pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/raids/raids.xml"); if (!result) { printXMLError("Error - Raids::loadFromXml", "data/raids/raids.xml", result); return false; } for (auto raidNode : doc.child("raids").children()) { std::string name, file; uint32_t interval, margin; pugi::xml_attribute attr; if ((attr = raidNode.attribute("name"))) { name = attr.as_string(); } else { std::cout << "[Error - Raids::loadFromXml] Name tag missing for raid" << std::endl; continue; } if ((attr = raidNode.attribute("file"))) { file = attr.as_string(); } else { std::ostringstream ss; ss << "raids/" << name << ".xml"; file = ss.str(); std::cout << "[Warning - Raids::loadFromXml] File tag missing for raid " << name << ". Using default: " << file << std::endl; } interval = pugi::cast<uint32_t>(raidNode.attribute("interval2").value()) * 60; if (interval == 0) { std::cout << "[Error - Raids::loadFromXml] interval2 tag missing or zero (would divide by 0) for raid: " << name << std::endl; continue; } if ((attr = raidNode.attribute("margin"))) { margin = pugi::cast<uint32_t>(attr.value()) * 60 * 1000; } else { std::cout << "[Warning - Raids::loadFromXml] margin tag missing for raid: " << name << std::endl; margin = 0; } bool repeat; if ((attr = raidNode.attribute("repeat"))) { repeat = booleanString(attr.as_string()); } else { repeat = false; } Raid* newRaid = new Raid(name, interval, margin, repeat); if (newRaid->loadFromXml("data/raids/" + file)) { raidList.push_back(newRaid); } else { std::cout << "[Error - Raids::loadFromXml] Failed to load raid: " << name << std::endl; delete newRaid; } } loaded = true; return true; }
bool Monsters::loadMonster(const std::string& file, const std::string& monsterName, std::list<std::pair<MonsterType*, std::string>>& monsterScriptList, bool reloading /*= false*/) { MonsterType* mType = nullptr; bool new_mType = true; pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(file.c_str()); if (!result) { printXMLError("Error - Monsters::loadMonster", file, result); return false; } pugi::xml_node monsterNode = doc.child("monster"); if (!monsterNode) { std::cout << "[Error - Monsters::loadMonster] Missing monster node in: " << file << std::endl; return false; } pugi::xml_attribute attr; if (!(attr = monsterNode.attribute("name"))) { std::cout << "[Error - Monsters::loadMonster] Missing name in: " << file << std::endl; return false; } if (reloading) { mType = getMonsterType(monsterName); if (mType != nullptr) { new_mType = false; mType->reset(); } } if (new_mType) { mType = &monsters[asLowerCaseString(monsterName)]; } mType->name = attr.as_string(); if ((attr = monsterNode.attribute("nameDescription"))) { mType->nameDescription = attr.as_string(); } else { mType->nameDescription = "a " + mType->name; toLowerCaseString(mType->nameDescription); } if ((attr = monsterNode.attribute("race"))) { std::string tmpStrValue = asLowerCaseString(attr.as_string()); uint16_t tmpInt = pugi::cast<uint16_t>(attr.value()); if (tmpStrValue == "venom" || tmpInt == 1) { mType->race = RACE_VENOM; } else if (tmpStrValue == "blood" || tmpInt == 2) { mType->race = RACE_BLOOD; } else if (tmpStrValue == "undead" || tmpInt == 3) { mType->race = RACE_UNDEAD; } else if (tmpStrValue == "fire" || tmpInt == 4) { mType->race = RACE_FIRE; } else if (tmpStrValue == "energy" || tmpInt == 5) { mType->race = RACE_ENERGY; } else { std::cout << "[Warning - Monsters::loadMonster] Unknown race type " << attr.as_string() << ". " << file << std::endl; } } if ((attr = monsterNode.attribute("experience"))) { mType->experience = pugi::cast<uint64_t>(attr.value()); } if ((attr = monsterNode.attribute("speed"))) { mType->baseSpeed = pugi::cast<int32_t>(attr.value()); } if ((attr = monsterNode.attribute("manacost"))) { mType->manaCost = pugi::cast<uint32_t>(attr.value()); } if ((attr = monsterNode.attribute("skull"))) { mType->skull = getSkullType(attr.as_string()); } if ((attr = monsterNode.attribute("script"))) { monsterScriptList.emplace_back(mType, attr.as_string()); } pugi::xml_node node; if ((node = monsterNode.child("health"))) { if ((attr = node.attribute("now"))) { mType->health = pugi::cast<int32_t>(attr.value()); } else { std::cout << "[Error - Monsters::loadMonster] Missing health now. " << file << std::endl; } if ((attr = node.attribute("max"))) { mType->healthMax = pugi::cast<int32_t>(attr.value()); } else { std::cout << "[Error - Monsters::loadMonster] Missing health max. " << file << std::endl; } } if ((node = monsterNode.child("flags"))) { for (auto flagNode : node.children()) { attr = flagNode.first_attribute(); const char* attrName = attr.name(); if (strcasecmp(attrName, "summonable") == 0) { mType->isSummonable = attr.as_bool(); } else if (strcasecmp(attrName, "rewardboss") == 0) { mType->isRewardBoss = attr.as_bool(); } else if (strcasecmp(attrName, "attackable") == 0) { mType->isAttackable = attr.as_bool(); } else if (strcasecmp(attrName, "hostile") == 0) { mType->isHostile = attr.as_bool(); } else if (strcasecmp(attrName, "illusionable") == 0) { mType->isIllusionable = attr.as_bool(); } else if (strcasecmp(attrName, "convinceable") == 0) { mType->isConvinceable = attr.as_bool(); } else if (strcasecmp(attrName, "pushable") == 0) { mType->pushable = attr.as_bool(); } else if (strcasecmp(attrName, "canpushitems") == 0) { mType->canPushItems = attr.as_bool(); } else if (strcasecmp(attrName, "canpushcreatures") == 0) { mType->canPushCreatures = attr.as_bool(); } else if (strcasecmp(attrName, "staticattack") == 0) { uint32_t staticAttack = pugi::cast<uint32_t>(attr.value()); if (staticAttack > 100) { std::cout << "[Warning - Monsters::loadMonster] staticattack greater than 100. " << file << std::endl; staticAttack = 100; } mType->staticAttackChance = staticAttack; } else if (strcasecmp(attrName, "lightlevel") == 0) { mType->lightLevel = pugi::cast<uint16_t>(attr.value()); } else if (strcasecmp(attrName, "lightcolor") == 0) { mType->lightColor = pugi::cast<uint16_t>(attr.value()); } else if (strcasecmp(attrName, "targetdistance") == 0) { mType->targetDistance = std::max<int32_t>(1, pugi::cast<int32_t>(attr.value())); } else if (strcasecmp(attrName, "runonhealth") == 0) { mType->runAwayHealth = pugi::cast<int32_t>(attr.value()); } else if (strcasecmp(attrName, "hidehealth") == 0) { mType->hiddenHealth = attr.as_bool(); } else if (strcasecmp(attrName, "isblockable") == 0) { mType->isBlockable = attr.as_bool(); } else { std::cout << "[Warning - Monsters::loadMonster] Unknown flag attribute: " << attrName << ". " << file << std::endl; } } //if a monster can push creatures, // it should not be pushable if (mType->canPushCreatures && mType->pushable) { mType->pushable = false; } } if ((node = monsterNode.child("targetchange"))) { if ((attr = node.attribute("speed")) || (attr = node.attribute("interval"))) { mType->changeTargetSpeed = pugi::cast<uint32_t>(attr.value()); } else { std::cout << "[Warning - Monsters::loadMonster] Missing targetchange speed. " << file << std::endl; } if ((attr = node.attribute("chance"))) { mType->changeTargetChance = pugi::cast<int32_t>(attr.value()); } else { std::cout << "[Warning - Monsters::loadMonster] Missing targetchange chance. " << file << std::endl; } } if ((node = monsterNode.child("look"))) { if ((attr = node.attribute("type"))) { mType->outfit.lookType = pugi::cast<uint16_t>(attr.value()); if ((attr = node.attribute("head"))) { mType->outfit.lookHead = pugi::cast<uint16_t>(attr.value()); } if ((attr = node.attribute("body"))) { mType->outfit.lookBody = pugi::cast<uint16_t>(attr.value()); } if ((attr = node.attribute("legs"))) { mType->outfit.lookLegs = pugi::cast<uint16_t>(attr.value()); } if ((attr = node.attribute("feet"))) { mType->outfit.lookFeet = pugi::cast<uint16_t>(attr.value()); } if ((attr = node.attribute("addons"))) { mType->outfit.lookAddons = pugi::cast<uint16_t>(attr.value()); } } else if ((attr = node.attribute("typeex"))) { mType->outfit.lookTypeEx = pugi::cast<uint16_t>(attr.value()); } else { std::cout << "[Warning - Monsters::loadMonster] Missing look type/typeex. " << file << std::endl; } if ((attr = node.attribute("mount"))) { mType->outfit.lookMount = pugi::cast<uint16_t>(attr.value()); } if ((attr = node.attribute("corpse"))) { mType->lookcorpse = pugi::cast<uint16_t>(attr.value()); } } if ((node = monsterNode.child("attacks"))) { for (auto attackNode : node.children()) { spellBlock_t sb; if (deserializeSpell(attackNode, sb, monsterName)) { mType->attackSpells.emplace_back(std::move(sb)); } else { std::cout << "[Warning - Monsters::loadMonster] Cant load spell. " << file << std::endl; } } } if ((node = monsterNode.child("defenses"))) { if ((attr = node.attribute("defense"))) { mType->defense = pugi::cast<int32_t>(attr.value()); } if ((attr = node.attribute("armor"))) { mType->armor = pugi::cast<int32_t>(attr.value()); } for (auto defenseNode : node.children()) { spellBlock_t sb; if (deserializeSpell(defenseNode, sb, monsterName)) { mType->defenseSpells.emplace_back(std::move(sb)); } else { std::cout << "[Warning - Monsters::loadMonster] Cant load spell. " << file << std::endl; } } } if ((node = monsterNode.child("immunities"))) { for (auto immunityNode : node.children()) { if ((attr = immunityNode.attribute("name"))) { std::string tmpStrValue = asLowerCaseString(attr.as_string()); if (tmpStrValue == "physical") { mType->damageImmunities |= COMBAT_PHYSICALDAMAGE; mType->conditionImmunities |= CONDITION_BLEEDING; } else if (tmpStrValue == "energy") { mType->damageImmunities |= COMBAT_ENERGYDAMAGE; mType->conditionImmunities |= CONDITION_ENERGY; } else if (tmpStrValue == "fire") { mType->damageImmunities |= COMBAT_FIREDAMAGE; mType->conditionImmunities |= CONDITION_FIRE; } else if (tmpStrValue == "poison" || tmpStrValue == "earth") { mType->damageImmunities |= COMBAT_EARTHDAMAGE; mType->conditionImmunities |= CONDITION_POISON; } else if (tmpStrValue == "drown") { mType->damageImmunities |= COMBAT_DROWNDAMAGE; mType->conditionImmunities |= CONDITION_DROWN; } else if (tmpStrValue == "ice") { mType->damageImmunities |= COMBAT_ICEDAMAGE; mType->conditionImmunities |= CONDITION_FREEZING; } else if (tmpStrValue == "holy") { mType->damageImmunities |= COMBAT_HOLYDAMAGE; mType->conditionImmunities |= CONDITION_DAZZLED; } else if (tmpStrValue == "death") { mType->damageImmunities |= COMBAT_DEATHDAMAGE; mType->conditionImmunities |= CONDITION_CURSED; } else if (tmpStrValue == "lifedrain") { mType->damageImmunities |= COMBAT_LIFEDRAIN; } else if (tmpStrValue == "manadrain") { mType->damageImmunities |= COMBAT_MANADRAIN; } else if (tmpStrValue == "paralyze") { mType->conditionImmunities |= CONDITION_PARALYZE; } else if (tmpStrValue == "outfit") { mType->conditionImmunities |= CONDITION_OUTFIT; } else if (tmpStrValue == "drunk") { mType->conditionImmunities |= CONDITION_DRUNK; } else if (tmpStrValue == "invisible" || tmpStrValue == "invisibility") { mType->conditionImmunities |= CONDITION_INVISIBLE; } else if (tmpStrValue == "bleed") { mType->conditionImmunities |= CONDITION_BLEEDING; } else { std::cout << "[Warning - Monsters::loadMonster] Unknown immunity name " << attr.as_string() << ". " << file << std::endl; } } else if ((attr = immunityNode.attribute("physical"))) { if (attr.as_bool()) { mType->damageImmunities |= COMBAT_PHYSICALDAMAGE; mType->conditionImmunities |= CONDITION_BLEEDING; } } else if ((attr = immunityNode.attribute("energy"))) { if (attr.as_bool()) { mType->damageImmunities |= COMBAT_ENERGYDAMAGE; mType->conditionImmunities |= CONDITION_ENERGY; } } else if ((attr = immunityNode.attribute("fire"))) { if (attr.as_bool()) { mType->damageImmunities |= COMBAT_FIREDAMAGE; mType->conditionImmunities |= CONDITION_FIRE; } } else if ((attr = immunityNode.attribute("poison")) || (attr = immunityNode.attribute("earth"))) { if (attr.as_bool()) { mType->damageImmunities |= COMBAT_EARTHDAMAGE; mType->conditionImmunities |= CONDITION_POISON; } } else if ((attr = immunityNode.attribute("drown"))) { if (attr.as_bool()) { mType->damageImmunities |= COMBAT_DROWNDAMAGE; mType->conditionImmunities |= CONDITION_DROWN; } } else if ((attr = immunityNode.attribute("ice"))) { if (attr.as_bool()) { mType->damageImmunities |= COMBAT_ICEDAMAGE; mType->conditionImmunities |= CONDITION_FREEZING; } } else if ((attr = immunityNode.attribute("holy"))) { if (attr.as_bool()) { mType->damageImmunities |= COMBAT_HOLYDAMAGE; mType->conditionImmunities |= CONDITION_DAZZLED; } } else if ((attr = immunityNode.attribute("death"))) { if (attr.as_bool()) { mType->damageImmunities |= COMBAT_DEATHDAMAGE; mType->conditionImmunities |= CONDITION_CURSED; } } else if ((attr = immunityNode.attribute("lifedrain"))) { if (attr.as_bool()) { mType->damageImmunities |= COMBAT_LIFEDRAIN; } } else if ((attr = immunityNode.attribute("manadrain"))) { if (attr.as_bool()) { mType->damageImmunities |= COMBAT_MANADRAIN; } } else if ((attr = immunityNode.attribute("paralyze"))) { if (attr.as_bool()) { mType->conditionImmunities |= CONDITION_PARALYZE; } } else if ((attr = immunityNode.attribute("outfit"))) { if (attr.as_bool()) { mType->conditionImmunities |= CONDITION_OUTFIT; } } else if ((attr = immunityNode.attribute("bleed"))) { if (attr.as_bool()) { mType->conditionImmunities |= CONDITION_BLEEDING; } } else if ((attr = immunityNode.attribute("drunk"))) { if (attr.as_bool()) { mType->conditionImmunities |= CONDITION_DRUNK; } } else if ((attr = immunityNode.attribute("invisible")) || (attr = immunityNode.attribute("invisibility"))) { if (attr.as_bool()) { mType->conditionImmunities |= CONDITION_INVISIBLE; } } else { std::cout << "[Warning - Monsters::loadMonster] Unknown immunity. " << file << std::endl; } } } if ((node = monsterNode.child("voices"))) { if ((attr = node.attribute("speed")) || (attr = node.attribute("interval"))) { mType->yellSpeedTicks = pugi::cast<uint32_t>(attr.value()); } else { std::cout << "[Warning - Monsters::loadMonster] Missing voices speed. " << file << std::endl; } if ((attr = node.attribute("chance"))) { mType->yellChance = pugi::cast<uint32_t>(attr.value()); } else { std::cout << "[Warning - Monsters::loadMonster] Missing voices chance. " << file << std::endl; } for (auto voiceNode : node.children()) { voiceBlock_t vb; if ((attr = voiceNode.attribute("sentence"))) { vb.text = attr.as_string(); } else { std::cout << "[Warning - Monsters::loadMonster] Missing voice sentence. " << file << std::endl; } if ((attr = voiceNode.attribute("yell"))) { vb.yellText = attr.as_bool(); } else { vb.yellText = false; } mType->voiceVector.emplace_back(vb); } } if ((node = monsterNode.child("loot"))) { for (auto lootNode : node.children()) { LootBlock lootBlock; if (loadLootItem(lootNode, lootBlock)) { mType->lootItems.emplace_back(std::move(lootBlock)); } else { std::cout << "[Warning - Monsters::loadMonster] Cant load loot. " << file << std::endl; } } } if ((node = monsterNode.child("elements"))) { for (auto elementNode : node.children()) { if ((attr = elementNode.attribute("physicalPercent"))) { mType->elementMap[COMBAT_PHYSICALDAMAGE] = pugi::cast<int32_t>(attr.value()); } else if ((attr = elementNode.attribute("icePercent"))) { mType->elementMap[COMBAT_ICEDAMAGE] = pugi::cast<int32_t>(attr.value()); } else if ((attr = elementNode.attribute("poisonPercent")) || (attr = elementNode.attribute("earthPercent"))) { mType->elementMap[COMBAT_EARTHDAMAGE] = pugi::cast<int32_t>(attr.value()); } else if ((attr = elementNode.attribute("firePercent"))) { mType->elementMap[COMBAT_FIREDAMAGE] = pugi::cast<int32_t>(attr.value()); } else if ((attr = elementNode.attribute("energyPercent"))) { mType->elementMap[COMBAT_ENERGYDAMAGE] = pugi::cast<int32_t>(attr.value()); } else if ((attr = elementNode.attribute("holyPercent"))) { mType->elementMap[COMBAT_HOLYDAMAGE] = pugi::cast<int32_t>(attr.value()); } else if ((attr = elementNode.attribute("deathPercent"))) { mType->elementMap[COMBAT_DEATHDAMAGE] = pugi::cast<int32_t>(attr.value()); } else if ((attr = elementNode.attribute("drownPercent"))) { mType->elementMap[COMBAT_DROWNDAMAGE] = pugi::cast<int32_t>(attr.value()); } else if ((attr = elementNode.attribute("lifedrainPercent"))) { mType->elementMap[COMBAT_LIFEDRAIN] = pugi::cast<int32_t>(attr.value()); } else if ((attr = elementNode.attribute("manadrainPercent"))) { mType->elementMap[COMBAT_MANADRAIN] = pugi::cast<int32_t>(attr.value()); } else { std::cout << "[Warning - Monsters::loadMonster] Unknown element percent. " << file << std::endl; } } } if ((node = monsterNode.child("summons"))) { if ((attr = node.attribute("maxSummons"))) { mType->maxSummons = std::min<uint32_t>(pugi::cast<uint32_t>(attr.value()), 100); } else { std::cout << "[Warning - Monsters::loadMonster] Missing summons maxSummons. " << file << std::endl; } for (auto summonNode : node.children()) { int32_t chance = 100; int32_t speed = 1000; bool force = false; if ((attr = summonNode.attribute("speed")) || (attr = summonNode.attribute("interval"))) { speed = pugi::cast<int32_t>(attr.value()); } if ((attr = summonNode.attribute("chance"))) { chance = pugi::cast<int32_t>(attr.value()); } if ((attr = summonNode.attribute("force"))) { force = attr.as_bool(); } if ((attr = summonNode.attribute("name"))) { summonBlock_t sb; sb.name = attr.as_string(); sb.speed = speed; sb.chance = chance; sb.force = force; mType->summons.emplace_back(sb); } else { std::cout << "[Warning - Monsters::loadMonster] Missing summon name. " << file << std::endl; } } } if ((node = monsterNode.child("script"))) { for (auto eventNode : node.children()) { if ((attr = eventNode.attribute("name"))) { mType->scripts.emplace_back(attr.as_string()); } else { std::cout << "[Warning - Monsters::loadMonster] Missing name for script event. " << file << std::endl; } } } mType->summons.shrink_to_fit(); mType->lootItems.shrink_to_fit(); mType->attackSpells.shrink_to_fit(); mType->defenseSpells.shrink_to_fit(); mType->voiceVector.shrink_to_fit(); mType->scripts.shrink_to_fit(); return true; }
bool Npc::loadFromXml() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file(filename.c_str()); if (!result) { printXMLError("Error - Npc::loadFromXml", filename, result); return false; } pugi::xml_node npcNode = doc.child("npc"); if (!npcNode) { std::cout << "[Error - Npc::loadFromXml] Missing npc tag in " << filename << std::endl; return false; } name = npcNode.attribute("name").as_string(); attackable = npcNode.attribute("attackable").as_bool(); floorChange = npcNode.attribute("floorchange").as_bool(); pugi::xml_attribute attr; if ((attr = npcNode.attribute("speed"))) { baseSpeed = pugi::cast<uint32_t>(attr.value()); } else { baseSpeed = 100; } if ((attr = npcNode.attribute("walkinterval"))) { walkTicks = pugi::cast<uint32_t>(attr.value()); } if ((attr = npcNode.attribute("walkradius"))) { masterRadius = pugi::cast<int32_t>(attr.value()); } if ((attr = npcNode.attribute("ignoreheight"))) { ignoreHeight = attr.as_bool(); } if ((attr = npcNode.attribute("speechbubble"))) { speechBubble = pugi::cast<uint32_t>(attr.value()); } if ((attr = npcNode.attribute("skull"))) { setSkull(getSkullType(attr.as_string())); } pugi::xml_node healthNode = npcNode.child("health"); if (healthNode) { if ((attr = healthNode.attribute("now"))) { health = pugi::cast<int32_t>(attr.value()); } else { health = 100; } if ((attr = healthNode.attribute("max"))) { healthMax = pugi::cast<int32_t>(attr.value()); } else { healthMax = 100; } } pugi::xml_node lookNode = npcNode.child("look"); if (lookNode) { pugi::xml_attribute lookTypeAttribute = lookNode.attribute("type"); if (lookTypeAttribute) { defaultOutfit.lookType = pugi::cast<uint16_t>(lookTypeAttribute.value()); defaultOutfit.lookHead = pugi::cast<uint16_t>(lookNode.attribute("head").value()); defaultOutfit.lookBody = pugi::cast<uint16_t>(lookNode.attribute("body").value()); defaultOutfit.lookLegs = pugi::cast<uint16_t>(lookNode.attribute("legs").value()); defaultOutfit.lookFeet = pugi::cast<uint16_t>(lookNode.attribute("feet").value()); defaultOutfit.lookAddons = pugi::cast<uint16_t>(lookNode.attribute("addons").value()); } else if ((attr = lookNode.attribute("typeex"))) { defaultOutfit.lookTypeEx = pugi::cast<uint16_t>(attr.value()); } defaultOutfit.lookMount = pugi::cast<uint16_t>(lookNode.attribute("mount").value()); currentOutfit = defaultOutfit; } for (auto parameterNode : npcNode.child("parameters").children()) { parameters[parameterNode.attribute("key").as_string()] = parameterNode.attribute("value").as_string(); } pugi::xml_attribute scriptFile = npcNode.attribute("script"); if (scriptFile) { npcEventHandler = new NpcEventsHandler(scriptFile.as_string(), this); if (!npcEventHandler->isLoaded()) { delete npcEventHandler; npcEventHandler = nullptr; return false; } } return true; }
bool Commands::loadFromXml() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/XML/commands.xml"); if (!result) { printXMLError("Error - Commands::loadFromXml", "data/XML/commands.xml", result); return false; } loaded = true; for (pugi::xml_node commandNode = doc.child("commands").first_child(); commandNode; commandNode = commandNode.next_sibling()) { pugi::xml_attribute cmdAttribute = commandNode.attribute("cmd"); if (!cmdAttribute) { std::cout << "[Warning - Commands::loadFromXml] Missing cmd" << std::endl; continue; } auto it = commandMap.find(cmdAttribute.as_string()); if (it == commandMap.end()) { std::cout << "[Warning - Commands::loadFromXml] Unknown command " << cmdAttribute.as_string() << std::endl; continue; } Command* command = it->second; pugi::xml_attribute groupAttribute = commandNode.attribute("group"); if (groupAttribute) { if (!command->loadedGroupId) { command->groupId = pugi::cast<uint32_t>(groupAttribute.value()); command->loadedGroupId = true; } else { std::cout << "[Notice - Commands::loadFromXml] Duplicate command: " << it->first << std::endl; } } pugi::xml_attribute acctypeAttribute = commandNode.attribute("acctype"); if (acctypeAttribute) { if (!command->loadedAccountType) { command->accountType = static_cast<AccountType_t>(pugi::cast<uint32_t>(acctypeAttribute.value())); command->loadedAccountType = true; } else { std::cout << "[Notice - Commands::loadFromXml] Duplicate command: " << it->first << std::endl; } } pugi::xml_attribute logAttribute = commandNode.attribute("log"); if (logAttribute) { if (!command->loadedLogging) { command->logged = booleanString(logAttribute.as_string()); command->loadedLogging = true; } else { std::cout << "[Notice - Commands::loadFromXml] Duplicate log tag for: " << it->first << std::endl; } } } for (const auto& it : commandMap) { Command* command = it.second; if (!command->loadedGroupId) { std::cout << "[Warning - Commands::loadFromXml] Missing group id for command " << it.first << std::endl; } if (!command->loadedAccountType) { std::cout << "[Warning - Commands::loadFromXml] Missing acctype level for command " << it.first << std::endl; } if (!command->loadedLogging) { std::cout << "[Warning - Commands::loadFromXml] Missing log command " << it.first << std::endl; } g_game.addCommandTag(it.first.front()); } return loaded; }
bool Vocations::loadFromXml() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/XML/vocations.xml"); if (!result) { printXMLError("Error - Vocations::loadFromXml", "data/XML/vocations.xml", result); return false; } for (pugi::xml_node vocationNode = doc.child("vocations").first_child(); vocationNode; vocationNode = vocationNode.next_sibling()) { pugi::xml_attribute attr; if (!(attr = vocationNode.attribute("id"))) { std::cout << "[Warning - Vocations::loadFromXml] Missing vocation id" << std::endl; continue; } uint16_t id = pugi::cast<uint16_t>(attr.value()); auto res = vocationsMap.emplace(id, id); Vocation& voc = res.first->second; if ((attr = vocationNode.attribute("name"))) { voc.name = attr.as_string(); } if ((attr = vocationNode.attribute("clientid"))) { voc.clientId = pugi::cast<uint16_t>(attr.value()); } if ((attr = vocationNode.attribute("description"))) { voc.description = attr.as_string(); } if ((attr = vocationNode.attribute("gaincap"))) { voc.gainCap = pugi::cast<uint32_t>(attr.value()) * 100; } if ((attr = vocationNode.attribute("gainhp"))) { voc.gainHP = pugi::cast<uint32_t>(attr.value()); } if ((attr = vocationNode.attribute("gainmana"))) { voc.gainMana = pugi::cast<uint32_t>(attr.value()); } if ((attr = vocationNode.attribute("gainhpticks"))) { voc.gainHealthTicks = pugi::cast<uint32_t>(attr.value()); } if ((attr = vocationNode.attribute("gainhpamount"))) { voc.gainHealthAmount = pugi::cast<uint32_t>(attr.value()); } if ((attr = vocationNode.attribute("gainmanaticks"))) { voc.gainManaTicks = pugi::cast<uint32_t>(attr.value()); } if ((attr = vocationNode.attribute("gainmanaamount"))) { voc.gainManaAmount = pugi::cast<uint32_t>(attr.value()); } if ((attr = vocationNode.attribute("manamultiplier"))) { voc.manaMultiplier = pugi::cast<float>(attr.value()); } if ((attr = vocationNode.attribute("attackspeed"))) { voc.attackSpeed = pugi::cast<uint32_t>(attr.value()); } if ((attr = vocationNode.attribute("basespeed"))) { voc.baseSpeed = pugi::cast<uint32_t>(attr.value()); } if ((attr = vocationNode.attribute("soulmax"))) { voc.soulMax = pugi::cast<uint16_t>(attr.value()); } if ((attr = vocationNode.attribute("gainsoulticks"))) { voc.gainSoulTicks = pugi::cast<uint16_t>(attr.value()); } if ((attr = vocationNode.attribute("fromvoc"))) { voc.fromVocation = pugi::cast<uint32_t>(attr.value()); } for (pugi::xml_node childNode = vocationNode.first_child(); childNode; childNode = childNode.next_sibling()) { if (strcasecmp(childNode.name(), "skill") == 0) { pugi::xml_attribute skillIdAttribute = childNode.attribute("id"); if (skillIdAttribute) { uint16_t skill_id = pugi::cast<uint16_t>(skillIdAttribute.value()); if (skill_id <= SKILL_LAST) { voc.skillMultipliers[skill_id] = pugi::cast<float>(childNode.attribute("multiplier").value()); } else { std::cout << "[Notice - Vocations::loadFromXml] No valid skill id: " << skill_id << " for vocation: " << voc.id << std::endl; } } else { std::cout << "[Notice - Vocations::loadFromXml] Missing skill id for vocation: " << voc.id << std::endl; } } else if (strcasecmp(childNode.name(), "formula") == 0) { pugi::xml_attribute meleeDamageAttribute = childNode.attribute("meleeDamage"); if (meleeDamageAttribute) { voc.meleeDamageMultiplier = pugi::cast<float>(meleeDamageAttribute.value()); } pugi::xml_attribute distDamageAttribute = childNode.attribute("distDamage"); if (distDamageAttribute) { voc.distDamageMultiplier = pugi::cast<float>(distDamageAttribute.value()); } pugi::xml_attribute defenseAttribute = childNode.attribute("defense"); if (defenseAttribute) { voc.defenseMultiplier = pugi::cast<float>(defenseAttribute.value()); } pugi::xml_attribute armorAttribute = childNode.attribute("armor"); if (armorAttribute) { voc.armorMultiplier = pugi::cast<float>(armorAttribute.value()); } } } } return true; }
bool Store::loadFromXml(bool /*reloading = false*/) { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/store/store.xml"); if (!result) { printXMLError("Error - Store::loadFromXml", "data/store/store.xml", result); return false; } loaded = true; std::string name; std::string description; StringVec icons; for (auto categoryNode : doc.child("store").children()) { pugi::xml_attribute attr; name.clear(); description.clear(); icons.clear(); if ((attr = categoryNode.attribute("name"))) { name = attr.as_string(); } else { std::cout << "[Error - Store::loadFromXml] Missing category name." << std::endl; continue; } if ((attr = categoryNode.attribute("description"))) { description = attr.as_string(); } if ((attr = categoryNode.attribute("icons"))) { icons = explodeString(attr.as_string(), ";"); } categories.emplace_back(name, description, icons); StoreCategory& category = categories.back(); for (auto offerNode : categoryNode.children()) { StoreOffer& offer = category.createOffer(runningId++); if ((attr = offerNode.attribute("name"))) { offer.name = attr.as_string(); } else { std::cout << "[Error - Store::loadFromXml] Missing offer name in category: " << category.name << std::endl; category.offers.pop_back(); continue; } if ((attr = offerNode.attribute("description"))) { offer.description = attr.as_string(); } if ((attr = offerNode.attribute("message"))) { offer.message = attr.as_string(); } if ((attr = offerNode.attribute("icons"))) { offer.icons = explodeString(attr.as_string(), ";"); } if ((attr = offerNode.attribute("price"))) { offer.price = attr.as_uint(); } for (auto subOfferNode : offerNode.children()) { name.clear(); description.clear(); icons.clear(); if ((attr = subOfferNode.attribute("name"))) { name = attr.as_string(); } if ((attr = subOfferNode.attribute("description"))) { description = attr.as_string(); } if ((attr = subOfferNode.attribute("icons"))) { icons = explodeString(attr.as_string(), ";"); } offer.subOffers.push_back(SubOffer(name, description, icons)); } if ((attr = offerNode.attribute("script"))) { if (!scriptInterface) { scriptInterface.reset(new LuaScriptInterface("Store Interface")); scriptInterface->initState(); } std::string script = attr.as_string(); if (scriptInterface->loadFile("data/store/scripts/" + script) == 0) { offer.scriptInterface = scriptInterface.get(); offer.renderEvent = scriptInterface->getEvent("onRender"); offer.buyEvent = scriptInterface->getEvent("onBuy"); } else { std::cout << "[Warning - Store::loadFromXml] Can not load script: " << script << std::endl; std::cout << scriptInterface->getLastLuaError() << std::endl; } } } } return true; }