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>
Agent, Flight, Combat, MoveTo and Follow write only Ship.Command. Entities
with no agent apply first, then each agent applies right after it decides.
A pilot reads its own pending designation and aim item back from its command;
FireControl gains Refuses/AgentFires/HitProbability overloads that take them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DropSeed = CombatSeed ^ Mix(Galaxy.Seed), derived at construction. A zone with
no galaxy, or a restored seed of 0, keeps its dice bit for bit; CombatSeed
still roots shot, patrol and range-sample dice. RunSeedFixture builds a test
zone's galaxy through RunSave.Commit and the Continue constructor.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Cuts WatchForGrudge, PerceivedStanceOf, the recursive IsHostileTo and the inline compare-and-write; adds _telemetry (ReceiveTelemetry at track entry), Provoke (Track paint, committed shot), RefreshStance, BelievesTrespassing. Not yet verified: unbuilt, tests unrun.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Conflicts: GameData/Aetheria.cc takes master's blob (doctrine-catalog and verse-grammar re-applied in a later commit, follow-up catalog-blob-merge-order); IffAndCombatTests NewShip admits through zone.Admit(ship, piloted); Program.cs keeps master's cases plus doctrine-catalog; FireControlPerWeaponTests keeps master's asserts with the branch's Minion constructor. Master-only compile sites adapted: Minion(ship, doctrine) in FireControlPerWeaponTests, LayoutAimTests, ScannerTests; AgentFires threshold in SolutionTests; Zone.Remove and VerseGrammar in FlightTests.
Not verified to build until the verify run at the end of the pass.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Forecast and Fire drop a mount aim whose gate closed (destroyed, unidentified); a record for one Bay never hides another's mount; Deactivate clears the record. Deleted: the located-or-booked guard in RecordSeenDestroyed and the Entity == subject check in ResolvedAim (the record is read only for layout mounts; a Target change already clears the slot). Comments name AimedAt. Not built or run yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The previous commit does not build (a leftover line in FireControl.cs). EndReveals
only runs for subjects the book holds, so a record of a quiet departed ship was held
for the sitting; Sense's prune now ends it too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Entity.AimedAt (AimTarget: a revealed item or a believed mount) replaces
TargetItem. Two writers, TrySelectTargetItem (IsRevealed) and TrySelectMount
(in LayoutOf, not seen destroyed); ResolvedAim re-validates both on every read.
AimCycle is SchematicRows' enemy rows minus mounts in the observer's
seen-destroyed record, written only in Sense through PerceivesDestroyed.
SchematicRows drops its covering filter. IsLocated and AimsAtMount are deleted;
PendingShot.AimedMount and Silhouette's HardpointData mount replace the bool.
The cycle key calls Entity.CycleAim; the schematic marks read ResolvedAim.
Entity.ToString names an entity (follow-up entity-formats-safely).
The slot is AimedAt, not Aim: Entity.Aim is the pilot's pointing direction.
Not yet built or run; ActionGameManager and SchematicDisplay are uncompiled
without Unity.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
TrySelectTargetItem and ResolvedTargetItem gate on FireControl.IsLocated (an item seen to act, or one on a mount of the
believed hull's layout) instead of IsRevealed; Combat keeps IsRevealed. Entity.LayoutOf derives the layout from the
Contact profile; SchematicRows appends a mount row per unclaimed hardpoint. A mount aim centres on the mount's cells and
is frozen per shot (PendingShot.AimAtMount). The cycle runs over located items, the schematic renders mount rows and
marks through SchematicRow.Marks. Not yet built or tested.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A mine layer carries no EffectiveRange or DamageAtMaxRange (StatValidation.ValidateMineLayerFlat, run wherever the other catalog rules run), so RangeFactor is 1 inside its gate for the mine, the AI and the panel without any reader branching on type; Lay's damage is the weapon's damage again. Adds a test that fails without Deliver's min(reach, MaxRange) clamp. Not built or tested yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A no-lock fused round reads RangeFactor in CommitBurst at the distance it travelled to the hull it stops on; every round whose point
Solve plans reads it once at Fire (PendingShot.DeliveredAtCommit says which). Lay reads it at its own distance 0. PerformanceStat.Evaluate
no longer interpolates a single-value span, so an unauthored +infinity stat evaluates unequipped. Tests: the round that stops short, the
Fused Rounds hull ahead, a mine layer's authored ranges, the group pick at the target's real distance, unequipped SRMM72/Mine Launcher.
Not yet built (verify job follows).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WeaponData.RangeFactor is the one function of damage over range: 0 outside
[MinRange, Range], 1 up to EffectiveRange, one lerp to DamageAtMaxRange.
DamageCurve (key 7, retired) and its formula parameters, CurveField's
BezierCurve path, and every fixture curve line are deleted. Fire freezes
damage times the factor at BurstReach; the AI's DPS reads, Combat's optimum
sampling and the properties panel chart read the same function. AetherDb
gains range-falloff (command only; the catalog is re-saved in a later commit).
Cut and wiring land in one commit rather than two; this commit has not been
built yet.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
IsRevealed is now the observer's book (Entity.HasReveal) plus the live filter
(still on its ship, not IsDestroyed). The tier ladder and
GameplaySettings.TargetArmorInfoThreshold are deleted, with the 19 fixture
initializers and the Settings.asset line. Fixtures that aim at an item record
its reveal through RecordReveal; Aetheria.Shared exposes internals to
Aetheria.Shared.Tests for that. Unbuilt and untested at this commit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
AbsorbEvent gains AbsorbLayer. Entity.Capabilities, four publish sites in ApplyDirectHit and Detonate (each before the damage it reports), Feedback.Cue, DrawAhead.Carried (Impact delegates), PlayerGraphicsSettings.ScreenShake. Not yet built or tested; tests follow in the next commit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deletes the articulation anchor role. Adds ShipJoint (key 5 Joints), ShipAnchor.Joint (key 5),
the judge's joint-shape, mount-on-joint and yaw-reach checks over RigChains, Bind's GLB checks
(ReadNodeIds returns the nearest tagged ancestor), and ShipModPlan.Rigs. Presentation only:
arc stays HardpointData.FiringArc and traverse WeaponData.Tracking (ruling mount-arc-gun-traverse).
Not yet built or run when committed; the verification commit follows.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FireControl.RoundEnd and RoundAt leave FireControl (RoundEnd to DrawAhead verbatim, RoundAt as DrawAhead's private Line);
DrawAhead.Round takes the published outcome, steers a hit or burst from its frozen line at the commit tick onto its
end (burst point, else the impact cell on the target's drawn pose), and RoundStop is deleted. Projectile caches the
last published ShotOutcome and calls DrawAhead only. BallisticFlightTests move to the new signatures; the frozen-line
moving-target test is replaced by impact-cell, steer and no-drawing-function tests. Unverified: not yet built or run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
RoundEnd(shot, known) is the one statement of when a ballistic round's drawn
flight ends: arrival for a hit, burst or unpublished outcome, the frozen range
(never short of arrival) for a miss. RoundAt takes the known outcome and clamps
at RoundEnd. DrawAhead gains Round, RoundStop, RoundOver (pure, no state) so the
blend, stop and done rules are headless-testable. Seven new tests (ten cases).
Unity build: Projectile.cs still calls the old RoundAt, so this commit does not
compile in Unity (the headless test project does not include Projectile). The
next commit moves Projectile onto the statics.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FireRange is the distance to the engaged target and 0 for a round with none, so a no-lock burst round and a
round that misses never flew. MaxRange = weapon.Range is frozen at Fire beside Speed. Unity compile not yet run.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PendingShot freezes the weapon's Velocity as Speed at Fire; RoundAt(shot, time) reads the frozen origin,
direction, speed and fire time, clamped to the FireRange point. Step, Commit and Apply do not call it.
BallisticFlightTests pin the line against the shooter position, aim and authored velocity.
Builds: yes. Presenters still fly their own rounds at this commit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
FactionDoctrine/RoleDoctrine (Faction key 17), Flight as the only writer of
members' Target and Task, hail/grace/compliance, FollowTask/FollowState,
agent removal on Entities removal, doctrine-catalog command, FlightTests.
Not yet built or run; verification follows in later commits.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Bears is extracted from PFire; ArcPermitsFire passes on a fused gun, a solution, or a free aim in arc.
Solve flies along Solution's direction. ArticulationPoint loses its yaw clamp and follows a per-group
aim point placed from the group's solution. Arcs gets its new brief; Broadside is new.
Unverified: first commit of the cut, not yet built.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Soul gate closed at verdict cut-evasion-term.s5 (head 473a4bcc); remaining Low
test gaps are deferred to a follow-up. Merged under operator ruling
aetheria-release:ruling:completed-cuts-merge. Carries the migrated
GameData/Aetheria.cc (LFS sha256 63250cf2...7ae25); master did not change the
catalog.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Delete ABigGunHitsABigShipAtRange and TheCatalogMeetsTheRuledOutcomes (rulings cshot-rainbowlite-rate, evasion-angular-velocity-r2).
- TheJinkIsForgivenPerShipInThePrice: HitProbability of two guns of different rates carries PDeviation(Evasion, Tracking(shooter)).
- TrackingRate: an unlimited gun is +infinity whatever the gear reads, not inf * 0 = NaN.
- EveryAggregateAndTheCompensationReadLiveThrust: trim membership read from the thrusters' torques, not Ship's private list.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
MineLayerData (union 40) lays through InstantWeapon -> FireControl.Fire -> Lay;
Zone.Mines steps each mine as a KinematicBody after the entity loop, arms it,
triggers it on a hostile hull its blast disc touches (FireControl.Touches, the
coverage Detonate uses) and detonates it through FireControl.Detonate at the
fuse delay or lifetime. Hostile trigger, faction-blind blast, no owner leash.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Soul gate closed at verdict cut-floating-bodies.s3, head 6299627b, under
operator ruling aetheria-release:ruling:completed-cuts-merge.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
PMount(AngularVelocity(source, target), TrackingRate(weapon, source)) multiplies HitProbability after the pFire gate;
Fire freezes it into PendingShot.PFire; Inspect and the debug HUD show omega, rate and the factor. TrackingRate is the
one product of the gun's rate and the ship's gear (ruling tracking-per-gun). Tracking(Entity) in metres still alone
forgives the changes of vector (ruling jink-per-ship).
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Operator ruling mines-back-in-sim-asap: delete now, return as a simulation body.
Mesh, materials and BigExplosion stay for the sim-mines presenter. GridObject
stays for the pickups until loot-1 r2. Comments in FireControl.Detonate and
HullCollider drop the deleted callers. Builds not yet verified at this commit.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Ship.Update reads Turn and feeds the rotation thrusters and aether drives; it no longer reads the
look direction or snaps Direction toward it. Steering.Toward is the one law from heading to demand
(a heading astern now turns at full demand). HelmInput owns the face-the-aim state. Accelerate,
Combat and MoveTo write Turn through Steering.Toward. Entity.LookDirection is renamed Aim in the
simulation, the Unity readers and the tests. Unity player input follows in the next commit.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Every hit price gains one factor, PDeviation(Evasion, Tracking): how far the target can
and does move off the line of fire within SolutionWindow (0.75 s). Capability is Reach, an
eight-face closed form over the ship's ManoeuvreEnvelope (summed from what each live
thruster and aether drive reports with its own Execute arithmetic, read live: a thruster's
Thrust property is stale until it fires, which is why the Djinni moved 1.6 times its stats,
M25). Behaviour is ManoeuvreTrack, observed once per Entity.Update from the measured
acceleration; a steady burn, coasting and a dither much faster than the window do not
evade, and sideways speed alone does not (ruling evasion-speed). The commit price adds the
term at any flight time, so an instant weapon feels a jinking target. Forecast owns the
term for HitProbability and Inspect, which gain Evasion and PEvasion.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
DeviationProbability's inline saturate becomes PDeviation(deviation, tolerance), defined
for a zero tolerance as well. No behaviour change for a positive tolerance. Delete-first
step of the evasion term: every later deviation-like price reads this one shape.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Mining owns belts, chunks and target picking; scenarios owns admission and run
staging; master owns ships and fire control (rule scenarios-cut.md S4).
- AetheriaStores.CatalogTypes: nine-type union, master's list plus FieldKindData, no Scenario.
- tools/AetherDb/Program.cs: both cases (ship-authoring, field-kinds), one usage string.
- Zone.cs: master's MineAsteroid dropped (mining deleted its inputs); scenarios' SettleBelts and its three calls deleted.
- RunStartTests: the two belt-task tests deleted (they read belt.Transforms and MineAsteroid).
- FireControlCut124Tests: master's strict Exact assertions; mining's CompatibleDrift allowance and its comment dropped.
- GameData/Aetheria.cc: master's pointer 70a7b0a9. This commit lacks the Asteroid field kind in the catalog, so
TheShippedCatalogHasAPickableFieldKind fails here by design; the next commit rebuilds it.
Builds: this commit builds (verified at the end with commit 2); the catalog pin test fails at this commit.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The placement rule (HardpointAt) already finds the one hardpoint an item lies
in at equip; TryEquip threw that answer away and eighteen readers recomputed it
from the item's origin cell, which need not lie in the hardpoint (Soul's
scenarios batch-4 P30). EquippedItem.Hardpoint now carries the answer, null for
Tool gear and the hull, and every origin-cell lookup reads it instead:
FireControl.ArcFor, the eleven weapon managers, EntityInstance, ShipInstance
and ActionGameManager's articulation grouping. Entity.Hardpoints[,] stays the
per-cell map for armour and display.
TryFindSpace's hardpoint search tries every origin the fit rule can accept,
including ones up and left of the hardpoint, so a design whose shape lacks its
origin cell is found wherever ItemFits would place it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Entity.Target is one slot of TargetRef, read-only from outside
(IReadOnlyReactiveProperty); Entity.SetTarget is its one writer. A chunk is
taken only while the entity can see it, so a rock in darkness cannot be
picked. Every handler, agent, turret and test writes through SetTarget.
- Entity.ChunkInfo (Q14 A): the value the per-tick sensor rule settles at,
computed on demand through Sensor.PassiveRate/Sensor.Gain -- sum of the
active sensors' passive rates over (sensors x TargetInfoDecay), capped at 1.
Stored nowhere; no per-tick loop over chunks. ChunkVisible is the detection
threshold through the chunk path.
- The lost-track rule reads through the chunk path: Activate's reconciliation
and a per-tick check of the one slot drop a chunk target that has gone dark.
- Entity.VisibleChunksInReach (Q13 A): visible chunks within the longest range
among active weapons -- the one reach rule for cycling and programmatic picks.
- Entity-only readers take .Entity: TargetedBy/TargetedByCount, target items,
the stance gate (a chunk has no stance), lock (Q12 A: never on a chunk),
turrets, Combat, Minion, FireControl (a chunk fires untargeted until Cut 4).
TargetRange and the arc gate read a chunk's planar position.
- ActionGameManager: the reticle and next/previous offer visible ships and
visible chunks in reach; nearest stays enemies-only; the target panel,
indicator and fire-control debug take TargetRef. EntityInstance reads .Entity.
- MiningCut3Tests pin parity, darkness, monotone brightness, wear and break,
reach, the chunk query, target survival and loss, TargetRef equality, lock,
and field-kind assignment at generation and first load.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A burst whose every round is refused fires nothing and leaves no cooldown: the cooldown moves from
Trigger to the first round Execute does not refuse, and CanFire holds a triggered burst that has not
yet fired. ChargedWeapon.Activate asks FireControl before it starts charging, so a refused weapon pays
no charge heat or audio. InReach is deleted: Designated carries the one range test and the lock gate,
and Combat reads it. GuidedProjectile answers Resolve while alive and keeps its binding through the
shot's flight time, so a faded round still shows the simulation's detonation.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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>
Operator rulings 2026-09-30.
* Combat and TurretController ask FireControl.AgentFires for each weapon. A
fused weapon fires whenever its target is designated (Designated, the one
visible / in-range / locked predicate PFire already used), whatever the arc;
an agent never fires one at nothing. A direct-hit weapon keeps the
AgentMinHitProbability threshold. The group's first weapon no longer speaks
for the group, and the turret's own range test is gone.
* FireControl.Solve is the one decision about what a round does, extracted
from Fire: Direct, Burst at a reach, or Refused. Fire, Inspect and the
weapons' refusal check all read it. Inspect gains Outcome and BurstReach and
the debug HUD prints them for fused weapons.
* A refused round costs nothing. InstantWeapon asks before its ammo and energy
spend (at the trigger and at each round), ConstantWeapon folds the refusal
into the gate its power request and Execute already share, so a refused beam
draws no power, wear, heat or visibility and stops.
* The arming distance is BlastRadius, measured from the shooter's position and
blind to hull size. HullAhead's exit, ArmingDistance and
PendingShot.ArmingDistance are deleted; HullAhead survives as HullEntry for
the contact fuse. A round fired at a valid target inside the radius is pushed
out along its line but keeps its target, so a departed target cancels it.
* Step settles a shot's queue state before publishing about it, so a throwing
presentation observer costs its own notification and cannot re-commit or
re-resolve the shot on every later tick.
Tests: FireControlPerWeaponTests (new; includes a fused-beam fixture), the
arming tests in FireControlCut124Tests rewritten to the literal distance,
the hull-inclusive probe premises deleted.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Operator ruling 2026-09-30. A fused round's burst is at least BlastRadius
beyond the far edge of the shooter's own hull, measured along the flight line
against the hull as it stood at fire (HullAhead's exit). A close burst -- a
target inside that distance, in or out of arc -- is pushed out along the aim
and carries no target; a contact round is floored to it too.
- The F3 trigger gate is deleted. Fire refuses a round (returns 0) whose
arming distance exceeds Range, per round, where Range is read after Execute
refreshed it; InstantWeapon and ConstantWeapon skip a refused round.
- PFire's range, Inspect's range and the range clamp are planar (R7).
- HullEntryDistance becomes HullAhead (entry and exit); the max(...,0) clamp
on entry is gone, the arming floor covers it.
- ShotOutcome.HasBurstPoint names the rounds that have a frozen burst point.
- SafeAssert: the tests no longer hand xunit an Entity, PendingShot or
ShotOutcome to format; a failing assertion had been overflowing the test
host's stack.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Operator ruling 2026-09-30: a fused weapon with a selected but out-of-arc
target fires. Its round flies along the arc-clamped aim and bursts at the
target's range. Non-fused weapons still refuse.
- FireControl.ArcPermitsFire is the one trigger arc gate (fused weapons are
exempt); Fire reads the same InArc through PFire's new designated/inArc
outs, which replace `bears`. No valid targeting data still bursts at Range.
- F3: a fused weapon whose effective Range does not exceed its BlastRadius
stays safed at the trigger (FuseCanArm, read from the runtime Range). The
catalog check on Range.Min is deleted; it read the authored floor, which
Evaluate can scale below.
- F4: a targeted proximity burst is pulled back along its line to Range.
- F8: a proximity round that detonates commits as Burst (or Hit); Apply's
Proximity case collapses into the Burst path via Outcome.BurstPoint.
- Tests: arc-only and LockWeapon gates, out-of-arc burst, trigger gate,
runtime-Range refusal, Range clamp, Burst typing, commit horizon, and
Soul's adopted probes (aim clamp edges, contact point, target leaves,
shooter destroyed).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Operator rulings 2026-09-30 after Soul's pass on 8c002637:
- A no-lock round flies along Entity.LookDirection restricted by the mount's
arc (FireControl.AimDirection: inside InArc's cone as is, outside it turned
to the cone's edge; no aim falls back to the mount). The simulation had no
aim clamp before; the old code used the hull-fixed mount direction.
- An invalid target (out of range, out of arc, not visible, not locked) counts
as no lock for a fused round. PFire's gate is the one decider and now also
reports `bears`; Fire reads it. The round carries no target afterwards.
- A no-lock Contact round bursts at the first hull its aim line crosses
before max range, read through Lane's own cell admission (CellsOnLine,
split out of Lane). Proximity and Delayed keep the max-range burst. Such a
round commits at Fire, since it has no target facing to read late, and
arrives when it has flown to the burst point. The seam for mining chunks is
FireControl.ContactDistance.
- A round outlives its shooter: Step no longer cancels a shot whose source
left the zone. Resolution reads the zone and the target; the shooter is an
identity a shot carries. PendingShot.FireOrigin freezes where it left from.
- ShotOutcome.Result (Miss, Hit, Burst) replaces the stored Hit bool, which
is now derived. A burst without a target is no longer reported as a miss,
and the debug HUD labels it BURST.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Operator ruling 2026-09-30: fused weapons without a lock explode at max
range. Fire froze BurstPosition at the shooter's own position with flight
time 0, so a proximity shot detonated on its own shooter and contact and
delayed shots did nothing.
With no target and a fuse, Fire now freezes the burst point as the mount
direction times the weapon's Range stat from the source, and flight time as
Range over Velocity. Apply sends every such shot through Detonate at that
point whatever its fuse. Targeted shots and unfused shots are untouched.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>