Render assessed creatures through the shared private viewport with retail heading, bounding-box camera, and light. Build the exact authored nine-row stat list and resolve creature names from the retail EnumMapper while keeping remaining font/sequencer adaptations explicit. Co-authored-by: Codex <codex@openai.com>
16 KiB
World interaction completion — pre-M4 program
Status: Slice 1 user-accepted 2026-07-23. Slice 2 Use-hand selection,
zero-useability, carried direct-use, AutoWear correction, and the requested
shared item-cooldown follow-up passed their connected gates. Slice 3's first
connected gate exposed an incorrect IdentifyResponse flag table, a non-retail
shared-panel mount, and its missing inscription transaction. All three are
corrected and live-confirmed. The creature-page follow-up now has retail's
ordered stat rows and animated private preview; its visual gate is 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 independent movable/resizable retail floaty examination window.
- 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 | retained controller in an independent floaty examination window |
| 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 corrected 18-cell bar and both overflow directions passed the connected gate.
Slice 2 now drives the toolbar hand from canonical SelectionState changes and
live ClientObjectTable updates. The pure Core predicate ports
gmToolbarUI::HandleSelectionChanged: combat-use items, armor/clothing/jewelry,
and ItemUses values without USEABLE_NO remain active. Clicking still enters
the existing ItemInteractionController command path, so weapons use the
server-confirmed AutoWield transaction and targeted tools enter the existing
use-on-target cursor. Empty selection and explicitly unusable spell components
are ghosted and ignore clicks. Empty-selection ghosting is the user's explicit
choice over retail's generic TARGET_MODE_USE entry and is registered as
AP-122. The 14-test Core interaction focus, 49-test toolbar focus, Release
solution build, 3,474 App tests / 3 skips, and 7,848 complete-solution tests /
5 skips pass.
The connected selection-state gate passed. Its follow-up exposed three deeper
shared-policy/delivery defects, now corrected from named retail plus the
matching binary. ItemUses::IsUseable @ 0x004FCCC0 tests only USEABLE_NO;
reset/absent value zero is usable. ItemHolder::UseObject @ 0x00588A80 sends a
carried direct-use item immediately; acdream had incorrectly routed that
packet through a world approach lookup, where Blackmoor's Favor has no spatial
entity and was silently cancelled. Owned Use now bypasses that query while
world-object Use retains the registered AD-27 approach seam. AutoWear applies
CPlayerSystem::AutoWearIsLegal @ 0x0055EF40 through the same double-click and
toolbar-hand path, resolves the overlapping worn object from the
retail-ordered equipment projection, and emits the exact system line
You must remove your <item> to wear that. Research:
../research/2026-07-23-retail-item-use-and-autowear-pseudocode.md.
The focused 25-test Core and 85-test App sets pass, as do the warning-free
Release solution build, 3,476 App tests / 3 skips, and 7,857 complete-solution
tests / 5 skips. The carried-use delivery correction adds an end-to-end App
pin from Favor activation through wire dispatch and authoritative UseDone busy
release. The Release build retains the 17 tracked test-project warnings;
3,477 App tests / 3 skips and 7,858 complete-solution tests / 5 skips pass.
The user confirmed Blackmoor's Favor now activates correctly.
Before Assess, the user requested the adjacent retail item-cooldown
presentation. PublicWeenieDesc now preserves the optional shared cooldown id
and duration, assessed property updates reach the same object fields, and
CEnchantmentRegistry::OnCooldown @ 0x005943C0 plus
UIElement_UIItem::UpdateCooldownDisplay @ 0x004E1E20 are ported through the
canonical Core registry and one pure display projection. Every retained item
list shares one controller and the exact
ten DAT-authored radial sprites 0x060067CF..0x060067D8; items with the same
group display the same server-authored cooldown. Research:
../research/2026-07-23-retail-item-cooldown-pseudocode.md.
The focused parser/Core/UI/production-DAT tests, warning-free Release solution
build, 3,482 App tests / 3 skips, and 7,875 complete-solution tests / 5 skips
pass. AP-123 records only the retained toolkit's procedural-child adaptation;
the visible assets, ordering, timing, and shared-group behavior are exact.
The user accepted the live cooldown presentation 2026-07-23.
Slice 3 preserves the existing toolbar/keyboard Assess command and ports the
retail response owner around it. One shared UI-busy reference covers the
latest pending GUID, stale replies are rejected, the accepted reply becomes
the current appraisal, and combat-time creature/player refreshes occur every
0.75 seconds only while the examination window is visible. Complete
IdentifyObjectResponse parsing now uses ACE/retail's exact flag values and
positional order, includes the three-word HookProfile, and rejects truncated
gated payloads rather than continuing from a corrupt cursor. The first live
monster gate found that 0x0100 had been mislabeled WeaponProfile; the parser
dropped every creature response before response acceptance, leaving the one
busy reference held. A literal ACE 0x0100 creature fixture now protects that
packet-to-controller path.
LayoutDesc 0x2100006B, root 0x100005F2, supplies the complete 310 x 400
floaty chrome, title, item/creature/character subviews, close control, and
authored scrollbars. gmFloatyExaminationUI is an independent top-level
window, so Inventory/Skills/Spellbook no longer replace it or inherit its
geometry. The imported multiline inscription field now ports
ItemExamineUI's public/hook inscribability, inventory ownership and
same-scribe permission rules, placeholder/signature presentation, exact
failure notices, focus commit behavior, and CP-1252 SetInscription (0x00BF)
transaction. Basic item and player reports are live. The creature page now
resolves its type through retail EnumMapper 0x2200000E, preserves the
authored Character/Level header, creates the exact nine stat rows from
template 0x10000166, and renders a fixed-heading animated clone through a
private viewport using retail's bounding-box camera and distant light.
Item-object preview, specialized detail regions, exact appraisal font-state
selection, and selection-follow remain the narrowed AP-110 residual. Research:
../research/2026-07-23-retail-appraisal-ui-pseudocode.md.
The focused parser/router/request/controller/fixture tests pass, as do the
Release solution build with 17 pre-existing tracked test warnings, 3,496 App
tests / 3 skips, and 7,913 complete-solution tests / 5 skips.
The creature presentation follow-up adds real-DAT row-template and EnumMapper fixtures plus pure conformance coverage for row order/formatting, enchantment semantics, failed assessments, stable clone identity, live animated mesh updates, hydrated mesh bounds, and retail camera fitting. The warning-free App code, Release solution build, 3,506 App tests / 3 skips, and 7,923 complete-solution tests / 5 skips pass. The connected visual result remains the closeout gate.
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.
Slice 2 — status Use/Assess commands
Use-hand implementation
ItemInteractionPolicy.IsToolbarUseEnabledis the pure named-retail selection predicate.ItemInteractionController.IsToolbarUseEnabledadapts the selected live object without triggering a request or consuming the use throttle.ToolbarControllersubscribes to canonicalSelectionState.Changedand selected-object add/update/remove notices, then sets the imported button's normal or ghosted state throughUiButton.Enabled.- Enabled clicks retain the one existing activation path:
equipment enters
AutoWieldController, ordinary use enters the normal Use request owner, and targeted items enterUseItemOnTarget, which already owns the retail target cursor.
Slice 2 closeout
- The shared item-cooldown visual gate passed.
gmToolbarUI::ListenToElementMessage @ 0x004BEE90confirms the existing magnifying-glass path was already correct: assess the selected GUID immediately, otherwise enter one-shot Examine target mode.- Slice 3 owns the response lifetime and retained examination presentation; Slice 2 adds no duplicate command path.
Slice 3 — assessment information panel
Implemented ownership
AppraiseInfoParserowns the complete positional response payload, including HookProfile and strict truncation failure.ItemInteractionControllerowns the pending/current GUID pair and the balanced shared busy reference.AppraisalUiControllerowns response acceptance, item/creature/character subview selection, report projection, scroll preservation, first-response visibility, and visible-combat refresh.RetailUiRuntimeimports and registers retail'sgmFloatyExaminationUIas its own top-level window. It deliberately does not enterRetailPanelUiController; Inventory, Skills, Spellbook, and effects keep their shared main-panel geometry while Examination coexists.- Network workers deliver immutable parsed data through the existing session router; retained state changes remain on the update thread.
AppraisalUiControllerowns inscription presentation and optimistic field state;WorldSessionowns the exact0x00BFGameAction send. Authoritative inventory/appraisal data remains the source on the next response.
Connected gate
- Select an item and click the magnifying glass (or press Assess): a separate floaty window should show its name, available properties, descriptions, inscription/signature, retail chrome, and working scrollbars.
- Assess a monster, NPC, and player: the correct creature/character page should appear and the busy cursor should clear.
- On a monster, verify the animated creature is centered behind the exact Strength/Endurance/Coordination/Quickness/Focus/Self/Health/Stamina/Mana order, with its creature type and level in the authored header. Assess differently sized monsters to verify the retail bounding-box fit.
- In combat, leave a creature assessment open long enough to observe a health refresh; closing the examination window must stop refreshes.
- Keep Examination open while opening/moving Inventory or Skills and confirm both windows coexist with independent rectangles.
- Assess an owned inscribable weapon. Edit and clear its inscription by clicking elsewhere, then reassess it. An item authored by another player is read-only and reports the exact retail permission line when clicked.