feat: resolve spell \$s1/\$s2/\$s3 to real DBC damage/heal values

Spell descriptions now substitute \$s1/\$s2/\$s3 template variables
with actual effect base points from Spell.dbc (field 80/81/82).
For example: "causes \$s1 Fire Damage" → "causes 562 Fire Damage".

Implementation:
- Added EffectBasePoints0/1/2 to all 4 expansion DBC layouts
- SpellNameEntry now stores effectBasePoints[3]
- loadSpellNameCache reads base points during DBC iteration
- cleanSpellDescription substitutes \$s1→abs(base)+1 when available
- getSpellEffectBasePoints() accessor on GameHandler

Values are DBC base points (before spell power scaling). Still uses
"X" placeholder for unresolved variables (\$d, \$o1, etc.).
This commit is contained in:
Kelsi 2026-03-23 00:51:19 -07:00
parent f9464dbacd
commit a5aa1faf7a
7 changed files with 852 additions and 804 deletions

View file

@ -23191,6 +23191,15 @@ void GameHandler::loadSpellNameCache() {
if (hasAttrExField) {
entry.attrEx = dbc->getUInt32(i, attrExField);
}
// Load effect base points for $s1/$s2/$s3 tooltip substitution
if (spellL) {
uint32_t f0 = spellL->field("EffectBasePoints0");
uint32_t f1 = spellL->field("EffectBasePoints1");
uint32_t f2 = spellL->field("EffectBasePoints2");
if (f0 != 0xFFFFFFFF) entry.effectBasePoints[0] = static_cast<int32_t>(dbc->getUInt32(i, f0));
if (f1 != 0xFFFFFFFF) entry.effectBasePoints[1] = static_cast<int32_t>(dbc->getUInt32(i, f1));
if (f2 != 0xFFFFFFFF) entry.effectBasePoints[2] = static_cast<int32_t>(dbc->getUInt32(i, f2));
}
spellNameCache_[id] = std::move(entry);
}
}
@ -23430,6 +23439,12 @@ void GameHandler::loadTalentDbc() {
static const std::string EMPTY_STRING;
const int32_t* GameHandler::getSpellEffectBasePoints(uint32_t spellId) const {
const_cast<GameHandler*>(this)->loadSpellNameCache();
auto it = spellNameCache_.find(spellId);
return (it != spellNameCache_.end()) ? it->second.effectBasePoints : nullptr;
}
const std::string& GameHandler::getSpellName(uint32_t spellId) const {
auto it = spellNameCache_.find(spellId);
return (it != spellNameCache_.end()) ? it->second.name : EMPTY_STRING;