Cut 12.2: where a hit lands is priced and drawn from one silhouette

FireControl.Silhouette replaces HullKernel/WeightedPick/POnHull: the hull's
lateral shadow at a bearing, merged into intervals, integrated exactly with
CultMath.erf/erfinv instead of a discrete per-cell Gaussian sum. FireControl.Lane
does exact slab traversal to pick the impact cell from a lateral offset; only
its first element (the entry-nearest occupied cell) is used here, per the cut
map -- the rest is 12.3's armour-first absorption march.

Bearing timing: PendingShot.PBase is renamed PFire and now carries only the
shooter-side factor (Accuracy x PSensor) behind the gates; TravelDirection,
Spread and FireRange are frozen alongside it. The target's facing is read live
at Commit through FireControl.CommitProbability (steps 1-5 of the spec's
"Bearing timing"), not frozen at Fire, so a target that turns its armour into
an incoming shot takes the hit there. ShotOutcome gains Bearing/Lateral,
frozen at commit; Apply reads only those, never a live position or facing.
Entity.ApplyHit takes an already-schematic bearing instead of a world
direction, and the ToSchematic call 12.1 put inside it is gone.

Superseded tests: PlacementAndProbabilityShareOneKernel, EveryHitLandsOnMetal
and AimingAtTheSternHitsTheStern are replaced by
FireControlCut12Tests.PlacementAndProbabilityShareOneSilhouette,
HitsLandOnTheFacingEdge and AimingAtAnItemCentresTheScatterOnItsLane.
FireAuthorityTests.AimedHitLandsOnSelectedItem and PenetrationMarchIsPlanar are
updated for ApplyHit's new bearing parameter and Lane's entry-nearest-cell
placement (a solid hull's Tool item is never itself the entry cell; reaching
it now needs the same penetration march the new tests exercise).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-24 20:40:50 +02:00
commit 7dbb3bcf7a
8 changed files with 1042 additions and 261 deletions

View file

@ -384,12 +384,13 @@ public abstract class Entity
return float2(dot(worldPlanar, right), dot(worldPlanar, forward));
}
// Cut 3: the shape construction moved from EntityInstance.cs's Unity HullCollider subscription, with two
// changes forced by R7 (the simulation is 2D): the hit cell is the rolled Cell FireControl already chose,
// not a UV texture coordinate; and the penetration march rotates the firer-to-target direction into this
// entity's own frame with a planar rotation by -Direction, in place of transform.InverseTransformDirection
// -- no 3D transform anywhere in the march. `hitDirection` is the planar (x,z) firer-to-target unit vector.
public void ApplyHit(Entity source, int2 cell, float spread, float penetration, float damage, float2 hitDirection)
// Cut 3: the shape construction moved from EntityInstance.cs's Unity HullCollider subscription -- the hit
// cell is the rolled Cell FireControl already chose, not a UV texture coordinate.
// Cut 12.2 (docs/fire-control-cut.md): `bearing` is already in this entity's own schematic frame -- the
// committed ShotOutcome.Bearing FireControl.Commit computed once, at the commit tick -- so the ToSchematic
// call this used to make internally (12.1) is gone; ApplyHit no longer touches a world direction or this
// entity's own Direction at all.
public void ApplyHit(Entity source, int2 cell, float spread, float penetration, float damage, float2 bearing)
{
IncomingHit.OnNext(source);
@ -402,7 +403,7 @@ public abstract class Entity
if (penetration > .5f)
{
var penetrationVector = normalize(ToSchematic(hitDirection));
var penetrationVector = normalize(bearing);
var penetrationPoint = (float2) cell + float2(.5f);
var penetrationDistance = 0f;