From 53d144c51eb95271534d022814a9828d0f627015 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 10 Mar 2026 18:09:21 -0700 Subject: [PATCH] fix: expansion-aware SpellRange.dbc loading and Classic spell tooltip fields SpellRange.dbc layout fix: - Classic 1.12 uses field 2 (MaxRange), TBC/WotLK use field 4 (MaxRangeHostile) - Add SpellRange layout to each expansion's dbc_layouts.json - Replace hardcoded field 5 with layout-driven lookup in SpellRange loading - Corrects previously wrong range values in WotLK spellbook tooltips Classic 1.12 Spell.dbc field additions: - Add CastingTimeIndex=15, PowerType=28, ManaCost=29, RangeIndex=33 to classic/dbc_layouts.json so Classic spellbook shows mana cost, cast time, and range in tooltips Trainer fieldCount guard: - Lower Trainer::loadSpellNameCache() Spell.dbc fieldCount threshold from 154 to 148 so Classic trainers correctly resolve spell names from Spell.dbc --- Data/expansions/classic/dbc_layouts.json | 4 +++- Data/expansions/tbc/dbc_layouts.json | 1 + Data/expansions/wotlk/dbc_layouts.json | 1 + src/game/game_handler.cpp | 6 ++++-- src/ui/spellbook_screen.cpp | 17 ++++++++++++++--- 5 files changed, 23 insertions(+), 6 deletions(-) diff --git a/Data/expansions/classic/dbc_layouts.json b/Data/expansions/classic/dbc_layouts.json index 4ec229d5..102074be 100644 --- a/Data/expansions/classic/dbc_layouts.json +++ b/Data/expansions/classic/dbc_layouts.json @@ -1,8 +1,10 @@ { "Spell": { "ID": 0, "Attributes": 5, "IconID": 117, - "Name": 120, "Tooltip": 147, "Rank": 129, "SchoolEnum": 1 + "Name": 120, "Tooltip": 147, "Rank": 129, "SchoolEnum": 1, + "CastingTimeIndex": 15, "PowerType": 28, "ManaCost": 29, "RangeIndex": 33 }, + "SpellRange": { "MaxRange": 2 }, "ItemDisplayInfo": { "ID": 0, "LeftModel": 1, "LeftModelTexture": 3, "InventoryIcon": 5, "GeosetGroup1": 7, "GeosetGroup3": 9, diff --git a/Data/expansions/tbc/dbc_layouts.json b/Data/expansions/tbc/dbc_layouts.json index d40a5766..8b597ba8 100644 --- a/Data/expansions/tbc/dbc_layouts.json +++ b/Data/expansions/tbc/dbc_layouts.json @@ -3,6 +3,7 @@ "ID": 0, "Attributes": 5, "IconID": 124, "Name": 127, "Tooltip": 154, "Rank": 136, "SchoolMask": 215 }, + "SpellRange": { "MaxRange": 4 }, "ItemDisplayInfo": { "ID": 0, "LeftModel": 1, "LeftModelTexture": 3, "InventoryIcon": 5, "GeosetGroup1": 7, "GeosetGroup3": 9, diff --git a/Data/expansions/wotlk/dbc_layouts.json b/Data/expansions/wotlk/dbc_layouts.json index d802b540..82252391 100644 --- a/Data/expansions/wotlk/dbc_layouts.json +++ b/Data/expansions/wotlk/dbc_layouts.json @@ -4,6 +4,7 @@ "Name": 136, "Tooltip": 139, "Rank": 153, "SchoolMask": 225, "PowerType": 14, "ManaCost": 39, "CastingTimeIndex": 47, "RangeIndex": 49 }, + "SpellRange": { "MaxRange": 4 }, "ItemDisplayInfo": { "ID": 0, "LeftModel": 1, "LeftModelTexture": 3, "InventoryIcon": 5, "GeosetGroup1": 7, "GeosetGroup3": 9, diff --git a/src/game/game_handler.cpp b/src/game/game_handler.cpp index 79071a51..e8ecdf72 100644 --- a/src/game/game_handler.cpp +++ b/src/game/game_handler.cpp @@ -15671,8 +15671,10 @@ void GameHandler::loadSpellNameCache() { return; } - if (dbc->getFieldCount() < 154) { - LOG_WARNING("Trainer: Spell.dbc has too few fields"); + // Classic 1.12 Spell.dbc has 148 fields; TBC/WotLK have more. + // Require at least 148 so Classic trainers can resolve spell names. + if (dbc->getFieldCount() < 148) { + LOG_WARNING("Trainer: Spell.dbc has too few fields (", dbc->getFieldCount(), ")"); return; } diff --git a/src/ui/spellbook_screen.cpp b/src/ui/spellbook_screen.cpp index 38c01fe8..99af8c1f 100644 --- a/src/ui/spellbook_screen.cpp +++ b/src/ui/spellbook_screen.cpp @@ -66,15 +66,26 @@ void SpellbookScreen::loadSpellDBC(pipeline::AssetManager* assetManager) { } } - // Load SpellRange.dbc: field 0=ID, field 5=MaxRangeHostile (float) + // Load SpellRange.dbc. Field layout differs by expansion: + // Classic 1.12: 0=ID, 1=MinRange, 2=MaxRange, 3=Flags, 4+=strings + // TBC / WotLK: 0=ID, 1=MinRangeFriendly, 2=MinRangeHostile, + // 3=MaxRangeFriendly, 4=MaxRangeHostile, 5=Flags, 6+=strings + // The correct field is declared in each expansion's dbc_layouts.json. + uint32_t spellRangeMaxField = 4; // WotLK / TBC default: MaxRangeHostile + const auto* spellRangeL = pipeline::getActiveDBCLayout() + ? pipeline::getActiveDBCLayout()->getLayout("SpellRange") + : nullptr; + if (spellRangeL) { + try { spellRangeMaxField = (*spellRangeL)["MaxRange"]; } catch (...) {} + } std::unordered_map rangeMap; // index → max yards auto rangeDbc = assetManager->loadDBC("SpellRange.dbc"); if (rangeDbc && rangeDbc->isLoaded()) { uint32_t rangeFieldCount = rangeDbc->getFieldCount(); - if (rangeFieldCount >= 6) { + if (rangeFieldCount > spellRangeMaxField) { for (uint32_t i = 0; i < rangeDbc->getRecordCount(); ++i) { uint32_t id = rangeDbc->getUInt32(i, 0); - float maxRange = rangeDbc->getFloat(i, 5); + float maxRange = rangeDbc->getFloat(i, spellRangeMaxField); if (id > 0 && maxRange > 0.0f) rangeMap[id] = maxRange; }