feat(combat): port retail basic combat bar

Mount authored gmCombatUI, share one press/hold/release request state machine across DAT buttons and keybindings, and recover the exact 1.0s/0.8s power timing from matching retail x86. The same timer fixes jump charge, while ready-stance, response queueing, auto-repeat, layout binding, migration, and conformance coverage keep behavior architectural rather than panel-local.

Co-Authored-By: Codex <codex@openai.com>
This commit is contained in:
Erik 2026-07-11 14:03:28 +02:00
parent 9958458318
commit 2215c76c7e
22 changed files with 1265 additions and 46 deletions

View file

@ -47,6 +47,14 @@ public sealed class UiButton : UiElement, IUiGlobalTimeListener, IUiDatStateful
/// <summary>Optional click handler. Wired by the controller (e.g. chat Submit, ToggleMaximize).</summary>
public Action? OnClick { get; set; }
/// <summary>
/// Optional pointer transition handlers. These expose retail's distinct
/// pressed/released element messages for controls such as the combat-height
/// buttons, where mouse-down begins charging and mouse-up commits the attack.
/// </summary>
public Action? OnPressed { get; set; }
public Action? OnReleased { get; set; }
/// <summary>
/// Optional position-aware click handler. Coordinates are local pixels in this button,
/// matching retail's <c>UIElementMessageInfo.ptWindow</c> paperdoll hit-test input.
@ -292,6 +300,8 @@ public sealed class UiButton : UiElement, IUiGlobalTimeListener, IUiDatStateful
_pointerOver = ContainsLocal(e.Data1, e.Data2);
_pressed = true;
UpdateVisualState();
if (Enabled)
OnPressed?.Invoke();
if (HotClickEnabled && Enabled)
{
OnClick?.Invoke();
@ -319,6 +329,8 @@ public sealed class UiButton : UiElement, IUiGlobalTimeListener, IUiDatStateful
_nextHotClickTime = double.NaN;
if (_pressed && _pointerOver && Enabled && ToggleBehavior)
_selected = !_selected;
if (_pressed && Enabled)
OnReleased?.Invoke();
_pressed = false;
UpdateVisualState();
return true;