fix(paperdoll): restore authored slot backgrounds

Port the retail UIItem catalog path so every supported equipment location resolves its exact empty-state silhouette from live DAT. Share one definition table between equip behavior and presentation, wire runtime plus UI Studio, pin all 21 prototypes and surfaces, and retire AP-66.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-13 09:43:21 +02:00
parent 6ba4148b24
commit 1be18cc4db
11 changed files with 335 additions and 52 deletions

View file

@ -36,12 +36,14 @@ public class PaperdollControllerTests
private static PaperdollController Bind(ImportedLayout layout, ClientObjectTable objects,
List<(uint item, uint mask)>? wields = null, uint emptySlot = 0u,
SelectionState? selection = null)
SelectionState? selection = null,
IReadOnlyDictionary<uint, uint>? emptySlotSprites = null)
=> PaperdollController.Bind(layout, objects, () => Player,
iconIds: (_, _, _, _, _) => 0x1234u,
sendWield: wields is null ? null : (i, m) => wields.Add((i, m)),
emptySlotSprite: emptySlot,
selection: selection ?? new SelectionState());
selection: selection ?? new SelectionState(),
emptySlotSprites: emptySlotSprites);
private static void SeedEquipped(ClientObjectTable t, uint guid, EquipMask loc)
{
@ -219,6 +221,26 @@ public class PaperdollControllerTests
Assert.Equal(0x06004D20u, lists[HeadSlot].Cell.EmptySprite);
}
[Fact]
public void PerLocation_empty_sprites_override_the_generic_fallback()
{
var (layout, lists) = BuildLayout();
var sprites = new Dictionary<uint, uint>
{
[HeadSlot] = 0x06006D7Fu,
[ChestSlot] = 0x060032C5u,
[ChestArmorSlot] = 0x06006D7Bu,
[ShieldSlot] = 0x06000F6Cu,
[WeaponSlot] = 0x06000F66u,
[FingerLSlot] = 0x06000F5Au,
};
Bind(layout, new ClientObjectTable(), emptySlot: 0x06004D20u, emptySlotSprites: sprites);
foreach (var (element, sprite) in sprites)
Assert.Equal(sprite, lists[element].Cell.EmptySprite);
}
[Fact]
public void Live_player_wield_repaints_the_slot() // event-driven: ObjectMoved → Concerns → Populate
{