From 922d6bc8f69836cd1ee8793ee57a50b83e7cabec Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sun, 22 Mar 2026 21:32:31 -0700 Subject: [PATCH] feat: clean spell description template variables for readable tooltips MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spell descriptions from DBC contain raw template variables like \$s1, \$d, \$o1 that refer to effect values resolved at runtime. Without DBC effect data loaded, these showed as literal "\$s1" in tooltips, making descriptions hard to read. Now strips template variables and replaces with readable placeholders: - \$s1/\$s2/\$s3 → "X" (effect base points) - \$d → "X sec" (duration) - \$o1 → "X" (periodic total) - \$a1 → "X" (radius) - \$\$ → "$" (literal dollar sign) - \${...} blocks → stripped Result: "Hurls a fiery ball that causes X Fire Damage" instead of "Hurls a fiery ball that causes \$s1 Fire Damage". Not as informative as real values, but significantly more readable. --- src/addons/lua_engine.cpp | 54 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/src/addons/lua_engine.cpp b/src/addons/lua_engine.cpp index f8fb7ae5..3cb35c1f 100644 --- a/src/addons/lua_engine.cpp +++ b/src/addons/lua_engine.cpp @@ -1626,12 +1626,64 @@ static int lua_GetSpellBookItemName(lua_State* L) { } // GetSpellDescription(spellId) → description string +// Clean spell description template variables for display +static std::string cleanSpellDescription(const std::string& raw) { + if (raw.empty() || raw.find('$') == std::string::npos) return raw; + std::string result; + result.reserve(raw.size()); + for (size_t i = 0; i < raw.size(); ++i) { + if (raw[i] == '$' && i + 1 < raw.size()) { + char next = raw[i + 1]; + if (next == 's' || next == 'S' || next == 'o' || next == 'O' || + next == 'e' || next == 'E' || next == 't' || next == 'T' || + next == 'h' || next == 'H' || next == 'u' || next == 'U') { + // $s1, $o1, $e1 etc. — skip the variable, insert "X" + result += 'X'; + i += 1; // skip letter + while (i + 1 < raw.size() && raw[i + 1] >= '0' && raw[i + 1] <= '9') ++i; + } else if (next == 'd' || next == 'D') { + // $d = duration — replace with "X sec" + result += "X sec"; + ++i; + while (i + 1 < raw.size() && raw[i + 1] >= '0' && raw[i + 1] <= '9') ++i; + } else if (next == 'a' || next == 'A') { + // $a1 = radius + result += "X"; + ++i; + while (i + 1 < raw.size() && raw[i + 1] >= '0' && raw[i + 1] <= '9') ++i; + } else if (next == 'b' || next == 'B' || next == 'n' || next == 'N' || + next == 'i' || next == 'I' || next == 'x' || next == 'X') { + // misc variables + result += "X"; + ++i; + while (i + 1 < raw.size() && raw[i + 1] >= '0' && raw[i + 1] <= '9') ++i; + } else if (next == '$') { + // $$ = literal $ + result += '$'; + ++i; + } else if (next == '{' || next == '<') { + // ${...} or $<...> — skip entire block + char close = (next == '{') ? '}' : '>'; + size_t end = raw.find(close, i + 2); + if (end != std::string::npos) i = end; + else result += raw[i]; // no closing — keep $ + } else { + result += raw[i]; // unknown $ pattern — keep + } + } else { + result += raw[i]; + } + } + return result; +} + static int lua_GetSpellDescription(lua_State* L) { auto* gh = getGameHandler(L); if (!gh) { lua_pushstring(L, ""); return 1; } uint32_t spellId = static_cast(luaL_checknumber(L, 1)); const std::string& desc = gh->getSpellDescription(spellId); - lua_pushstring(L, desc.c_str()); + std::string cleaned = cleanSpellDescription(desc); + lua_pushstring(L, cleaned.c_str()); return 1; }