fix #212: preserve shortcut tint in physical combat

Port the retail m_bShortcutGhosted meaning instead of treating SetShortcutNum's boolean as peace versus war. Keep occupied shortcut numbers on the gold sheet in NonCombat, Melee, and Missile, reserve the gray sheet for Magic, and lock the four-mode matrix with conformance tests and corrected research.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-13 11:21:12 +02:00
parent ab98cda26b
commit 5090aa7217
9 changed files with 197 additions and 112 deletions

View file

@ -46,9 +46,39 @@ Copy this block when adding a new issue:
---
## #211 — Login-equipped missile weapon incorrectly requests melee combat
## #212 — Toolbar shortcut numbers turn gray in physical combat
**Status:** IN-PROGRESS — implementation complete 2026-07-13, pending user gate
**Severity:** LOW
**Component:** retained UI / toolbar
**Description:** Entering melee or missile combat changed the numbered overlay
on occupied toolbar shortcuts from the gold mesh to the gray mesh.
**Root cause:** The port interpreted `UIElement_UIItem::SetShortcutNum`'s Boolean
as peace versus war. Retail names the stored value `m_bShortcutGhosted`, and
`gmToolbarUI::RecvNotice_SetCombatMode` passes true only for Magic combat mode.
The false interpretation therefore ghosted every occupied shortcut in every
combat stance.
**Resolution:** Shortcut state and digit arrays now use retail's regular/ghosted
terminology. NonCombat, Melee, and Missile select property `0x10000042`; Magic
alone selects ghosted property `0x10000043`. Empty slots continue to use the
stance-independent `0x1000005E` array.
**Research:** `docs/research/2026-07-10-retail-toolbar-interaction-pseudocode.md`
§2.4; `UIElement_UIItem::SetShortcutNum @ 0x004E1590`;
`gmToolbarUI::RecvNotice_SetCombatMode @ 0x004BD610`.
**Acceptance:** Compare an occupied numbered toolbar slot in peace, melee, and
missile modes: the mesh remains gold/yellow. Enter Magic mode: physical-item
shortcuts use the gray ghosted mesh.
---
## #211 — Login-equipped missile weapon incorrectly requests melee combat
**Status:** DONE — 2026-07-13, user confirmed combat entry works (`ab98cda2`)
**Severity:** HIGH
**Component:** inventory projection / combat mode

View file

@ -40,7 +40,7 @@ Plus a special case at `407546` (`0058d1ee`): **`IsThePlayer`** → `m_idIcon =
- **`src/AcDream.Core/Items/ItemInstance.cs`** — has `IconId`, `IconUnderlayId`, `IconOverlayId`, `Type`. **No `Effects`/`UiEffects` field yet.**
- **`src/AcDream.Core/Items/ItemRepository.cs`** — `EnrichItem(objectId, iconId, name, type, iconOverlayId=0, iconUnderlayId=0)` writes the typed icon ids onto an existing item + fires `ItemPropertiesUpdated`. Threaded from `WorldSession.EntitySpawned``GameWindow.OnLiveEntitySpawned`.
- **`src/AcDream.App/UI/Layout/ToolbarController.cs`** — calls `iconIds(item.Type, item.IconId, item.IconUnderlayId, item.IconOverlayId)` per slot, re-runs `Populate()` on `ItemRepository.ItemAdded`/`ItemPropertiesUpdated` (so a late `CreateObject` re-binds the slot's icon).
- **(related, not icon-composite)** the **slot-number** system (`SetShortcutNum`, 3 digit arrays: occupied peace/war `0x10000042`/`0x10000043` from cell composite `0x10000346`, empty/background `0x1000005e` from composite `0x10000341`) is done — it's a separate `UIElement_UIItem` feature, not the icon composite, but lives on the same widget.
- **(related, not icon-composite)** the **slot-number** system (`SetShortcutNum`, 3 digit arrays: occupied regular/ghosted `0x10000042`/`0x10000043` from cell composite `0x10000346`, empty/background `0x1000005e` from composite `0x10000341`) is done — it's a separate `UIElement_UIItem` feature, not the icon composite, but lives on the same widget. The Boolean is `m_bShortcutGhosted`, true only in Magic mode; it is not peace/war.
---

View file

@ -224,6 +224,45 @@ parse/store/write even though this toolbar ignores it. Do not add spell icons or
spell casting to `gmToolbarUI`; implement the eight favorite-spell lists as a
separate subsystem.
### 2.4 Physical-shortcut number ghosting
The Boolean parameter of `UIElement_UIItem::SetShortcutNum @ 0x004E1590` is
not a peace/war selector. `ACCWeenieObject::SetShortcutNum @ 0x0058C100`
stores it verbatim as `m_bShortcutGhosted`, and `UIElement_UIItem::Update`
replays that named field into the widget. The digit-array selection is:
```text
UIElement_UIItem.SetShortcutNum(slot, ghosted): // 0x004E1590
if slot < 0:
hide shortcut-number element
return
if item icon is in empty state 0x1000001C:
digits = property 0x1000005E // empty slot
else if ghosted:
digits = property 0x10000043 // gray mesh
else:
digits = property 0x10000042 // gold mesh
set number image to digits[slot]
show shortcut-number element
```
`gmToolbarUI::RecvNotice_SetCombatMode @ 0x004BD610` first stores
`mode != MAGIC_COMBAT_MODE`, then passes the inverse to every occupied
shortcut cell. In direct pseudocode:
```text
shortcutsGhosted = (mode == MAGIC_COMBAT_MODE)
for each occupied shortcut slot i:
cell.SetShortcutNum(i, shortcutsGhosted)
```
Therefore NonCombat, Melee, and Missile all use property `0x10000042`; only
Magic uses the ghosted `0x10000043` sheet. Calling these arrays “peace” and
“war” reverses the meaning and incorrectly grays physical shortcut numbers in
melee and missile combat.
---
## 3. `gmToolbarUI` input, use, and selection pseudocode