void Monsters::loadLootContainer(const pugi::xml_node& node, LootBlock& lBlock) { for (auto subNode : node.children()) { LootBlock lootBlock; if (loadLootItem(subNode, lootBlock)) { lBlock.childLoot.emplace_back(std::move(lootBlock)); } } }
void Monsters::loadLootContainer(const pugi::xml_node& node, LootBlock& lBlock) { for (pugi::xml_node subNode = node.first_child(); subNode; subNode = subNode.next_sibling()) { LootBlock lootBlock; if (loadLootItem(subNode, lootBlock)) { lBlock.childLoot.push_back(lootBlock); } } }
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; }