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.
This commit is contained in:
Kelsi 2026-03-17 07:42:01 -07:00
parent 8378eb9232
commit e38324619e
2 changed files with 30 additions and 12 deletions

View file

@ -6551,17 +6551,23 @@ VkDescriptorSet GameScreen::getSpellIcon(uint32_t spellId, pipeline::AssetManage
} }
}; };
// Always use expansion-aware layout if available // Use expansion-aware layout if available AND the DBC field count
// Field indices vary by expansion: Classic=117, TBC=124, WotLK=133 // 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) { if (spellL) {
tryLoadIcons((*spellL)["ID"], (*spellL)["IconID"]); 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"];
} }
// 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);
} }
tryLoadIcons(idField, iconField);
} }
} }

View file

@ -593,15 +593,27 @@ void TalentScreen::loadSpellDBC(pipeline::AssetManager* assetManager) {
if (!dbc || !dbc->isLoaded()) return; if (!dbc || !dbc->isLoaded()) return;
const auto* spellL = pipeline::getActiveDBCLayout() ? pipeline::getActiveDBCLayout()->getLayout("Spell") : nullptr; 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(); uint32_t count = dbc->getRecordCount();
for (uint32_t i = 0; i < count; ++i) { 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; if (spellId == 0) continue;
uint32_t iconId = dbc->getUInt32(i, spellL ? (*spellL)["IconID"] : 133); uint32_t iconId = dbc->getUInt32(i, iconField);
spellIconIds[spellId] = iconId; spellIconIds[spellId] = iconId;
std::string tooltip = dbc->getString(i, spellL ? (*spellL)["Tooltip"] : 139); std::string tooltip = dbc->getString(i, tooltipField);
if (!tooltip.empty()) { if (!tooltip.empty()) {
spellTooltips[spellId] = tooltip; spellTooltips[spellId] = tooltip;
} }