Melee feel overhaul: SwordCombat anims at heavy cadence, salvage axe, damage-at-contact + buffer + dash law (guidelines forks 1-6)
07-18/19/20 arc: LightCombo01/HeavyCombo01 clips onto Swing1-3/Slam at ~natural speed (26-tick window, 30-tick recover, DPS-held damage retune), Menacing01 combat idle (InCombat), SM_Wep_Axe_Large_01 rigid-skinned to Hand_R at x1.25, LANTERN FX retone + blade-smear ribbon. Forks 1-6 per Combat_Attack_Feel_Guidelines (design review wf_000bc247): cleave resolves at the CONTACT tick (MeleeCleavePending schedule-and-consume, knob 31, 0=legacy; connect cues moved to contact), MeleeRange 2.2 + reach-only finisher mult 1.25 (knob 30), BufferedAttackTick GhostField input buffer (knob 29, unlock-edge validity), dash refused pre-contact (lookup-based). Tests: MeleeComboTests pin legacy knobs; +3 fork tests (414 green); live server proof: HP drop exactly at swing+16 under tick batching. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -53,6 +53,12 @@ namespace ProjectM.Client
|
||||
/// override). The ability cooldown still gates how many shots actually result.</summary>
|
||||
public static void Fire(int frames = 10) { Active = true; FireFrames = math.max(FireFrames, frames); }
|
||||
|
||||
/// <summary>Frames remaining to hold the melee Attack event (07-19: melee swing validation).</summary>
|
||||
public static int AttackFrames;
|
||||
|
||||
/// <summary>Convenience: hold the melee Attack for the next <paramref name="frames"/> frames (also enables override).</summary>
|
||||
public static void Attack(int frames = 10) { Active = true; AttackFrames = math.max(AttackFrames, frames); }
|
||||
|
||||
/// <summary>Per-socket fire holds (LANTERN 4-socket kit). Each held frame raises that socket's fire event.</summary>
|
||||
public static readonly int[] SocketFrames = new int[SocketId.Count];
|
||||
|
||||
@@ -66,7 +72,7 @@ namespace ProjectM.Client
|
||||
public static void SetAim(float x, float z) { Active = true; Aim = new float2(x, z); }
|
||||
|
||||
/// <summary>Convenience: stop overriding and clear all injected input.</summary>
|
||||
public static void Stop() { Active = false; Move = default; Aim = default; FireFrames = 0; for (int i = 0; i < SocketId.Count; i++) SocketFrames[i] = 0; }
|
||||
public static void Stop() { Active = false; Move = default; Aim = default; FireFrames = 0; AttackFrames = 0; for (int i = 0; i < SocketId.Count; i++) SocketFrames[i] = 0; }
|
||||
|
||||
protected override void OnCreate()
|
||||
{
|
||||
@@ -80,6 +86,8 @@ namespace ProjectM.Client
|
||||
|
||||
bool fire = FireFrames > 0;
|
||||
if (FireFrames > 0) FireFrames--;
|
||||
bool attack = AttackFrames > 0;
|
||||
if (AttackFrames > 0) AttackFrames--;
|
||||
// LANTERN 4-socket kit: per-socket fire holds, decremented once per frame.
|
||||
bool s0 = SocketFrames[0] > 0; if (SocketFrames[0] > 0) SocketFrames[0]--;
|
||||
bool s1 = SocketFrames[1] > 0; if (SocketFrames[1] > 0) SocketFrames[1]--;
|
||||
@@ -99,6 +107,8 @@ namespace ProjectM.Client
|
||||
input.ValueRW.Scheme = Scheme;
|
||||
if (fire)
|
||||
input.ValueRW.Fire.Set();
|
||||
if (attack)
|
||||
input.ValueRW.Attack.Set();
|
||||
if (s0) input.ValueRW.Socket0.Set();
|
||||
if (s1) input.ValueRW.Socket1.Set();
|
||||
if (s2) input.ValueRW.Socket2.Set();
|
||||
|
||||
Reference in New Issue
Block a user