Fuse fixes: arming holds for every burst, no-lock rounds stop on the first hull, settle before user code

Operator ruling 2026-09-30: a no-lock round of any fuse stops at the first hull
on its aim line and detonates there (bomb fishing still bursts at max range on
a clear line). CommitBurst no longer special-cases Contact.

Soul's findings on 14f66634..7e620ff9:
- Arming (HIGH): a contact or delayed blast on a hull nearer the muzzle than the
  blast radius detonated at the hull. Armed is now the one owner of the arming
  rule; Solve plans its burst point through it and ApplyBlastHit pushes the hull
  point through it.
- A refused beam never starts (ConstantWeapon.Activate asks Refuses), so
  OnStartFiring no longer flashes visuals and audio for a beam that fires nothing.
- Step removes a shot from the queue before Apply runs damage observers, so a
  throwing observer cannot make the blast repeat every tick.
- AgentFires consults Solve for a fused weapon: a refused weapon is never fired
  and Combat's group pick no longer counts its damage.
- SingleAmmoBurst pays at its first unrefused round in Execute, judged with the
  Range that round flies with, instead of at the trigger on the previous tick's.
- Inspect reads Designated from Solve (FireSolution.Designated) instead of
  recomputing visible, in-range and locked; FireControlDiagnostic drops those
  three fields and the debug HUD shows the one. Combat's group range test is
  FireControl.InReach, the range half of Designated (a LockWeapon must be
  activated to acquire its lock, so Combat cannot ask Designated itself).

Tests pin each rule, plus the two surviving gaps: a pushed-out targeted round's
arrival at the arming distance, and the AgentMinHitProbability boundary.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-29 20:31:59 +02:00
commit 57c2560fc0
8 changed files with 325 additions and 69 deletions

View file

@ -1335,7 +1335,7 @@ public class ActionGameManager : MonoBehaviour
: "last: none";
var gates = target == null
? "target: none"
: $"gates vis {d.Visible} range {d.InRange} arc {d.InArc} lock {d.Locked}";
: $"gates designated {d.Designated} arc {d.InArc}";
// A fused weapon's forecast is its outcome, not a hit chance: the burst point or the refusal.
var outcomeLine = d.Outcome == FireOutcome.Burst ? $"burst at {d.BurstReach:F0}"