#124 bench: the ZONE-WALK MATRIX -- systematic per-panel targeting, operator-watchable

The precision rig the operator specified: two nodes, target visible,
every zone aimed at deliberately through the REAL reticle/pick path.

* BT_SPIN_SELF=<deg/s> (target node): rotates the node's own viewpoint
  mech in place (the BT_SPAWN_AT write pattern per frame) so every
  aspect passes the shooter's boresight; the operator watches this
  node's paper doll take the hits.
* BT_ZONE_WALK=<secs/zone> (shooter node): walks the target's damage
  zones in order, resolves each zone's carrier segment's live world
  position (BTResolveSegmentWorld + the new BTMechZoneSegAndName
  bridge), SERVOS the torso twist + aim elevation until the centered
  reticle ray (BTGetAimRay) points at the segment, fires 3 laser
  pulses, advances. [walk] ZONE/FIRE/HOLD on A pairs with [dmghit]
  zone/level lines on B.
* scratchpad/night10/zonewalk.sh: launch both + relay, map sed'd to
  grass/day, NO kill timer -- the session stays up for observation.

Hard-won servo constraints (documented in test-harness.md so they are
never relearned): the ENGAGE GATE (ray live + range<150 + bearing<1.1;
outside it RELAX the twist -- servoing at the twist limit while the
goto marches is a limit-clamp fight that visibly shakes the mech, and
a 0.55 gate deadlocks against the goto's ~0.55 resting bearing); YAW
POLARITY -1 (the twist cell's angular sense is opposite atan2(x,-z)
world yaw -- operator-observed live, the SECOND witness for the #124
SelectSlice twist-sign flip) with a divergence watchdog that
self-flips; damped correction (gain .40, cap .025/frame -- the aim ray
lags the twist write a frame); and a one-shot approach PORT to 100u
off the target instead of a cross-map march.

First live run: walker cycles zones, settles, fires; the target's
luleg climbed 0.458->0.523 under its own aimed pulses -- aimed shot,
correct panel, damage consumed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-08-03 10:04:03 -05:00
co-authored by Claude Fable 5
parent b0b7adc4ea
commit 16e75d6e1a
4 changed files with 341 additions and 1 deletions
+19
View File
@@ -1438,3 +1438,22 @@ void BTAmmoExplosionFanOut(
((Mech *)owner_mech)->AmmoExplosionFanOut(
(::Subsystem *)inflicting_subsystem, inflicting_subsystem_id, total_damage);
}
//
// #124 ZONE WALKER bridge: a zone's carrier SEGMENT index + name, complete-
// type TU (Mech__DamageZone). Replicant-safe -- the zone table streams on
// every instance, so the SHOOTER can enumerate its target's zones locally.
// Returns 0 past the end (the walker wraps on that).
//
int BTMechZoneSegAndName(void *mech_v, int zone_idx, int *seg_out, const char **name_out)
{
Mech *m = (Mech *)mech_v;
if (m == 0 || zone_idx < 0 || zone_idx >= m->damageZoneCount)
return 0;
Mech__DamageZone *dz = m->Zone(zone_idx);
if (dz == 0)
return 0;
*seg_out = dz->EffectSegmentIndex(); // public accessor (@0x194)
*name_out = (const char *)dz->damageZoneName; // engine base, public
return 1;
}