From e38324619e31198a010b66f6508431d073d1cd76 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Tue, 17 Mar 2026 07:42:01 -0700 Subject: [PATCH] fix: resolve missing Classic spell icons on action bar and talents When Classic is active, loadDBC("Spell.dbc") finds the WotLK base DBC (234 fields) since no binary Classic DBC exists. The Classic layout says IconID is at field 117, but in the WotLK DBC that field contains unrelated data (mostly zeros). This caused all spell icon lookups to fail silently. Now detects the DBC/layout field count mismatch and falls back to the WotLK field index 133, which is correct for the base DBC. Classic spell IDs are a subset of WotLK, so the icon mapping works correctly. --- src/ui/game_screen.cpp | 24 +++++++++++++++--------- src/ui/talent_screen.cpp | 18 +++++++++++++++--- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/ui/game_screen.cpp b/src/ui/game_screen.cpp index 287f0456..eab06871 100644 --- a/src/ui/game_screen.cpp +++ b/src/ui/game_screen.cpp @@ -6551,17 +6551,23 @@ VkDescriptorSet GameScreen::getSpellIcon(uint32_t spellId, pipeline::AssetManage } }; - // Always use expansion-aware layout if available - // Field indices vary by expansion: Classic=117, TBC=124, WotLK=133 + // Use expansion-aware layout if available AND the DBC field count + // matches the expansion's expected format. Classic=173, TBC=216, + // WotLK=234 fields. When Classic is active but the base WotLK DBC + // is loaded (234 fields), field 117 is NOT IconID — we must use + // the WotLK field 133 instead. + uint32_t iconField = 133; // WotLK default + uint32_t idField = 0; if (spellL) { - tryLoadIcons((*spellL)["ID"], (*spellL)["IconID"]); - } - - // Fallback if expansion layout missing or yielded nothing - // Only use WotLK field 133 as last resort if we have no layout - if (spellIconIds_.empty() && !spellL && fieldCount > 133) { - tryLoadIcons(0, 133); + uint32_t layoutIcon = (*spellL)["IconID"]; + // Only trust the expansion layout if the DBC has a compatible + // field count (within ~20 of the layout's icon field). + if (layoutIcon < fieldCount && fieldCount <= layoutIcon + 20) { + iconField = layoutIcon; + idField = (*spellL)["ID"]; + } } + tryLoadIcons(idField, iconField); } } diff --git a/src/ui/talent_screen.cpp b/src/ui/talent_screen.cpp index bed817ab..c2b92eff 100644 --- a/src/ui/talent_screen.cpp +++ b/src/ui/talent_screen.cpp @@ -593,15 +593,27 @@ void TalentScreen::loadSpellDBC(pipeline::AssetManager* assetManager) { if (!dbc || !dbc->isLoaded()) return; const auto* spellL = pipeline::getActiveDBCLayout() ? pipeline::getActiveDBCLayout()->getLayout("Spell") : nullptr; + uint32_t fieldCount = dbc->getFieldCount(); + // Detect DBC/layout mismatch: Classic layout expects ~173 fields but we may + // load the WotLK base DBC (234 fields). Use WotLK field indices in that case. + uint32_t idField = 0, iconField = 133, tooltipField = 139; + if (spellL) { + uint32_t layoutIcon = (*spellL)["IconID"]; + if (layoutIcon < fieldCount && fieldCount <= layoutIcon + 20) { + idField = (*spellL)["ID"]; + iconField = layoutIcon; + try { tooltipField = (*spellL)["Tooltip"]; } catch (...) {} + } + } uint32_t count = dbc->getRecordCount(); for (uint32_t i = 0; i < count; ++i) { - uint32_t spellId = dbc->getUInt32(i, spellL ? (*spellL)["ID"] : 0); + uint32_t spellId = dbc->getUInt32(i, idField); if (spellId == 0) continue; - uint32_t iconId = dbc->getUInt32(i, spellL ? (*spellL)["IconID"] : 133); + uint32_t iconId = dbc->getUInt32(i, iconField); spellIconIds[spellId] = iconId; - std::string tooltip = dbc->getString(i, spellL ? (*spellL)["Tooltip"] : 139); + std::string tooltip = dbc->getString(i, tooltipField); if (!tooltip.empty()) { spellTooltips[spellId] = tooltip; }