fix(ui): resolve retail spell slot background

Keep shared shortcut digit overlays separate from the per-ItemList background. Resolve the magic favorite list through its cross-layout inherited cell prototype and use the pinned brown/gold ItemSlot_Empty surface instead of the blue toolbar slot.

Co-authored-by: OpenAI Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-15 19:23:46 +02:00
parent e3605672bb
commit 09612f9981
9 changed files with 128 additions and 53 deletions

View file

@ -21,8 +21,8 @@ public static class ItemListCellTemplate
public const uint CatalogLayoutId = 0x21000037u;
private const uint CellTemplateAttr = 0x1000000eu; // UIElement attribute: cell-template element id
private const uint IconChildId = 0x1000033Bu; // m_elem_Icon sub-element (carries ItemSlot_Empty)
private const string ItemSlotEmpty = "ItemSlot_Empty"; // UIStateId.ToString() for state 0x1000001c
private const uint IconChildId = 0x1000033Bu; // m_elem_Icon sub-element (carries ItemSlot_Empty)
private const string ItemSlotEmpty = "ItemSlot_Empty"; // UIStateId.ToString() for state 0x1000001c
/// <summary>
/// Resolve the empty-slot sprite (a 0x06xxxxxx RenderSurface id) for the cells of item-list
@ -43,6 +43,29 @@ public static class ItemListCellTemplate
return ResolvePrototypeEmptySprite(dats, protoId);
}
/// <summary>
/// Resolve from an already inherited <see cref="ElementInfo"/> tree. Use this
/// overload when the ItemList is contributed by a cross-layout BaseElement:
/// the raw outer LayoutDesc does not physically contain that descendant, but
/// <see cref="LayoutImporter.ImportInfos(DatCollection,uint)"/> has applied the
/// same inheritance that retail uses before <c>InternalCreateItem</c> queries
/// attribute <c>0x1000000E</c>.
/// </summary>
public static uint ResolveEmptySprite(
DatCollection dats,
ElementInfo resolvedRoot,
uint listElementId)
{
ElementInfo? list = FindInfo(resolvedRoot, listElementId);
if (list is null
|| !list.TryGetEffectiveProperty(CellTemplateAttr, out UiPropertyValue property)
|| property.Kind is not (UiPropertyKind.Enum or UiPropertyKind.DataId)
|| property.UnsignedValue is 0 or > uint.MaxValue)
return 0;
return ResolvePrototypeEmptySprite(dats, (uint)property.UnsignedValue);
}
/// <summary>
/// Resolves <c>ItemSlot_Empty</c> directly from an authored UIItem prototype in
/// <see cref="CatalogLayoutId"/>. Paperdoll lists select distinct prototypes for their
@ -168,4 +191,15 @@ public static class ItemListCellTemplate
}
return null;
}
private static ElementInfo? FindInfo(ElementInfo element, uint id)
{
if (element.Id == id) return element;
foreach (ElementInfo child in element.Children)
{
ElementInfo? found = FindInfo(child, id);
if (found is not null) return found;
}
return null;
}
}