Place favorite-bar arrows by their authored sides, import rollover and pressed media through the shared scrollbar, and preserve manual offsets across passive refreshes. Carry the mixed-parent DAT anchor chain to a fixed 18-cell favorite viewport so overflow controls and the Cast button remain inside the retail-sized combat frame. Co-authored-by: Codex <codex@openai.com>
6.2 KiB
World interaction completion — pre-M4 program
Status: Slice 1 code-complete 2026-07-23; connected visual gate pending.
Milestone: M4 prerequisite/preamble.
Architecture: retained gameplay UI over shared selection, object, and
interaction state. GameWindow remains a composition/callback shell.
Outcome
Close the remaining retail interaction surfaces before the larger M4 quest/emote/character-creation bodies begin:
- Favorite spell bars expose their DAT-authored overflow arrows and scroll through every server-persisted favorite.
- The status bar's hand and magnifying-glass controls invoke the same Use and Assess commands as their keyboard paths.
- Assessing a creature, player, NPC, or object opens its retail information in the canonical shared main-panel host.
- World picking can resolve visible equipped children, such as a character's wielded weapon, while selection markers remain anchored to the picked child.
- Vendor use opens the authored vendor surface, publishes its inventory, and supports retail selection/browsing.
- Vendor buy/sell transactions, quantities, pending-state ownership, and authoritative inventory reconciliation complete the loop.
The program reuses the existing retained-window host, SelectionState,
ClientObjectTable, interaction transaction owner, and server-authoritative
inventory updates. It does not create parallel panel positions, item tables,
selection state, or optimistic inventory outcomes.
Ordered slices
| Slice | Deliverable | Principal owner |
|---|---|---|
| 1 | Spell-bar overflow arrows | SpellcastingUiController + generic retained scrollbar/list |
| 2 | Status Use/Assess commands | focused status-bar controller binding to the existing action router |
| 3 | Assessment information panel | new retained panel controller mounted by the canonical main-panel host |
| 4 | Equipped-child world picking | pure world-query/picking policy plus presentation anchor |
| 5 | Vendor browse lifecycle | vendor session/controller plus authored panel |
| 6 | Vendor transactions | server-authoritative buy/sell command and reconciliation owner |
Each slice begins with named-retail research, produces pseudocode and conformance tests, updates the divergence register if required, and lands as a separate bisectable commit. A visual gate follows each UI-bearing slice.
Slice 1 now imports both 23-pixel arrow buttons, their rollover/pressed media, and HideDisabled from the real combat fixture; places their artwork by the authored leading/trailing positions; shares the list's single pixel-scroll model; advances one 32-pixel cell per press; and exposes only actively selected spells. Passive object/endowment refresh preserves a manual offset. The mixed 610/800-pixel DAT anchor chain is solved to a fixed 747-pixel combat root, producing exactly 18 visible 32-pixel favorite cells (nine numbered plus nine unnumbered) without consuming the overflow. The initial 57-test/full-suite gate passed; the corrective 104-test focus set, 3,472 App tests / 3 skips, Release solution build, and 7,845 complete-solution tests / 5 skips pass. The connected gate is pending after user feedback on arrow sides, rollover, width, and offset persistence.
Slice 1 — spell-bar overflow arrows
Retail oracle
The authored Magic combat layout contains, inside every favorite-tab group:
- horizontal scrollbar
0x100000B5, 685×36 at the 800-pixel design width; - decrement button
0x10000071, 23×36; - increment button
0x10000072, 23×36; - item list
0x100000B6, inset by 23 pixels on both sides and 32 pixels high.
The list references the scrollbar through UIElement_Scrollable property
0x71. The scrollbar references increment/decrement buttons through
properties 0x77/0x78, and property 0x79 enables HideDisabled. There is no
track or thumb in this specific control: the two authored arrows are the whole
visible scrollbar.
Named retail references and executable pseudocode are recorded in
../research/2026-07-23-retail-spellbar-overflow-pseudocode.md.
Implementation plan
- Generalize
DatWidgetFactory.BuildScrollbarso horizontal and vertical scrollbars both import the referenced decrement/increment children, including their authored positions, dimensions, Normal/rollover/pressed media, and HideDisabled property. - Generalize
UiScrollbarto use distinct authored decrement/increment extents for rendering, hit-testing, track geometry, and dragging. Preserve the existing 16-pixel default for layouts whose button children are absent. - Reproduce retail disabled presentation: a model without overflow rejects pointer input; when HideDisabled is authored, the scrollbar also draws nothing and does not claim hit tests.
- In
SpellcastingUiController, bind each group's scrollbar to itsUiItemList.Scroll, enable horizontal scrolling, and retain one independent pixel offset per favorite tab. - Match
SpellCastSubMenu::SetSelected: selecting a spell through keyboard, shortcut, or code scrolls that item into view; passive state refresh does not re-expose it. - Carry the combat root's mixed-parent raw-edge policies through the complete imported tree and solve for the retail 18-cell favorite viewport; keep that HUD capacity fixed across desktop resizes.
- Pin the importer, arrow hit extents, 32-pixel step, no-overflow behavior, controller binding, and selection exposure with focused App tests.
- Run the App Release suite, solution Release build, and complete Release suite. Then update the roadmap/memory and request the connected visual gate: place more favorites than fit, scroll both directions, change tabs, and verify arrows disappear on a non-overflowing tab.
Invariants
- DAT supplies the controls and their artwork; no new spell-bar texture or overlay is invented.
- The scrollbar and list share one
UiScrollable; there is no second offset. - One arrow press moves one 32-pixel favorite cell, matching
UIElement_ListBox::InqScrollDelta. - Hidden disabled arrows cannot intercept combat-page dragging or clicks.
- Existing stack, combat-power, chat, inventory, spellbook, and external container scrollbars retain their current behavior.
- No substantial feature body enters
GameWindow.