acdream/docs/research/2026-07-13-retail-jump-powerbar-pseudocode.md
Erik db03b4bda8 feat(ui): port retail jump power bar
Import gmFloatyPowerBarUI LayoutDesc 0x21000072, teach the meter factory its stateful single-image shape, and project the movement-owned retail jump charge through a focused retained controller. Preserve authored resize constraints and state-managed visibility, with named-decomp pseudocode plus controller, movement, and production-DAT conformance coverage.

Co-Authored-By: Codex <codex@openai.com>
2026-07-13 10:22:12 +02:00

135 lines
4.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Retail jump power bar — pseudocode and port map
Date: 2026-07-13
Binary: Sept. 2013 EoR `acclient.exe` v11.4186
Scope: the floating `gmPowerbarUI` presentation used while the player charges a jump
## Named retail sources
- `gmPowerbarUI::PostInit @ 0x004DA4E0`
- `gmPowerbarUI::RecvNotice_SetPowerbarLevel @ 0x004DA550`
- `gmPowerbarUI::RecvNotice_FinishPowerbar @ 0x004DA580`
- `gmPowerbarUI::RecvNotice_BeginPowerbar @ 0x004DA730`
- `gmFloatyPowerBarUI::PostInit @ 0x004D0F00`
- `gmFloatyPowerBarUI::UpdateFromPlayerModule @ 0x004D1200`
- `gmFloatyPowerBarUI::ResizeTo @ 0x004D1460`
- `gmFloatyPowerBarUI::MoveTo @ 0x004D15D0`
- `gmFloatyPowerBarUI::SetVisible @ 0x004D17D0`
- `ClientCombatSystem::FinishJump @ 0x0056A9B0`
- `ClientCombatSystem::StartPowerBarBuild @ 0x0056ADB0`
- `ClientCombatSystem::GetPowerBarLevel @ 0x0056ADE0`
- `ClientCombatSystem::CommenceJump @ 0x0056AF90`
- `ClientCombatSystem::DoJump @ 0x0056B110`
The symbols and addresses above are present in
`docs/research/named-retail/symbols.json`; the bodies are in
`docs/research/named-retail/acclient_2013_pseudo_c.txt`.
## Authored DAT layout
Portal DAT `LayoutDesc 0x21000072` is a `gmFloatyPowerBarUI` window:
| Element | ID | Geometry | Media/state |
|---|---:|---:|---|
| Root | `0x10000612` | 610×25 px | custom type `0x10000053` |
| Meter | `0x10000034` | x=5, y=5, 600×15 px | empty track `0x06004D0B` |
| Fill field | `0x00000002` | 600×15 px | JumpMode `0x10000042``0x06001354`; MeleeMode `0x10000043` and MissileMode `0x10000044``0x06001200`; DDDMode `0x10000045``0x0600195B` |
| Recklessness field | `0x100005EE` | x=60, 480×15 px | `0x0600715E`; hidden by `PostInit` |
The meter's fill is clipped horizontally. A level of 0.0 shows no fill; 0.5
shows the left 300 px; 1.0 shows the full 600 px. It does not stretch from the
center or from the right.
## Retail lifecycle pseudocode
```text
CommenceJump():
if jump_pending:
return
error = motion_interpreter.charge_jump()
if error != success:
report the matching jump error
return
cancel repeat attack if active
latest_powerbar_level = 0
jump_pending = true
powerbar_mode = JUMP
notify BeginPowerbar(JUMP)
StartPowerBarBuild()
StartPowerBarBuild():
build_in_progress = true
build_start_time = current_time
notify SetPowerbarLevel(powerbar_mode, 0)
latest_powerbar_level = 0
GetPowerBarLevel():
if not build_in_progress:
return 0
duration = 0.8 seconds in dual-wield style, otherwise 1.0 second
return clamp((current_time - build_start_time) / duration, 0, 1)
gmPowerbarUI.BeginPowerbar(JUMP):
set root state to JumpMode (0x10000042)
current_mode = JUMP
set meter 0x10000034 level to 0
show window
gmPowerbarUI.SetPowerbarLevel(mode, level):
if mode == current_mode:
set meter 0x10000034 level to level
DoJump(on release):
extent = max(GetPowerBarLevel(), MIN_JUMP_EXTENT)
FinishJump()
motion_interpreter.jump(extent)
send JumpPack(extent, velocity, position/update sequences)
FinishJump():
if jump_pending:
stop build and clear its time
notify FinishPowerbar(JUMP)
powerbar_mode = UNDEFINED
clear standing_longjump
jump_pending = false
gmPowerbarUI.FinishPowerbar(JUMP):
if JUMP == current_mode:
current_mode = UNDEFINED
set meter level to 0
hide window
```
`gmPowerbarUI::PostInit` also hides the recklessness field. The floaty subclass
restores and persists its position, size, lock chrome, and visibility through
the normal retail window preferences.
## Reference cross-checks
- ACE `ACE.Server/Network/Structure/JumpPack.cs` documents `Extent` as jump
power 01. `ACE.Server/WorldObjects/Player.cs::HandleActionJump` clamps the
received extent to that same interval before applying jump stamina/height.
- holtburger `crates/holtburger-core/src/client/commands.rs` carries the chosen
extent unchanged into the `JumpData` action. Its vendored ACViewer movement
implementation likewise stores jump extent as the power input to the jump
calculation.
These references corroborate the data range and its handoff. The named retail
decomp remains authoritative for charge timing, notices, visibility, and UI
state selection.
## acdream port map
- `PlayerMovementController` already owns the exact shared retail charge clock
and release transition. Expose it as a read-only `(IsCharging, Power)`
snapshot; do not add a UI timer.
- Teach `UiMeter`/`DatWidgetFactory` the DAT's stateful single-image meter shape:
meter direct media is the track, child state media is the selected fill.
- `JumpPowerbarController` selects JumpMode, binds fill to the movement snapshot,
and performs the begin/show and finish/reset/hide transitions.
- `RetailUiRuntime` imports and mounts `0x21000072` as a state-managed retained
window. `GameWindow` only supplies the movement snapshot delegate.
This port introduces no intentional retail divergence.