feat(ui): drive toolbar use state from selection

Port the retail selected-object availability predicate into Core and project it through the shared interaction owner. The imported hand now follows canonical selection/object notices, keeps weapon and targeted-tool activation on the existing wield/use cursor paths, and ghosts empty or explicitly unusable selections per the connected UX requirement.

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-23 08:07:47 +02:00
parent 0134122c28
commit 60387668d0
11 changed files with 269 additions and 16 deletions

View file

@ -1,6 +1,7 @@
# World interaction completion — pre-M4 program
**Status:** Slice 1 code-complete 2026-07-23; connected visual gate pending.
**Status:** Slice 1 user-accepted 2026-07-23. Slice 2 Use-hand state and command
path code-complete; connected visual gate pending before Assess continues.
**Milestone:** M4 prerequisite/preamble.
**Architecture:** retained gameplay UI over shared selection, object, and
interaction state. `GameWindow` remains a composition/callback shell.
@ -52,9 +53,21 @@ spells. Passive object/endowment refresh preserves a manual offset. The mixed
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.
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.
## Slice 1 — spell-bar overflow arrows
@ -115,3 +128,27 @@ Named retail references and executable pseudocode are recorded in
- 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
1. `ItemInteractionPolicy.IsToolbarUseEnabled` is the pure named-retail
selection predicate.
2. `ItemInteractionController.IsToolbarUseEnabled` adapts the selected live
object without triggering a request or consuming the use throttle.
3. `ToolbarController` subscribes to canonical `SelectionState.Changed` and
selected-object add/update/remove notices, then sets the imported button's
normal or ghosted state through `UiButton.Enabled`.
4. Enabled clicks retain the one existing activation path:
equipment enters `AutoWieldController`, ordinary use enters the normal Use
request owner, and targeted items enter `UseItemOnTarget`, which already
owns the retail target cursor.
### Remaining Slice 2 work
- Port the magnifying-glass Assess command state and activation.
- Run the connected Use-hand visual gate: no selection, spell component,
weapon, and health kit.
- Continue directly into the Assess information slice after the combined
status-control gate.