feat(ui): the spell-bar drop ring — retail's authored drag-accept state, and the ring exposed a real drop off-by-one
Some checks failed
Headless portability / portable-headless (ubuntu-latest) (push) Has been cancelled
Headless portability / portable-headless (windows-latest) (push) Has been cancelled
Headless portability / linux-graphical (push) Has been cancelled
Headless portability / linux-vulkan (push) Has been cancelled
Some checks failed
Headless portability / portable-headless (ubuntu-latest) (push) Has been cancelled
Headless portability / portable-headless (windows-latest) (push) Has been cancelled
Headless portability / linux-graphical (push) Has been cancelled
Headless portability / linux-vulkan (push) Has been cancelled
The green ring is retail's own art: every UIItem cell carries an authored DragAccept child (catalog 0x21000037, child 0x1000045A), and the spell bar's drag-over handler (SpellCastSubMenu::OnItemListDragOver @0x004C5990) flips it to the Accept state (0x10000040 -> surface 0x060011F9) for any spell payload. Ported through a per-slot SetDragAcceptVisual seam + a catalog DragOverAcceptance hook; other lists are untouched (null acceptance = neutral). A polarity error in our older docs (Accept/Reject state ids swapped) was corrected against three independent sources; the shipped art was always right, only the labels lied. The ring shares ONE landing computation with the drop (FavoriteDropIndex) — and that requirement exposed a genuine #354 off-by-one: the empty-tail path double-applied the -1 adjustment (retail gates it on the lift's removal @0x004C7157), landing a reordered spell second-to-last instead of last. Fixed; discriminator-verified both ways. AP-172 narrowed + its false empty-tail claim corrected. Clean-room complete solution: 11,545 passed / 4 skipped / 0 failed. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
81a9d85a1d
commit
6bb4cfa795
9 changed files with 434 additions and 34 deletions
|
|
@ -60,6 +60,36 @@ bytes for `AddSpellFavorite`/`RemoveSpellFavorite` (opcodes 0x1E3/0x1E4) and
|
|||
`RuntimeCharacterState.TryAddFavorite`/`TryRemoveFavorite` were already
|
||||
covered and needed no change.
|
||||
|
||||
**UPDATE 2026-08-08 (follow-up session, drop-ring gate finding):** the user's
|
||||
next gate finding — "Should be the green ring indicator where the spell icon
|
||||
should land, like in retail" — is implemented. Retail's mechanism (grepped and
|
||||
byte-confirmed): the ring is a per-cell authored slot STATE, not a synthetic
|
||||
overlay — `SpellCastSubMenu::OnItemListDragOver` @0x004C5990 sets the shared
|
||||
UIItem prototype's `m_elem_Icon_DragAccept` child (element 0x1000045A, bound in
|
||||
`UIElement_UIItem::PostInit` @0x004E1870, catalog LayoutDesc 0x21000037) to
|
||||
`ItemSlot_DragOver_Accept` (UIStateId 0x10000040 → authored art 0x060011F9)
|
||||
whenever the dragged payload carries a spell id; leave resets to
|
||||
`ItemSlot_DragOver_Normal` 0x1000003F @0x004E1438. Wired through
|
||||
`UiCatalogSlot.DragOverAcceptance` (the catalog port of retail's per-list drag
|
||||
handler) → the shared `UiItemSlot.DrawDragAcceptOverlay`. Two corrections
|
||||
landed with it: (1) the accept/reject UIStateId labels were SWAPPED in
|
||||
`UiItemSlot`/`InventoryController` comments and in the 2026-06-16 / 2026-07-13
|
||||
research docs (art-per-semantic was always right; polarity pinned by paperdoll
|
||||
`AutoWearIsLegal` @0x004A3AC9/0x004A3AEB, `VendorSellUI` @0x004C2327/0x004C2336,
|
||||
DatReaderWriter's `UIStateId` enum, and the 2026-06-25 layout dump); (2) a real
|
||||
off-by-one in #354's drop path: the `-1` adjustment double-corrected the
|
||||
empty-tail cell's live-count-clamped index, landing a lifted non-last favorite
|
||||
second-to-last instead of last — retail's adjustment is gated on
|
||||
`RemoveSpellFromMenu`'s return (@0x004C7157), which is `-1` (no adjustment) at
|
||||
drop time because the spell left the live list at lift. `FavoriteDropIndex` is
|
||||
now THE one landing computation shared by the ring and the drop
|
||||
(discriminator-verified: the pre-fix computation fails
|
||||
`SpellFavoriteDrag_DroppedOnTheEmptyTail_AppendsAtTheEnd` with landed index 1
|
||||
vs 2). AP-172 narrowed + corrected in the same change-set. New tests: ring
|
||||
appears/tracks/survives-a-tick/clears-on-drop, empty-tail append, ring clears
|
||||
on leave + off-bar release keeps the lift removal, physical payloads stay
|
||||
neutral while both spell payload kinds ring.
|
||||
|
||||
## #353 — Toolbar selected-object text: count field ignores authored HJustify; name field does not wrap to its authored two lines
|
||||
|
||||
**Status:** CLOSED 2026-08-08 — user-passed ("Ok slider bar looks ok!" + the wrap confirmed); the OneLine routing fix (4cfcc8b3) completed it. (RightAligned on the authored HJustify=2 entry; two stacked centered one-line labels wrapping at the authored 140 px via WrapNameTwoLines).
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -141,6 +141,19 @@ internal element states `SetDragAcceptState` writes — both are real; the Layou
|
|||
states and the `0x1000003x/4x` UIStateIds are the same overlay seen from the dat side vs.
|
||||
the C++ side. CONFIRMED.
|
||||
|
||||
> **Correction 2026-08-08 (spell-bar drop-ring research):** the parenthetical
|
||||
> above has the accept/reject ids SWAPPED. The true mapping is
|
||||
> `ItemSlot_DragOver_Accept = 0x10000040 → 0x060011F9` and
|
||||
> `ItemSlot_DragOver_Reject = 0x10000041 → 0x060011F8`, confirmed by
|
||||
> DatReaderWriter's retail-derived `UIStateId` enum, by the legal/illegal
|
||||
> branches of `gmPaperDollUI::HandlePaperDollDragOver` @ 0x004A3AC9/0x004A3AEB
|
||||
> and `VendorSellUI::OnItemListDragOver` @ 0x004C2327/0x004C2336, and by the
|
||||
> machine layout dump (`2026-06-25-retail-ui-layout-dump.json`, states
|
||||
> 268435520/268435521 on elements 0x1000046D/0x1000046C). The table row's
|
||||
> name→art column above was always right; only this paragraph's numeric
|
||||
> pairing was inverted (and propagated into
|
||||
> `2026-07-13-retail-item-drag-visuals-pseudocode.md`, corrected the same day).
|
||||
|
||||
### 2.3 Key methods + the update pass (`UIItem_Update`, decomp 230226)
|
||||
|
||||
`UIItem_Update` is the per-change refresh; the controller calls it whenever the bound
|
||||
|
|
|
|||
|
|
@ -79,12 +79,28 @@ if target list is a container selector
|
|||
target.SetDragAcceptState(0x10000046) # ItemSlot_DragOver_DropIn
|
||||
# 0x060011F7 green arrow
|
||||
else if target accepts an ordinary item-list placement:
|
||||
target.SetDragAcceptState(0x10000041) # ItemSlot_DragOver_Accept
|
||||
target.SetDragAcceptState(0x10000040) # ItemSlot_DragOver_Accept
|
||||
# 0x060011F9 green circle
|
||||
else:
|
||||
target.SetDragAcceptState(0x10000040) # 0x060011F8 reject
|
||||
target.SetDragAcceptState(0x10000041) # ItemSlot_DragOver_Reject
|
||||
# 0x060011F8 reject
|
||||
```
|
||||
|
||||
> **Correction 2026-08-08 (spell-bar drop-ring research):** the block above
|
||||
> originally had the Accept/Reject numeric ids swapped (`0x10000041` labeled
|
||||
> Accept, `0x10000040` labeled reject). Three primary sources agree the true
|
||||
> mapping is `ItemSlot_DragOver_Accept = 0x10000040 → 0x060011F9` and
|
||||
> `ItemSlot_DragOver_Reject = 0x10000041 → 0x060011F8`: DatReaderWriter's
|
||||
> retail-derived `UIStateId` enum; the legal/illegal branches in
|
||||
> `gmPaperDollUI::HandlePaperDollDragOver` (`AutoWearIsLegal` → 0x10000040
|
||||
> @ 0x004A3AC9, else 0x10000041 @ 0x004A3AEB) and
|
||||
> `VendorSellUI::OnItemListDragOver` (`DragItemAcceptable` → 0x10000040
|
||||
> @ 0x004C2327, else 0x10000041 @ 0x004C2336); and the machine layout dump
|
||||
> (`2026-06-25-retail-ui-layout-dump.json`: state 268435520 = 0x10000040 →
|
||||
> image 0x060011F9, state 268435521 = 0x10000041 → 0x060011F8). The
|
||||
> art-per-semantic mapping in the shipped code was always correct; only the
|
||||
> numeric labels here were swapped.
|
||||
|
||||
Therefore the backpack contents grid uses the green circle; the side-bag column
|
||||
and main-pack container cell use the green drop-in arrow. The selected/open
|
||||
indicators remain visible while `m_elem_Icon_Ghosted` is active, so the
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue