feat(ui): port retail selected-stack quantity
Bind the authored stack count entry and horizontal slider to one Core split-quantity owner, preserve retail count-first naming and exact 1000-step rounding, refresh on stack changes, and consume the selected amount during merges. Conformance covers the production DAT fixture and retained pointer/focus paths. Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
parent
dc1649c493
commit
a20e5c68c7
19 changed files with 595 additions and 51 deletions
|
|
@ -2050,7 +2050,7 @@ See divergence register **AP-59**.
|
|||
|
||||
## #141 — Toolbar interactivity — selected-object display
|
||||
|
||||
**Status:** IN PROGRESS (D.5.3a health + name + flash — DONE & visually confirmed 2026-06-20; mana + stack slider still deferred). Renumbered from #140 on the 2026-06-20 main merge — A7 Fix D held #140 on main; this branch's commits/spec still reference #140.
|
||||
**Status:** IN PROGRESS (health/name/flash DONE and visually confirmed 2026-06-20; formatted stack count + entry/slider implemented 2026-07-11, visual gate pending; mana still deferred). Renumbered from #140 on the 2026-06-20 main merge — A7 Fix D held #140 on main; this branch's commits/spec still reference #140.
|
||||
**Severity:** MEDIUM
|
||||
**Filed:** 2026-06-17
|
||||
**Component:** ui — D.5 toolbar / selection
|
||||
|
|
@ -2058,8 +2058,9 @@ See divergence register **AP-59**.
|
|||
**Description:** The action bar (D.5.1) is the retail "selected object" display. Wire the B.4 WorldPicker/selection state to the toolbar's currently-hidden elements: the two meters 0x100001A1 (selected-object Health) / 0x100001A2 (selected-object Mana) + the stack slider 0x100001A4 + the object-name line, so the bar shows what the player has selected in the world. Click-to-use + the peace/war stance indicator already shipped in D.5.1. Promote to roadmap D.5.3 (already listed there).
|
||||
|
||||
**Root cause / status:** The selection-state wire was deferred out of D.5.1 scope; the meter/slider elements are present in LayoutDesc 0x21000016 but hidden (no backing data). D.5.3 is the planned port.
|
||||
- **D.5.3a (2026-06-18):** the Health meter (0x100001A1) + the object-name line (0x1000019F) + the overlay state (0x100001A0) are wired via `SelectedObjectController` (port of `gmToolbarUI::HandleSelectionChanged`); `SelectionChanged` event on `GameWindow`; `QueryHealth (0x01BF)` sent on select. Spec/plan: `docs/superpowers/specs|plans/2026-06-18-d53a-*`. **Still deferred:** the Mana meter (0x100001A2 — owned-item-only; no remote-target mana path yet) and the stack entry/slider (0x100001A3/A4 — stack-split UI). Divergence row AP-46.
|
||||
- **D.5.3a visual gate PASSED (2026-06-20):** name top-aligned in the bar sprite's black band, friendly NPCs/Doors name-only, players/monsters get the bar (gated on PWD BF_ATTACKABLE/BF_PLAYER), bar appears on assess/damage (UpdateHealth-driven, AP-47 retired), brief green selection flash. Fixed during the gate: the two magenta end-lines (UiMeter.DrawHBar resolved slice id 0 → 1x1 magenta placeholder → 1px caps), the stack-entry black box (hid 0x100001A3), and the flash being eaten by a framebuffer-dump diagnostic. Commits `8f627cc` (fixes), `0796585` (CLI apparatus). **Remaining for #141:** Mana meter (0x100001A2) + stack entry/slider (0x100001A3/A4).
|
||||
- **D.5.3a (2026-06-18):** the Health meter (0x100001A1) + the object-name line (0x1000019F) + the overlay state (0x100001A0) are wired via `SelectedObjectController` (port of `gmToolbarUI::HandleSelectionChanged`); `SelectionChanged` event on `GameWindow`; `QueryHealth (0x01BF)` sent on select. Spec/plan: `docs/superpowers/specs|plans/2026-06-18-d53a-*`. **Still deferred:** the Mana meter (0x100001A2 — owned-item-only; no remote-target mana path yet). Divergence row AP-46.
|
||||
- **D.5.3a visual gate PASSED (2026-06-20):** name top-aligned in the bar sprite's black band, friendly NPCs/Doors name-only, players/monsters get the bar (gated on PWD BF_ATTACKABLE/BF_PLAYER), bar appears on assess/damage (UpdateHealth-driven, AP-47 retired), brief green selection flash. Fixed during the gate: the two magenta end-lines (UiMeter.DrawHBar resolved slice id 0 → 1x1 magenta placeholder → 1px caps), the stack-entry black box (hid 0x100001A3), and the flash being eaten by a framebuffer-dump diagnostic. Commits `8f627cc` (fixes), `0796585` (CLI apparatus). **Remaining for #141:** Mana meter (0x100001A2).
|
||||
- **D.5.3b implementation (2026-07-11):** stacked selection formats the retail `"%d %hs"` count/name, reveals authored entry `0x100001A3` and horizontal DAT slider `0x100001A4`, initializes to the full stack, clamps entry edits, and uses the exact 1000-step slider conversion. One Core `StackSplitQuantityState` feeds both controls and the selected-source merge amount. Live visual gate pending.
|
||||
|
||||
**Files:** `src/AcDream.App/UI/Layout/ToolbarController.cs` + the selection/WorldPicker state (see `claude-memory/project_interaction_pipeline.md`).
|
||||
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ AP-94..AP-110 for the confirmed retail-UI completion gaps.
|
|||
| ~~AP-97~~ | **RETIRED 2026-07-10 (Wave 1 retained-widget foundation)** — the prior generic Device-timer premise was a decomp misread. Named retail polls the hovered element's tooltip deadline, then broadcasts global UI time message `3`; it does not expose the assumed arbitrary timer queue. `UiRoot.Tick` now preserves that order and subtree removal clears input/time ownership before another pulse. | `src/AcDream.App/UI/UiRoot.cs`; `IUiGlobalTimeListener.cs` | — | — | `UIElementManager::UseTime` and hover/focus paths, pinned in `docs/research/2026-07-10-retained-widget-foundations-pseudocode.md` |
|
||||
| ~~AP-98~~ | **RETIRED 2026-07-10 (Wave 2.3)** — typed handles/manager own lifecycle; every production/Studio window uses `RetailWindowFrame`; schema-v2 `UiWindowLayout` persists outer bounds, visibility, toolbar collapse, and chat maximize by character/resolution with legacy-radar migration, nearest-resolution fallback, clamping, and a pre-login `default` write guard. Chat maximize uses DAT 100–360 limits and preserves its lower edge when growing upward. | `src/AcDream.App/UI/RetailWindowManager.cs`; `RetailWindowLayoutPersistence.cs`; `RetailWindowHandle.cs`; `Layout/RetailWindowFrame.cs`; `ChatWindowController.cs`; `SettingsStore.cs` | — | — | `gmMainChatUI::HandleMaximizeButton @ 0x004CCE50`; retail `saveui/loadui` behavior |
|
||||
| ~~AP-99~~ | **RETIRED 2026-07-11 (Wave 3.2)** — Core `ItemInteractionPolicy` ports the complete ordered `DetermineUseResult`/`UseObject`/`AttemptPlaceIn3D` matrix; PWD flags and `CombatUse` survive CreateObject; component-pack membership comes from portal.dat; App owns throttle, UseDone-balanced busy state, target mode, wire/optimistic dispatch, and typed confirmation/auxiliary seams. The two corrupt decompiler operands were pinned from matching x86 as `BF_REQUIRES_PACKSLOT` and `BF_VENDOR`. | `src/AcDream.Core/Items/ItemInteractionPolicy.cs`; `src/AcDream.App/UI/ItemInteractionController.cs` | — | — | `ItemHolder::DetermineUseResult @ 0x00588460`; `UseObject @ 0x00588A80`; `AttemptPlaceIn3D @ 0x00588600` |
|
||||
| AP-101 | Most toolbar panel/Use/Examine controls are not fully dispatched; selected-object mana and stack entry/slider are absent | `src/AcDream.App/UI/Layout/ToolbarController.cs`; `GameWindow.OnInputAction` | Item click/use, health/name, quick-slot use/select/create actions, some panel toggles, and all four combat indicator buttons work; combat clicks and the bound key share `ToggleLiveCombatMode` | Remaining bound retail buttons do nothing and item/stack selections show incomplete state | `gmToolbarUI @ 0x004BD0C0..0x004BF380`; LayoutDesc `0x21000016` |
|
||||
| AP-101 | Most toolbar panel/Use/Examine controls are not fully dispatched and selected-object mana is absent | `src/AcDream.App/UI/Layout/ToolbarController.cs`; `GameWindow.OnInputAction` | Item click/use, health/name, exact stack name/entry/slider, shared split quantity, quick-slot actions, some panel toggles, and all four combat indicators work | Remaining bound retail buttons do nothing and mana-bearing item selections show incomplete state | `gmToolbarUI @ 0x004BD0C0..0x004BF380`; LayoutDesc `0x21000016` |
|
||||
| AP-104 | Vitals detail element `0x100004A9` and root `HideDetail`/`ShowDetail` transitions are not wired | `src/AcDream.App/UI/Layout/VitalsController.cs` | Compact vitals values/bars are correct | Detail click does nothing and expanded retail state is unreachable | `gmVitalsUI::ListenToElementMessage @ 0x004BFC00`; `PostInit @ 0x004BFCE0` |
|
||||
| AP-105 | **PARTIAL 2026-07-10 (Wave 2.2)** — inherited scrollbar media/roles now come from DAT (decrement/top `0x06004C69`, increment/bottom `0x06004C6C`). Retained chat still lacks complete tab/filter/unread, social availability, squelch, and focus-opacity behavior; a second ChatVM still loses FPS/position providers. | `src/AcDream.App/UI/Layout/DatWidgetFactory.cs`; `ChatWindowController.cs`; chat mount in `GameWindow.cs` | Shared log/send path, wrapping, scrollbar roles, and outer maximize geometry work; Wave 5 consolidates remaining chat state | Commands degrade, tabs are no-ops, moderation/channel state is wrong, and focus visuals diverge | `gmMainChatUI @ 0x004CCCC0..0x004CE2A0`; `UIElement_Scrollbar::OnSetAttribute @ 0x004714D0`; `ChatInterface` methods |
|
||||
| AP-106 | The retained UI has no external/ground-container window lifecycle, while the original owned-side-bag `NoLongerViewingContents` premise was incorrect (#196) | `src/AcDream.App/UI`; window runtime; absent external-container controller | Owned inventory navigation remains usable and must not gain an unproven `0x0195` send; Wave 2/6 adds lifecycle ownership and the separate external surface | External container replacement/close cannot notify the server exactly once; adding the packet to owned bag close would itself diverge from the named retail call graph | `ClientUISystem.groundObject`; `CM_Inventory::Event_NoLongerViewingContents @ 0x006ABC50`; `docs/research/2026-07-10-retail-panel-behavior-pseudocode.md` |
|
||||
|
|
|
|||
|
|
@ -490,10 +490,11 @@ behavior. Estimated 17–26 days focused work, 3–5 weeks calendar.
|
|||
- **✓ SHIPPED — Wave 4.3a shortcut-alias boundary.** Drag feedback now preserves retail's neutral/accept/reject distinction. Inventory and paperdoll apply the `(DropItemFlags & 0xE) == 0` physical-item gate, so a toolbar alias can reorder within the toolbar but can never move, unwield, wield, or drop the object it references. Live equipped-helmet gate passed 2026-07-11: inventory drop removed only the shortcut.
|
||||
- **✓ SHIPPED — Wave 4.3b source-aware toolbar transactions.** Pure Core `ShortcutDropPlanner` ports `gmToolbarUI::HandleDropRelease @ 0x004BE7C0`: fresh inventory drops displace cyclically right (with wrap), shortcut aliases restore to their vacated source, duplicate objects are removed before placement, full bars intentionally lose the displaced entry when retail finds no empty slot, and every transaction is planned before local mutation then emitted in exact Remove/Add order. Full-stack rekey planning preserves the raw spell word. AP-102 retired; 4,646 automated tests pass; live inventory-to-occupied displacement and toolbar reorder gate passed 2026-07-11.
|
||||
- **✓ SHIPPED — Wave 4.3c remaining drop branches + stack merge.** `UiButton` now has a reusable retained item-drop-target seam; gmToolbarUI's inventory/backpack button accepts only fresh physical items, draws the exact authored green-arrow overlay `0x060011F7`, and sends them to the player container while shortcut aliases remain neutral. Pure Core `StackMergePlanner` ports `IsMergeAttemptLegal @ 0x00586F30` and `AttemptMerge @ 0x005878F0`; inventory drops try legal same-WCID stack merges before normal insertion, clamp `0x0054` amount to destination capacity, immediately broadcast retail's misleadingly named `FullMergingItem` notice to rekey the toolbar, and select the destination. Existing destination shortcuts are removed before rekey. Warning-free Release build and 4,660 tests pass; live stack-merge gate passed 2026-07-11. Backpack-button drop gate remains pending.
|
||||
- **✓ IMPLEMENTED — Wave 4.4a selected-stack controls.** `SelectedObjectController` now formats retail's count-first stack name, reveals the authored numeric entry and horizontal DAT slider, initializes both to the full stack, refreshes them on selected-object stack changes, and shares one Core split quantity with inventory merge. Exact cdb-pinned 1000-step slider rounding, entry clamping, real-DAT fixture media, and pointer drag have conformance tests. Warning-free App Release build and 4,683 tests pass; live visual gate pending 2026-07-11. Selected-item mana and remaining toolbar buttons stay under AP-101.
|
||||
- **✓ SHIPPED — Character window** (`LayoutDesc 0x2100002E`, `CharacterStatController`, 2026-06-26, same branch). **Visually user-confirmed 2026-06-26 — Attributes tab reads as retail.** Three tabs, header (name/heritage/PK), large-gold level number (dat font, `largeDatFont` 18px), "Total Experience (XP):" + "XP for next level:" captions, 9-row attribute list (icons + right-aligned values + Health/Stamina/Mana vitals), click-to-select (top/bottom selection bars + footer State-B "{Attr}: {value}" / "Experience To Raise: Infinity!" + affordability-gated raise triangles), centered footer. User noted "still needs some polish for later" — deferred to Issue #158.
|
||||
- **✓ SHIPPED — D.5.4 — Client object/item data model (foundation).** Shipped 2026-06-18 (`b506f53`..`a33e897`, 11 commits). Renamed `ItemRepository`→`ClientObjectTable` / `ItemInstance`→`ClientObject`; broadened the table to hold EVERY server object (retail `weenie_object_table` shape). `CreateObject` is now the canonical merge-upsert (`ClientObjectTable.Ingest`, retail `SetWeenieDesc` semantics) via a new Core.Net `ObjectTableWiring` (off GameWindow); `DeleteObject` evicts; `PlayerDescription` is a membership manifest (`RecordMembership`); live container-membership index (`GetContents`, retail `object_inventory_table`). `_liveEntityInfoByGuid` retired (selection/describe resolve from the one table). Root fix: the old enrich-existing-only `EnrichItem` dropped `CreateObject`s for items with no `PlayerDescription` stub — live-Coldeve 4/6 hotbar slots blank; items are now created, not dropped. **Crux resolved:** retail is TWO tables (`object_table` + `weenie_object_table`), NOT one — acdream's `WorldEntity` (3D system) + `ClientObjectTable` (data/UI) split was already architecturally faithful; the fix was the ingestion path, not a table unification. 2671 tests green.
|
||||
- **Roadmap correction (2026-07-10):** the completion order is now the architecture-first campaign in `docs/superpowers/plans/2026-07-10-retail-ui-fidelity-completion.md`. Retail `gmToolbarUI` is object-only: preserve `ShortCutData.index_`, `objectID_`, and `spellID_`, but do not invent spell glyphs on this bar. `PlayerModule::favorite_spells_[8]` feeds separate spell bars.
|
||||
- **☐ D.5.3 — Toolbar selected-object display (issue #141).** Wire unified selection to the hidden mana meter (`0x100001A2`), stack entry (`0x100001A3`), stack slider (`0x100001A4`), and complete health/name behavior. Exact raw `ShortCutData` preservation is already shipped in Wave 4.2; the eight `favorite_spells_` lists belong to the separate spellbook/spell-bar phase. (Click-to-use + peace/war + health/name already landed.)
|
||||
- **☐ D.5.3 — Toolbar selected-object display (issue #141).** Wire unified selection to the hidden mana meter (`0x100001A2`) and complete residual health policy. Stack entry (`0x100001A3`), stack slider (`0x100001A4`), formatted count/name, shared split quantity, click-to-use, peace/war, and health/name are implemented. Exact raw `ShortCutData` preservation is already shipped in Wave 4.2; the eight `favorite_spells_` lists belong to the separate spellbook/spell-bar phase.
|
||||
- **☐ D.5.5+ — Core panels.** Inventory (`gmInventoryUI`/`gmBackpackUI`), equipment/paperdoll (`gmPaperDollUI`/`gm3DItemsUI` + the `UiViewport` 3D doll), vendor, trade, spellbook. Research drop done (`docs/research/2026-06-16-*`). Depends on **D.5.4** (data model) + the item-slot/list/icon spine (D.5.1/D.5.2) + the **window manager** (Plan 2: open/close/z-order/persist + faithful grip/dragbar drag-resize) + the drag-drop spine wired (`UiRoot` has the chain; the per-cell accept/drop hooks are still stubs in `UiField`). Also deferred from D.5.1: drag/reorder + the `AddShortcut`/`RemoveShortcut` mutate wire.
|
||||
- **D.6 — HUD.** **Radar/compass IMPLEMENTED 2026-07-10; live-world visual gate pending.** It is the retained retail `gmRadarUI` (`LayoutDesc 0x21000074`): a 120×140 circular radar (`0x06004CC1`) with N/E/S/W token sprites orbiting the face, a fixed bright-green player marker, and the coordinate footer (`0x06004CC0`). Projection is `radarPixelRadius / radarRange` with 75 m outdoor / 25 m indoor ranges — there is no 1.18 factor or scrolling compass strip. It lives in `AcDream.App/UI` beside the other imported retail panels. Remaining D.6: target name plate, damage floaters, and other world-space HUD elements through the raw `TextRenderer` path. See slice 06 §A.2, `docs/research/2026-07-10-retail-radar-pseudocode.md`, and the named `gmRadarUI` decomp.
|
||||
- **✓ SHIPPED — D.7 — Cursor manager (user-confirmed 2026-07-11).** All reachable `ClientUISystem::UpdateCursorState @ 0x00564630` branches resolve through production DAT EnumIDMap table 6, with event-ordered global-default versus captured/hovered `MediaDescCursor` layering from `UIElementManager::CheckCursor @ 0x0045ABF0`. OS fallback remains only AP-72 and emits a visible diagnostic. The live gate covered world/object, combat, targeted-use, text, move/resize, and drag contexts; combat-indicator mouse clicks and the quick key share the same toggle command.
|
||||
|
|
|
|||
|
|
@ -463,10 +463,10 @@ AttemptMerge(sourceId, targetId, quiet): // 0x005878F0
|
|||
return true
|
||||
```
|
||||
|
||||
acdream's selected-object stack entry/slider is still absent under AP-101, so the
|
||||
current inventory merge path requests the whole source stack and lets the same
|
||||
retail capacity clamp limit the transfer. Once the shared split-quantity owner
|
||||
lands, it supplies `requested` without changing legality or wire ordering.
|
||||
acdream now has one Core-owned split-quantity state shared by the selected-object
|
||||
entry/slider and inventory merge. A selected source supplies that quantity to
|
||||
`AttemptMerge`; an unselected source retains retail's full-source default. Legality,
|
||||
capacity clamping, and wire ordering are unchanged.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -507,7 +507,7 @@ HandleSelectionChanged(): // 0x004BF380
|
|||
if object missing: return
|
||||
|
||||
set selected name:
|
||||
normal object: name, or formatted name + count when stacked
|
||||
normal object: name, or `"%d %hs"` (count then name) when stacked
|
||||
owned coinstack: formatted coin total/name path
|
||||
|
||||
splitSize = 1
|
||||
|
|
@ -567,13 +567,22 @@ RecvNotice_UpdateItemMana(id, fraction, valid): // 0x004BD0C0
|
|||
- On entry deactivation, parse unsigned text, clamp to `1..maxSplitSize`, rewrite
|
||||
the text if clamped, update `GenItemHolder::splitSize`, update slider attribute
|
||||
`0x86 = splitSize/maxSplitSize`, and broadcast the stack-slider notice.
|
||||
- Slider message `0xA` maps its normalized value to an integer in
|
||||
`1..maxSplitSize`, stores it, rewrites the entry, and broadcasts the notice.
|
||||
- `UIElement_Scrollbar::SetScrollbarPosition @ 0x00470EC0` clamps the normalized
|
||||
position to `[0,1]`, multiplies by `1000.0f`, truncates through `_ftol2`, and
|
||||
broadcasts that integer as message `0xA` parameter 1.
|
||||
- `gmToolbarUI::ListenToElementMessage @ 0x004BEFE0..0x004BF041` converts the
|
||||
message exactly as follows, stores it, rewrites the entry, and broadcasts the
|
||||
stack-slider notice:
|
||||
|
||||
**Unresolved:** Binary Ninja lost the exact floating expression immediately before
|
||||
the slider's `1 - _ftol2()` conversion at `0x004BF02D`. The clamp, endpoints, and
|
||||
text update are exact, but the intermediate rounding direction must be recovered
|
||||
from Ghidra/disassembly before writing conformance vectors.
|
||||
```text
|
||||
positionMillis = truncate(clamp01(sliderRatio) * 1000)
|
||||
splitSize = clamp(1 + floor(positionMillis * maxSplitSize / 1000),
|
||||
1, maxSplitSize)
|
||||
```
|
||||
|
||||
The apparently odd extra one is verbatim retail behavior. Static cdb disassembly
|
||||
of the matching v11.4186 binary also pins the stack-name format string at
|
||||
`0x007B4738` to `"%d %hs"` and the numeric-entry format at `0x007A0184` to `"%d"`.
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -505,12 +505,12 @@ overlay, while aliases stay neutral. Inventory now tries the pure named-retail
|
|||
stack-merge legality/amount planner before ordinary insertion, sends `0x0054`,
|
||||
broadcasts `FullMergingItem` immediately from the attempt owner, rekeys the toolbar
|
||||
with existing-destination removal, and selects the target. The notice is not a
|
||||
server confirmation despite its name. AP-101 still covers the absent shared split
|
||||
entry/slider; until it lands, merge requests use the whole source stack before the
|
||||
retail destination-capacity clamp. Release build is warning-free and 4,660 tests
|
||||
pass. The compatible-stack live gate passed 2026-07-11; it exposed the expected
|
||||
Wave 4.4/AP-101 gap that the selected strip still displays one instead of the
|
||||
stack count and has no split slider. The inventory-button live gate remains pending.
|
||||
server confirmation despite its name. Release build is warning-free and 4,660 tests
|
||||
pass. The compatible-stack live gate passed 2026-07-11 and exposed the expected
|
||||
Wave 4.4/AP-101 selected-stack gap. Wave 4.4a now implements that gap: exact count-first
|
||||
name formatting, authored entry/slider media, one Core split-quantity owner, live
|
||||
stack-size refresh, and selected-source merge amount. The inventory-button and
|
||||
selected-stack visual gates remain pending.
|
||||
|
||||
### 4.4 Finish toolbar controls
|
||||
|
||||
|
|
@ -518,12 +518,24 @@ stack count and has no split slider. The inventory-button live gate remains pend
|
|||
Use, and Examine actions; dispatch panel buttons through the window registry,
|
||||
ghosting unavailable panels rather than constructing placeholders.
|
||||
- [ ] Make open/closed states event-driven from `RetailWindowManager`.
|
||||
- [ ] Complete selected-object item mana, formatted stack count, stack entry and
|
||||
split slider; port `RecvNotice_UpdateItemMana`, `RecvNotice_SplitStack`, and
|
||||
`HandleSelectionChanged` precedence.
|
||||
- [ ] Complete selected-object item mana and port `RecvNotice_UpdateItemMana`.
|
||||
- [x] Complete formatted stack count, stack entry and split slider, the applicable
|
||||
`RecvNotice_SplitStack` activation behavior, and `HandleSelectionChanged` stack
|
||||
precedence. Vendor-specific initial quantity remains naturally dormant until a
|
||||
vendor panel owns an active vendor id.
|
||||
- [ ] Replace the PWD-only health gate with the exact attackable/player/pet policy.
|
||||
- [ ] Add item-mana query/cancel state, health query cancellation, and one shared
|
||||
split-quantity owner for the entry, slider, and item drag payload.
|
||||
- [ ] Add item-mana query/cancel state and health query cancellation.
|
||||
- [x] Add one shared split-quantity owner for the entry, slider, and selected-source
|
||||
item-holder merge payload.
|
||||
|
||||
**Wave 4.4a implementation (2026-07-11):** static cdb against the matching retail
|
||||
binary pinned stack-name `"%d %hs"`, numeric entry `"%d"`, and the slider's exact
|
||||
1000-step truncation formula. `StackSplitQuantityState` is the single Core owner;
|
||||
`SelectedObjectController` binds authored elements `0x100001A3/A4`, and
|
||||
`InventoryController` consumes the value only when the dragged source is selected.
|
||||
The horizontal scrollbar remains the generic retained `UiScrollbar` in scalar mode,
|
||||
using the DAT track/thumb rather than panel-local drawing. The warning-free App Release
|
||||
build and 4,683-test suite are green; the live visual gate follows.
|
||||
|
||||
**Wave 4.1 implementation (2026-07-11):** bare `1..9` now use slots 0..8,
|
||||
Ctrl+`1..9` selects them, Alt+`5..9` uses slots 13..17, and `0` creates a
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue