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:
parent
e3605672bb
commit
09612f9981
9 changed files with 128 additions and 53 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,8 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
private readonly Action<uint> _useItem;
|
||||
private readonly Action<int, int, uint>? _addFavorite;
|
||||
private readonly Action<int, uint>? _removeFavorite;
|
||||
private readonly UiShortcutSlotGraphics? _shortcutGraphics;
|
||||
private readonly UiShortcutDigitGraphics? _shortcutDigits;
|
||||
private readonly uint _emptySlotSprite;
|
||||
private readonly UiElement[] _tabs;
|
||||
private readonly UiElement[] _groups;
|
||||
private readonly UiItemList?[] _lists;
|
||||
|
|
@ -79,7 +80,8 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
UiItemList?[] lists,
|
||||
UiButton cast,
|
||||
UiElement endowmentHost,
|
||||
UiShortcutSlotGraphics? shortcutGraphics)
|
||||
UiShortcutDigitGraphics? shortcutDigits,
|
||||
uint emptySlotSprite)
|
||||
{
|
||||
_spellbook = spellbook;
|
||||
_casting = casting;
|
||||
|
|
@ -91,7 +93,8 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
_useItem = useItem;
|
||||
_addFavorite = addFavorite;
|
||||
_removeFavorite = removeFavorite;
|
||||
_shortcutGraphics = shortcutGraphics;
|
||||
_shortcutDigits = shortcutDigits;
|
||||
_emptySlotSprite = emptySlotSprite;
|
||||
_tabs = tabs;
|
||||
_groups = groups;
|
||||
_lists = lists;
|
||||
|
|
@ -143,7 +146,8 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
SelectionState selection,
|
||||
Action<int, int, uint>? addFavorite,
|
||||
Action<int, uint>? removeFavorite,
|
||||
UiShortcutSlotGraphics? shortcutGraphics = null)
|
||||
UiShortcutDigitGraphics? shortcutDigits = null,
|
||||
uint emptySlotSprite = 0u)
|
||||
{
|
||||
if (layout.FindElement(CastButtonId) is not UiButton cast
|
||||
|| layout.FindElement(EndowmentId) is not { } endowmentHost)
|
||||
|
|
@ -166,7 +170,8 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
layout, spellbook, casting, objects, playerGuid, resolveSpellIcon,
|
||||
resolveItemDragIcon, useItem, selection,
|
||||
addFavorite, removeFavorite,
|
||||
tabs, groups, lists, cast, endowmentHost, shortcutGraphics);
|
||||
tabs, groups, lists, cast, endowmentHost,
|
||||
shortcutDigits, emptySlotSprite);
|
||||
}
|
||||
|
||||
public void AddFavorite(uint spellId)
|
||||
|
|
@ -291,6 +296,7 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
list.SingleRow = true;
|
||||
list.CellWidth = 32f;
|
||||
list.CellHeight = 32f;
|
||||
list.CellEmptySprite = _emptySlotSprite;
|
||||
list.EmptySlotFactory = () => CreateEmptyFavoriteSlot(list, targetTab);
|
||||
list.FillVisibleEmptySlots = true;
|
||||
foreach (uint spellId in favorites)
|
||||
|
|
@ -332,9 +338,6 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
slot = new UiCatalogSlot
|
||||
{
|
||||
SpriteResolve = list.SpriteResolve,
|
||||
EmptySprite = _shortcutGraphics is { EmptySprite: > 0u } graphics
|
||||
? graphics.EmptySprite
|
||||
: 0x060074CFu,
|
||||
Dropped = payload =>
|
||||
{
|
||||
int position = Math.Max(0, list.IndexOf(slot!));
|
||||
|
|
@ -362,11 +365,9 @@ public sealed class SpellcastingUiController : IRetainedPanelController
|
|||
|
||||
private void ConfigureShortcutOverlay(UiItemSlot slot, int index)
|
||||
{
|
||||
slot.RegularDigits = _shortcutGraphics?.RegularDigits;
|
||||
slot.GhostedDigits = _shortcutGraphics?.GhostedDigits;
|
||||
slot.EmptyDigits = _shortcutGraphics?.EmptyDigits;
|
||||
if (_shortcutGraphics is { EmptySprite: > 0u } graphics)
|
||||
slot.EmptySprite = graphics.EmptySprite;
|
||||
slot.RegularDigits = _shortcutDigits?.RegularDigits;
|
||||
slot.GhostedDigits = _shortcutDigits?.GhostedDigits;
|
||||
slot.EmptyDigits = _shortcutDigits?.EmptyDigits;
|
||||
if (index < 9)
|
||||
slot.SetShortcutNum(index, ghosted: false);
|
||||
else
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue