fix(combat): restore retail combat bar controls

Resolve authored StringInfo labels from local.dat, port gmCombatUI's runtime option captions and checkbox widgets, and bind horizontal scrollbar media by retail structural roles so the green power jewel is a thumb instead of a tiled track. Persist the three combat options and make Auto Target govern target acquisition.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-11 20:26:52 +02:00
parent 2215c76c7e
commit 927fa7881a
19 changed files with 24591 additions and 48 deletions

View file

@ -6,6 +6,7 @@
- `gmCombatUI::RecvNotice_AttackHeightChanged` `0x004CC080`
- `gmCombatUI::RecvNotice_SetPowerbarLevel` `0x004CC0E0`
- `gmCombatUI::RecvNotice_DesiredAttackPowerChanged` `0x004CC110`
- `gmCombatUI::PostInit` `0x004CC1A0`
- `gmCombatUI::ListenToElementMessage` `0x004CC430`
- `gmCombatUI::RecvNotice_SetCombatMode` `0x004CC620`
- `ClientCombatSystem::Begin` `0x0056A460`
@ -16,6 +17,9 @@
- `ClientCombatSystem::UseTime` `0x0056C1F0`
- `ClientCombatSystem::HandleAttackDoneEvent` `0x0056C500`
- `ClientCombatSystem::SetRequestedAttackHeight` `0x0056C8F0`
- `UIOption_Checkbox::UIOption_Checkbox` `0x00486A50`
- `UIOption_Checkbox::ListenToElementMessage` `0x004869A0`
- `compute_str_hash` `0x00413110`
- Matching retail executable disassembly (`acclient.exe` v11.4186 + PDB):
`ATTACK_POWERUP_TIME = 1.0` seconds and
`DUAL_WIELD_POWERUP_TIME = 0.8` seconds. The named pseudo-C's x87
@ -133,3 +137,44 @@ attack power increase/decrease action:
Both keyboard and retained buttons therefore use one transition-based attack
controller. A one-shot click/keypress is not sufficient: down begins charging,
up ends the request.
## Authored labels and option checkboxes
```text
PostInit():
repeat = child 0x10000053 as UIOption_Checkbox
repeat.playerOption = AutoRepeatAttack
repeat.label = StringInfo(hash("ID_CombatPanelOption_AutoRepeatAttack"))
autoTarget = child 0x10000054 as UIOption_Checkbox
autoTarget.playerOption = AutoTarget
autoTarget.label = StringInfo(hash("ID_CombatPanelOption_AutoTarget"))
keepInView = child 0x10000055 as UIOption_Checkbox
keepInView.playerOption = ViewCombatTarget
keepInView.label = StringInfo(hash("ID_CombatPanelOption_ViewCombatTarget"))
```
The first two labels are deliberately not authored in LayoutDesc. They are
assigned by `gmCombatUI::PostInit`, so a layout-only renderer must perform that
controller binding. Ordinary Type-12 captions and High/Medium/Low use StringInfo
property `0x17` and resolve through local.dat table `0x23000001`.
`UIOption_Checkbox` is a toggle `UIElement_Button`. Its visible 13x13 face is
the authored child `0x10000328`; the label is embedded in the option object and
starts after that face. Mouse release toggles attribute `0x0E` and immediately
applies the associated player option.
## Horizontal scrollbar media roles
```text
track = scrollbar DirectState image
thumb = structural child element 1
live power fill = nested meter child 0x10000050 / image child 2
```
These roles are identified by authored element ids, never by resolved width.
The combat thumb is a 12x14 green jewel; inheritance reflow can make its
effective child geometry wide enough that a width heuristic incorrectly tiles
the jewel as the background. The base track is `0x060074CA`, thumb
`0x06001923`, and live red fill `0x06001200`.