fix(paperdoll): port quest-gated Aetheria slots
Add the three authored blue, yellow, and red sigil backgrounds and drive their visibility from player PropertyInt.AetheriaBitfield bits 1/2/4 at login and on live updates, matching gmPaperDollUI::UpdateAetheria. Include the sigil equip masks in the shared slot table and narrow AP-108. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
1be18cc4db
commit
edc9be3008
11 changed files with 208 additions and 16 deletions
|
|
@ -7,7 +7,7 @@ using AcDream.Core.Selection;
|
|||
namespace AcDream.App.UI.Layout;
|
||||
|
||||
/// <summary>
|
||||
/// Binds the ~21 equip slots mounted under the paperdoll (gmPaperDollUI 0x21000024, nested in the
|
||||
/// Binds the 24 equip slots mounted under the paperdoll (gmPaperDollUI 0x21000024, nested in the
|
||||
/// inventory frame 0x21000023) to live equipped-item data and makes them drag-drop WIELD targets.
|
||||
/// The acdream analogue of gmPaperDollUI::PostInit + GetLocationInfoFromElementID (named-retail decomp
|
||||
/// 175480 / 173620). Slice 1: equip slots only — no 3D doll viewport (that's Slice 2).
|
||||
|
|
@ -22,8 +22,8 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
/// <summary>
|
||||
/// The 9 armor-slot element-ids whose Visible state the Slots button (0x100005BE) toggles.
|
||||
/// Doll-view: hidden. Slot-view: shown. Source: gmPaperDollUI::ListenToElementMessage decomp
|
||||
/// 175674-175706 — these are the only 9 ids that element flips; the other ~12 equip slots
|
||||
/// (jewelry, weapon, wrists, feet…) are NON-armor and remain visible in both views.
|
||||
/// 175674-175706 — these are the only 9 ids that element flips. The 12 ordinary non-armor
|
||||
/// lists remain visible in both views; the three Aetheria lists are independently unlock-gated.
|
||||
/// </summary>
|
||||
public static readonly uint[] ArmorSlotElementIds =
|
||||
{
|
||||
|
|
@ -53,6 +53,7 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
private readonly SelectionState _selection;
|
||||
private readonly PaperdollClickMap? _clickMap;
|
||||
private readonly List<(EquipMask Mask, UiItemList List)> _slots = new();
|
||||
private readonly List<(AetheriaUnlockState Bit, UiItemList List)> _aetheriaSlots = new();
|
||||
|
||||
// ── Slots-toggle state ────────────────────────────────────────────────────────────────────────
|
||||
private readonly PaperdollViewState _viewState = new();
|
||||
|
|
@ -78,7 +79,7 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
|
||||
for (int i = 0; i < PaperdollSlotBackgrounds.Definitions.Length; i++)
|
||||
{
|
||||
var (element, mask, _) = PaperdollSlotBackgrounds.Definitions[i];
|
||||
var (element, mask, _, unlockBit) = PaperdollSlotBackgrounds.Definitions[i];
|
||||
if (layout.FindElement(element) is not UiItemList list) continue;
|
||||
list.RegisterDragHandler(this);
|
||||
list.Cell.SourceKind = ItemDragSource.Equipment;
|
||||
|
|
@ -108,6 +109,8 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
// insert-arrow 0x060011F7) are already wired by DatWidgetFactory when it built the UiItemList;
|
||||
// no need to re-set them here.
|
||||
_slots.Add((mask, list));
|
||||
if (unlockBit != AetheriaUnlockState.None)
|
||||
_aetheriaSlots.Add((unlockBit, list));
|
||||
}
|
||||
|
||||
_objects.ObjectAdded += OnObjectChanged;
|
||||
|
|
@ -198,7 +201,13 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
_selection.Select(hitObject, SelectionChangeSource.Paperdoll);
|
||||
}
|
||||
|
||||
private void OnObjectChanged(ClientObject o) { if (Concerns(o)) Populate(); }
|
||||
private void OnObjectChanged(ClientObject o)
|
||||
{
|
||||
if (o.ObjectId == _playerGuid())
|
||||
ApplyAetheriaVisibility();
|
||||
else if (Concerns(o))
|
||||
Populate();
|
||||
}
|
||||
private void OnObjectMoved(ClientObject o, uint from, uint to)
|
||||
{ if (Concerns(o) || from == _playerGuid() || to == _playerGuid()) Populate(); }
|
||||
private void OnSelectionChanged(SelectionTransition _) => ApplySelectionIndicators();
|
||||
|
|
@ -238,9 +247,22 @@ public sealed class PaperdollController : IItemListDragHandler, IRetainedPanelCo
|
|||
worn.Type, worn.IconId, worn.IconUnderlayId, worn.IconOverlayId, worn.Effects) ?? 0u;
|
||||
list.Cell.SetItem(worn.ObjectId, tex, dragIconTexture: dragTex);
|
||||
}
|
||||
ApplyAetheriaVisibility();
|
||||
ApplySelectionIndicators();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retail <c>gmPaperDollUI::UpdateAetheria @ 0x004A3E50</c>: property 0x142
|
||||
/// bits 1/2/4 independently expose the blue/yellow/red sigil lists. Missing
|
||||
/// player state is the locked state, matching PostInit before PlayerDescription.
|
||||
/// </summary>
|
||||
private void ApplyAetheriaVisibility()
|
||||
{
|
||||
AetheriaUnlockState unlocked = AetheriaUnlocks.Read(_objects.Get(_playerGuid()));
|
||||
foreach (var (bit, list) in _aetheriaSlots)
|
||||
list.Visible = (unlocked & bit) != AetheriaUnlockState.None;
|
||||
}
|
||||
|
||||
private void ApplySelectionIndicators()
|
||||
{
|
||||
foreach (var (_, list) in _slots)
|
||||
|
|
|
|||
|
|
@ -20,7 +20,8 @@ public static class PaperdollSlotBackgrounds
|
|||
internal readonly record struct Definition(
|
||||
uint Element,
|
||||
EquipMask Mask,
|
||||
uint EmptyPrototype);
|
||||
uint EmptyPrototype,
|
||||
AetheriaUnlockState UnlockBit = AetheriaUnlockState.None);
|
||||
|
||||
// WEAPON_READY_SLOT_LOC (acclient.h:3235): any wieldable weapon in the hand slot.
|
||||
private const EquipMask WeaponSlotMask =
|
||||
|
|
@ -49,6 +50,9 @@ public static class PaperdollSlotBackgrounds
|
|||
new(0x100001DFu, WeaponSlotMask, 0x1000044Bu),
|
||||
new(0x1000058Eu, EquipMask.TrinketOne, 0x1000058Fu),
|
||||
new(0x100005E9u, EquipMask.Cloak, 0x100005EAu),
|
||||
new(0x10000595u, EquipMask.SigilOne, 0x10000592u, AetheriaUnlockState.Blue),
|
||||
new(0x10000596u, EquipMask.SigilTwo, 0x10000593u, AetheriaUnlockState.Yellow),
|
||||
new(0x10000597u, EquipMask.SigilThree, 0x10000594u, AetheriaUnlockState.Red),
|
||||
};
|
||||
|
||||
/// <summary>Resolves every supported slot's exact empty RenderSurface from the live DAT.</summary>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue