A trigger is the weapon's own state: a tap fires one burst and a held trigger fires its cooldown's rounds at any tick; a step resolves its rounds in fire-time order; the idle-clamp test really idles
InstantWeapon repeats while its trigger is down (Activate to Deactivate), not when it was pulled this step; AutoWeapon's override of that is gone. FireControl keeps the shot queue in fire-time order (ties by shot id) and Step walks it oldest first. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
37a7bb76f7
commit
46912a20c8
4 changed files with 141 additions and 21 deletions
|
|
@ -20,8 +20,5 @@ public class AutoWeapon : InstantWeapon
|
|||
|
||||
public AutoWeapon(InstantWeaponData data, EquippedItem item) : base(data, item) { }
|
||||
public AutoWeapon(InstantWeaponData data, ConsumableItemEffect item) : base(data, item) { }
|
||||
|
||||
// The trigger is held while it is down: InstantWeapon starts the next burst the moment the cooldown ends.
|
||||
protected override bool Repeats => _firing;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -61,9 +61,6 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior, IPowerCo
|
|||
// Seconds the last countdown ran past zero (less than one step). The next countdown starts that far along, so a held
|
||||
// trigger fires Cooldown apart on average at any step, never floor(Cooldown/dt)+1 steps apart.
|
||||
private float _overshoot;
|
||||
// The shooter asked for fire during this step (Activate): a weapon asked of for the whole step fires every round its
|
||||
// cooldown allows inside it, rather than one per step. Cleared when the step ends.
|
||||
private bool _pulled;
|
||||
// The shortest cycle a countdown divides by: a cooldown of zero would otherwise fire without end in one step.
|
||||
private const float ShortestCycle = .0005f;
|
||||
|
||||
|
|
@ -95,9 +92,11 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior, IPowerCo
|
|||
// manager can bind its presentation to the one shot it belongs to instead of applying damage itself.
|
||||
public event Action<int> OnFire;
|
||||
|
||||
// Whether the trigger is held through this step, so a cooldown that ends inside it starts the next burst inside it. A
|
||||
// tap or a press fires once per pull (a pull is held for its step); an automatic weapon holds while its trigger is down.
|
||||
protected virtual bool Repeats => _pulled;
|
||||
// Whether the trigger is down, so a cooldown that ends inside a step starts the next burst inside it. The trigger is the
|
||||
// weapon's own state, set by Activate and cleared by Deactivate (a player's press and let-go, an agent's pull and
|
||||
// release), never inferred from how often it was pulled: a tap fires one burst, and a held trigger fires every round
|
||||
// its cooldown allows, at any step length.
|
||||
private bool Repeats => _firing;
|
||||
|
||||
public virtual void ResetEvents()
|
||||
{
|
||||
|
|
@ -269,7 +268,7 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior, IPowerCo
|
|||
public override bool Execute(float dt)
|
||||
{
|
||||
try { return Step(dt); }
|
||||
finally { _pulled = false; _capacitor.Settle(); }
|
||||
finally { _capacitor.Settle(); }
|
||||
}
|
||||
|
||||
// One step of rounds. A round is due at a moment inside the step (_burstTimer is how long ago, at the step's end), and a
|
||||
|
|
@ -356,7 +355,6 @@ public class InstantWeapon : Weapon, IProgressBehavior, IEventBehavior, IPowerCo
|
|||
|
||||
internal override void Activate()
|
||||
{
|
||||
_pulled = true;
|
||||
if(CanFire)
|
||||
Trigger();
|
||||
base.Activate();
|
||||
|
|
|
|||
|
|
@ -783,7 +783,12 @@ public static class FireControl
|
|||
// point is decided at its commit (CommitBurst), which reads it there. Each shot reads it once.
|
||||
if (!shot.DeliveredAtCommit) Deliver(ref shot, solution.BurstReach);
|
||||
|
||||
zone.PendingShots.Add(shot);
|
||||
// The queue is in fire-time order, ties in shot-id order (ids rise as shots are made): Step walks it oldest first. Rounds
|
||||
// of one step are born shooter by shooter, so a later shooter's earlier round goes in before an earlier shooter's later one.
|
||||
var queue = zone.PendingShots;
|
||||
var place = queue.Count;
|
||||
while (place > 0 && queue[place - 1].FireTime > shot.FireTime) place--;
|
||||
queue.Insert(place, shot);
|
||||
return shot.ShotId;
|
||||
}
|
||||
|
||||
|
|
@ -849,7 +854,10 @@ public static class FireControl
|
|||
if (shots.Count == 0) return;
|
||||
|
||||
var now = zone.Time;
|
||||
for (var i = shots.Count - 1; i >= 0; i--)
|
||||
// In fire-time order, oldest first (the queue is kept in it by Fire), so which of a step's rounds breaks a shield or
|
||||
// lands a kill follows sim time, not the order the shooters were stepped in. Shots queued while this walk runs are
|
||||
// left to the next step.
|
||||
for (int i = 0, end = shots.Count; i < end;)
|
||||
{
|
||||
var shot = shots[i];
|
||||
|
||||
|
|
@ -863,6 +871,7 @@ public static class FireControl
|
|||
// target is gone. Republishing the committed outcome here used to put a hit marker on a corpse.
|
||||
var miss = MakeOutcome(shot, ShotResult.Miss, false, false, int2.zero, float2.zero, 0f, now);
|
||||
shots.RemoveAt(i);
|
||||
end--;
|
||||
if (!shot.Committed) zone.ShotCommitted.OnNext(miss);
|
||||
zone.ShotResolved.OnNext(miss);
|
||||
continue;
|
||||
|
|
@ -890,9 +899,12 @@ public static class FireControl
|
|||
// Removed first: Apply reaches damage observers (user code), and a shot left in the queue by one
|
||||
// that throws would resolve, and hurt, again on every later tick.
|
||||
shots.RemoveAt(i);
|
||||
end--;
|
||||
Apply(zone, shot);
|
||||
zone.ShotResolved.OnNext(shot.Outcome);
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue