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:
parent
6ba4148b24
commit
1be18cc4db
11 changed files with 335 additions and 52 deletions
|
|
@ -44,37 +44,6 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
public void Toggle() => SlotView = !SlotView;
|
||||
}
|
||||
|
||||
// WEAPON_READY_SLOT_LOC (acclient.h:3235): the weapon-hand doll slot accepts any wieldable weapon.
|
||||
private const EquipMask WeaponSlotMask =
|
||||
EquipMask.MeleeWeapon | EquipMask.MissileWeapon | EquipMask.Held | EquipMask.TwoHanded;
|
||||
|
||||
// element-id → EquipMask (verified: dump paperdoll-0x21000024.txt ↔ deep-dive §3a ↔ acclient.h:3193).
|
||||
// The 3 Aetheria sigil slots (0x10000595/96/97) are SetVisible(0) in retail — skipped (Slice 1 scope).
|
||||
private static readonly (uint Element, EquipMask Mask)[] SlotMap =
|
||||
{
|
||||
(0x100005ABu, EquipMask.HeadWear), // 0x1
|
||||
(0x100001E2u, EquipMask.ChestWear), // 0x2
|
||||
(0x100001E3u, EquipMask.UpperLegWear), // 0x40
|
||||
(0x100005B0u, EquipMask.HandWear), // 0x20
|
||||
(0x100005B3u, EquipMask.FootWear), // 0x100
|
||||
(0x100005ACu, EquipMask.ChestArmor), // 0x200
|
||||
(0x100005ADu, EquipMask.AbdomenArmor), // 0x400
|
||||
(0x100005AEu, EquipMask.UpperArmArmor), // 0x800
|
||||
(0x100005AFu, EquipMask.LowerArmArmor), // 0x1000
|
||||
(0x100005B1u, EquipMask.UpperLegArmor), // 0x2000
|
||||
(0x100005B2u, EquipMask.LowerLegArmor), // 0x4000
|
||||
(0x100001DAu, EquipMask.NeckWear), // 0x8000
|
||||
(0x100001DBu, EquipMask.WristWearLeft), // 0x10000
|
||||
(0x100001DDu, EquipMask.WristWearRight), // 0x20000
|
||||
(0x100001DCu, EquipMask.FingerWearLeft), // 0x40000
|
||||
(0x100001DEu, EquipMask.FingerWearRight), // 0x80000
|
||||
(0x100001E1u, EquipMask.Shield), // 0x200000
|
||||
(0x100001E0u, EquipMask.MissileAmmo), // 0x800000 (LIKELY — gate-verify, AP row)
|
||||
(0x100001DFu, WeaponSlotMask), // 0x3500000 composite
|
||||
(0x1000058Eu, EquipMask.TrinketOne), // 0x4000000
|
||||
(0x100005E9u, EquipMask.Cloak), // 0x8000000
|
||||
};
|
||||
|
||||
private readonly ClientObjectTable _objects;
|
||||
private readonly Func<uint> _playerGuid;
|
||||
private readonly Func<ItemType, uint, uint, uint, uint, uint> _iconIds;
|
||||
|
|
@ -98,7 +67,8 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
Action<uint, uint>? sendWield,
|
||||
uint emptySlotSprite, UiDatFont? datFont, ItemInteractionController? itemInteraction,
|
||||
PaperdollClickMap? clickMap,
|
||||
Func<ItemType, uint, uint, uint, uint, uint>? dragIconIds)
|
||||
Func<ItemType, uint, uint, uint, uint, uint>? dragIconIds,
|
||||
IReadOnlyDictionary<uint, uint>? emptySlotSprites)
|
||||
{
|
||||
_objects = objects; _playerGuid = playerGuid; _iconIds = iconIds; _sendWield = sendWield;
|
||||
_dragIconIds = dragIconIds;
|
||||
|
|
@ -106,14 +76,17 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
_selection = selection ?? throw new ArgumentNullException(nameof(selection));
|
||||
_clickMap = clickMap;
|
||||
|
||||
for (int i = 0; i < SlotMap.Length; i++)
|
||||
for (int i = 0; i < PaperdollSlotBackgrounds.Definitions.Length; i++)
|
||||
{
|
||||
var (element, mask) = SlotMap[i];
|
||||
var (element, mask, _) = PaperdollSlotBackgrounds.Definitions[i];
|
||||
if (layout.FindElement(element) is not UiItemList list) continue;
|
||||
list.RegisterDragHandler(this);
|
||||
list.Cell.SourceKind = ItemDragSource.Equipment;
|
||||
list.Cell.SlotIndex = i; // SlotMap position = this equipped item's drag-payload SourceSlot when dragged out to unwield
|
||||
list.Cell.EmptySprite = emptySlotSprite; // visible empty-slot frame so every position is seen + usable. The live
|
||||
list.Cell.SlotIndex = i; // definition position = equipped drag-payload SourceSlot
|
||||
list.Cell.EmptySprite = emptySlotSprites is not null
|
||||
&& emptySlotSprites.TryGetValue(element, out uint authoredSprite)
|
||||
? authoredSprite
|
||||
: emptySlotSprite;
|
||||
list.Cell.Clicked = () =>
|
||||
{
|
||||
uint itemId = list.Cell.ItemId;
|
||||
|
|
@ -199,10 +172,11 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
uint emptySlotSprite = 0u, UiDatFont? datFont = null,
|
||||
ItemInteractionController? itemInteraction = null,
|
||||
PaperdollClickMap? clickMap = null,
|
||||
Func<ItemType, uint, uint, uint, uint, uint>? dragIconIds = null)
|
||||
Func<ItemType, uint, uint, uint, uint, uint>? dragIconIds = null,
|
||||
IReadOnlyDictionary<uint, uint>? emptySlotSprites = null)
|
||||
=> new PaperdollController(
|
||||
layout, objects, playerGuid, iconIds, selection, sendWield, emptySlotSprite,
|
||||
datFont, itemInteraction, clickMap, dragIconIds);
|
||||
datFont, itemInteraction, clickMap, dragIconIds, emptySlotSprites);
|
||||
|
||||
private void HandleDollClick(int x, int y)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue