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:
parent
9958458318
commit
2215c76c7e
22 changed files with 1265 additions and 46 deletions
|
|
@ -26,7 +26,7 @@ namespace AcDream.UI.Abstractions.Input;
|
|||
/// </summary>
|
||||
public sealed class KeyBindings
|
||||
{
|
||||
private const int CurrentSchemaVersion = 2;
|
||||
private const int CurrentSchemaVersion = 3;
|
||||
|
||||
private readonly List<Binding> _bindings = new();
|
||||
|
||||
|
|
@ -244,9 +244,12 @@ public sealed class KeyBindings
|
|||
// Melee mode (active when MeleeCombat scope pushed).
|
||||
b.Add(new(new KeyChord(Key.Insert, ModifierMask.None), InputAction.CombatDecreaseAttackPower));
|
||||
b.Add(new(new KeyChord(Key.PageUp, ModifierMask.None), InputAction.CombatIncreaseAttackPower));
|
||||
b.Add(new(new KeyChord(Key.Delete, ModifierMask.None), InputAction.CombatLowAttack));
|
||||
b.Add(new(new KeyChord(Key.End, ModifierMask.None), InputAction.CombatMediumAttack));
|
||||
b.Add(new(new KeyChord(Key.PageDown, ModifierMask.None), InputAction.CombatHighAttack));
|
||||
// Retail HandleCombatAction consumes key-down AND key-up for attack
|
||||
// height actions: down starts charging, up ends the request. Hold is
|
||||
// our binding representation for that transition pair.
|
||||
b.Add(new(new KeyChord(Key.Delete, ModifierMask.None), InputAction.CombatLowAttack, ActivationType.Hold));
|
||||
b.Add(new(new KeyChord(Key.End, ModifierMask.None), InputAction.CombatMediumAttack, ActivationType.Hold));
|
||||
b.Add(new(new KeyChord(Key.PageDown, ModifierMask.None), InputAction.CombatHighAttack, ActivationType.Hold));
|
||||
// Missile + Magic + Spell-tab — same chords; resolved by scope at
|
||||
// runtime per InputDispatcher's stack lookup. Add the bindings;
|
||||
// subscribers arrive in Phase L when CombatState.CurrentMode is
|
||||
|
|
@ -420,6 +423,7 @@ public sealed class KeyBindings
|
|||
}
|
||||
var chord = new KeyChord(silkKey, mods, device);
|
||||
action = MigrateLegacyQuickSlotIntent(version, action, chord, activation);
|
||||
activation = MigrateCombatAttackActivation(version, action, activation);
|
||||
loaded.Add(new(chord, action, activation));
|
||||
}
|
||||
}
|
||||
|
|
@ -516,6 +520,25 @@ public sealed class KeyBindings
|
|||
: action;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Schema v2 stored the three attack-height commands as one-shot Press
|
||||
/// bindings. Retail requires both press and release, so old and customized
|
||||
/// chords retain their key while upgrading to Hold transition semantics.
|
||||
/// </summary>
|
||||
private static ActivationType MigrateCombatAttackActivation(
|
||||
int version,
|
||||
InputAction action,
|
||||
ActivationType activation)
|
||||
{
|
||||
if (version >= 3 || activation != ActivationType.Press)
|
||||
return activation;
|
||||
return action is InputAction.CombatLowAttack
|
||||
or InputAction.CombatMediumAttack
|
||||
or InputAction.CombatHighAttack
|
||||
? ActivationType.Hold
|
||||
: activation;
|
||||
}
|
||||
|
||||
private static ModifierMask ParseModifiers(JsonElement bindingEl)
|
||||
{
|
||||
if (!bindingEl.TryGetProperty("mod", out var modEl)) return ModifierMask.None;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue