diff --git a/docs/architecture/retail-divergence-register.md b/docs/architecture/retail-divergence-register.md index 69b393f1..33912121 100644 --- a/docs/architecture/retail-divergence-register.md +++ b/docs/architecture/retail-divergence-register.md @@ -164,6 +164,7 @@ accepted-divergence entries (#96, #49, #50). | AP-63 | **Dual-wield-into-shield-slot special not implemented** — retail `OnItemListDragOver` (decomp 174302) lets a melee-capable item also drop on the Shield slot; acdream's `wieldMask = ValidLocations & slotMask` rejects it. | `src/AcDream.App/UI/Layout/PaperdollController.cs` (`HandleDropRelease`) | A dual-wielder cannot off-hand a melee weapon via the doll. | Dual-wield via drag-onto-shield-slot is blocked — functional gap for dual-wield characters. | `gmPaperDollUI::OnItemListDragOver` decomp 174302 | | AP-64 | **Wield-reject rollback assumes `InventoryServerSaveFailed 0x00A0`** — an optimistic wield rolls back only if ACE emits `0x00A0` for a `GetAndWieldItem` rejection; otherwise corrected by the next authoritative message. Gate-verify via WireMCP. | `src/AcDream.Core.Net/GameEventWiring.cs` (0x00A0 handler) | If ACE uses a different reject opcode for wield, the optimistic state is left dangling until the next full update. | Rejected wield briefly shows the item as equipped in the doll — cosmetic flicker or stuck state if `0x00A0` is not the rejection path. | `InventoryServerSaveFailed 0x00A0`; WireMCP gate-verify | | AP-65 | **PickupEvent (0xF74A) no longer evicts the weenie from `ClientObjectTable`** — only `DeleteObject (0xF747)` evicts, matching the retail `object_table`-vs-`weenie_object_table` split. An item another player picks up near you (only ever gets `PickupEvent`, never `DeleteObject`) lingers as a data-only entry (`ContainerId 0`, not in any view) until teleport/relog `Clear()`. | `src/AcDream.Core.Net/ObjectTableWiring.cs` (EntityDeleted handler); `src/AcDream.Core.Net/WorldSession.cs` (PickupEvent branch) | The weenie entry for nearby pickups is a harmless data ghost — no UI shows it (no container, not wielded). Retail evicts it from `weenie_object_table` when the object fully leaves interest range via `DeleteObject`; acdream defers to teleport/relog clear. | Slight memory growth in long sessions if many world items are picked up by other players near you; item data ghosts cannot cause functional issues because no UI queries `ContainerId 0`. | `CACObjectMaint::DeleteObject` / `SmartBox::HandleDeleteObject`; ACE `Player_Inventory.cs TryDequipObjectWithNetworking` | +| AP-66 | **Empty equip slots show a generic frame (Slice 1) instead of the retail doll-backed transparent look** — retail's slot-view leaves empty armor slots transparent with the live 3-D doll body behind them; Slice 1 has no doll yet, so empty slots render a visible frame (`0x06004D20`, the inventory grid's empty square) so every position is seen + usable. The "figure" in the paperdoll is the doll, NOT a per-slot silhouette. | `src/AcDream.App/UI/Layout/PaperdollController.cs` (`emptySlotSprite`); `src/AcDream.App/Rendering/GameWindow.cs` (PaperdollController.Bind) | Retired in Slice 2 when the doll `UiViewport` (`0x100001D5`) renders behind the slots and the empty slots flip to transparent (`EmptySprite=0`). | Empty equip slots look like plain framed squares instead of revealing the character body — cosmetic, pending Slice 2's doll viewport. | `gmPaperDollUI` init `SetVisible(0)` per slot; user retail screenshots (slot-view) | --- diff --git a/docs/research/2026-06-22-paperdoll-handoff.md b/docs/research/2026-06-22-paperdoll-handoff.md index 5e892362..028572d8 100644 --- a/docs/research/2026-06-22-paperdoll-handoff.md +++ b/docs/research/2026-06-22-paperdoll-handoff.md @@ -5,6 +5,17 @@ **Status:** SCOPED, not started. The decomposition + corrections + reuse map below are the design sketch; a fresh session runs the full brainstorm → spec → plan → subagent-driven → visual-gate flow **per slice**. **Line numbers drift — grep the symbol.** +> **⚠ SUPERSEDED / CORRECTED 2026-06-23 — Slice 1 SHIPPED (`a4c6852`).** This handoff's "⚠ Correction" +> section below ("empty equip slots are TRANSPARENT, no silhouettes") **was WRONG** and cost a visual-gate +> iteration. The user-axiom truth (his retail screenshots): the paperdoll has a **"Slots" toggle button +> (`0x100005BE` = `m_SlotCheckbox`)**. Button OFF (default) = the **live 3-D character** (the doll — can be +> naked) + the non-armor slots (weapon/shield/wand/jewelry/under-clothes); button ON = the doll **hides** and +> the **armor slots** become visible. **The "figure"/"silhouette" IS the doll (live render), NOT per-slot +> silhouette sprites — there are none.** So the doll `UiViewport` (Type 0xD, `0x100001D5`) + the Slots toggle +> = **Slice 2**. Slice 1 (equip-slot bind + wield/unwield + **visible empty-slot frames** + the `EquipMask` +> correction + the `PickupEvent` unwield fix) SHIPPED. **The corrected model + the full DO-NOT-RETRY list live +> in `claude-memory/project_d2b_retail_ui.md` (the Slice 1 entry) — read that, not the §"⚠ Correction" below.** + --- ## Read first (in this order)