fix(ui): finish retail stack selector polish

Keep the horizontal thumb at its raw pointer position so both endpoints are reachable, honor the stack entry's authored right alignment, and preserve PublicWeenieDesc plural names from CreateObject through the object table. Port retail's singular s/es fallback when no plural was sent.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-11 10:22:11 +02:00
parent a20e5c68c7
commit 6005c51c4d
22 changed files with 233 additions and 36 deletions

View file

@ -507,7 +507,8 @@ HandleSelectionChanged(): // 0x004BF380
if object missing: return
set selected name:
normal object: name, or `"%d %hs"` (count then name) when stacked
normal object: NAME_APPROPRIATE, or `"%d %hs"` (count then appropriate
name) when stacked
owned coinstack: formatted coin total/name path
splitSize = 1
@ -561,6 +562,16 @@ RecvNotice_UpdateItemMana(id, fraction, valid): // 0x004BD0C0
### 5.4 Stack editing
`ACCWeenieObject::GetObjectName(NAME_APPROPRIATE) @ 0x0058E6E0` selects
`PublicWeenieDesc._plural_name` whenever `_stackSize > 1`. If the optional plural
string is empty, retail copies the singular and appends `s`, or `es` when the
singular already ends in lowercase `s`. The CreateObject WeenieHeader carries the
explicit plural as flag `0x00000001`, before ItemsCapacity.
The stack entry's authored DAT horizontal justification is Right. Its number is
therefore right-aligned against the slider's left edge rather than drawn from the
entry's left edge.
- `RecvNotice_SplitStack(selectedId)` activates and selects all text only when the
selected object still has a stack size greater than one.
- On entry activation, select all text.
@ -583,6 +594,11 @@ splitSize = clamp(1 + floor(positionMillis * maxSplitSize / 1000),
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"`.
While the pointer is moving, the scrollbar retains its own normalized position and
the toolbar only rewrites the entry text. Selection refresh or entry deactivation
explicitly writes attribute `0x86 = splitSize/maxSplitSize`. Consequently a pointer
drag can remain at exact position `0` (quantity 1) or `1` (the maximum), rather than
being redrawn from the quantized quantity during the drag.
---