#include "otpch.h" #include "runeeffects.h" #include "pugicast.h" #include "tools.h" bool RuneEffects::reload() { runeEffects.clear(); return loadFromXml(); } bool RuneEffects::loadFromXml() { pugi::xml_document doc; pugi::xml_parse_result result = doc.load_file("data/XML/runeffects.xml"); if (!result) { printXMLError("Error - RuneEffects::loadFromXml", "data/XML/runeffects.xml", result); return false; } for (auto node : doc.child("runeffects").children()) { RuneEffect re( static_cast(pugi::cast(node.attribute("id").value())), node.attribute("name").as_string(), node.attribute("image").as_string(), static_cast(pugi::cast(node.attribute("effectId").value())), node.attribute("speed").as_float(0.5f), node.attribute("scale").as_float(1.0f), node.attribute("opacity").as_float(0.8f), node.attribute("color").as_string("#ffffff"), node.attribute("layer").as_string("back"), node.attribute("glow").as_float(1.0f), node.attribute("colorShift").as_float(0.0f), node.attribute("noise").as_float(0.0f), node.attribute("scanlines").as_float(0.0f), node.attribute("flicker").as_float(0.0f), pugi::cast(node.attribute("bonusLoot").value()), pugi::cast(node.attribute("bonusDamage").value()), pugi::cast(node.attribute("bonusSpeed").value()), pugi::cast(node.attribute("bonusXp").value()), node.attribute("damageInterval").as_int(2000), node.attribute("damageDelay").as_int(200), node.attribute("premium").as_bool() ); // Parse children for multi-layer support for (auto layerNode : node.children("layer")) { std::string texture = layerNode.attribute("texture").as_string(""); uint16_t layerEffectId = static_cast(pugi::cast(layerNode.attribute("effectId").value())); // If no texture and no effectId, try legacy single-image fallback if (texture.empty() && layerEffectId == 0) { continue; } re.layers.emplace_back( texture, layerEffectId, layerNode.attribute("offsetX").as_float(0.0f), layerNode.attribute("offsetY").as_float(0.0f), layerNode.attribute("speed").as_float(re.speed), layerNode.attribute("scale").as_float(re.scale), layerNode.attribute("opacity").as_float(re.opacity), layerNode.attribute("color").as_string(re.color.c_str()), layerNode.attribute("flicker").as_float(re.flicker), layerNode.attribute("colorShift").as_float(re.colorShift), layerNode.attribute("drawOrder").as_int(0), layerNode.attribute("behind").as_bool(true) ); } // Backward compat: if no children but has image/effectId, create implicit single layer if (re.layers.empty() && (!re.image.empty() || re.effectId > 0)) { re.layers.emplace_back( re.image, re.effectId, 0.0f, 0.0f, re.speed, re.scale, re.opacity, re.color, re.flicker, re.colorShift, 0, true ); } runeEffects.emplace_back(std::move(re)); } runeEffects.shrink_to_fit(); return true; } RuneEffect* RuneEffects::getRuneEffectByID(uint8_t id) { auto it = std::find_if(runeEffects.begin(), runeEffects.end(), [id](const RuneEffect& re) { return re.id == id; }); return it != runeEffects.end() ? &*it : nullptr; } RuneEffect* RuneEffects::getRuneEffectByName(const std::string& name) { auto effectName = name.c_str(); for (auto& it : runeEffects) { if (strcasecmp(effectName, it.name.c_str()) == 0) { return ⁢ } } return nullptr; }