Gait: the AUTHENTIC walk lean -- interior/exterior clip sets, level cockpit + leaning mechs (task #59)

The MadCat (and every leg-mech) leans -8deg into a walk / -11deg into a run --
an authored jointhip (hingex) pose in the EXTERIOR gait clips that the walk/run
CYCLE clips never rebind, so it HOLDS.  The 1995 game keeps a separate INTERIOR
('i'-suffix) clip set for the mech you PILOT: those shake jointshakey (cockpit
rattle) and OMIT jointhip, so your own view stays level while everyone else sees
you lean.  The port had this entirely dead -- the local cockpit mech pitched
-8deg into the ground (user-reported "staring at the ground").

ROOT CAUSE (two stacked bugs):
- The authentic ctor clip-set gate (@part_012.c:10308-10320) was reconstructed
  as no-op stubs: LoadLowDetailBody/LoadHighDetailBody MISLABELED the
  FUN_004a80d4/86c8 GAIT-CLIP loader addresses as a "body LOD" pair, so the gate
  did nothing and a separate unconditional LoadLocomotionClips always loaded
  EXTERIOR clips.
- LoadLocomotionClipsExt (the interior loader) was a stub aliased to the
  exterior loader.

FIX:
- Reconstructed the real 4-char INTERIOR loader (byte-exact vs @004a86c8; the
  'i'-suffix table dumped from the exe @0x10d74d: swri/wwri/wwli/...; all 18
  base clips confirmed present in BTL4.RES for mad/blh/ava).
- Fixed the ctor gate: getenv("L4VIEWEXT") || (instanceFlags&0xC)==4 -> exterior
  (replicant / forced external view); else -> interior (local cockpit master).
  Removed the mislabeling no-op stubs.
- PORT ADAPTATION (MaintainViewClipSet, per-frame in PerformAndWatch): the port
  never sets the replicant COPY bit (all MP mechs build as local masters --
  heat-sim/scoring/torso-watcher-connect all run on both, by design), so the
  ctor gate lands everyone on interior.  Pick the set by VIEWPOINT instead: the
  mech you pilot keeps interior (level cockpit), every other mech flips once to
  exterior (the lean).  Reloads only on a viewpoint-status change; the sets
  share stride data so the swap is seamless.  Model pointers stashed at ctor.

VERIFIED live (BT_HIP_LOG probe): your walking mech writes jointhip=0 (level);
the peer's replica in the other pod's view leans at exactly -8.0/-11.1deg --
the authored clip values.  A/B control: L4VIEWEXT=1 forces the walking master
back to 74 sustained -8/-11 writes.

KB: locomotion.md ("NO walk lean" audit conclusion CORRECTED -- the lean is
authored + sustained + clip-set-specific), asset-formats.md (.ANI parses
pitch/yaw/roll for all joint types; KeyJointPos translation; cycle clips carry
no pitch), open-questions.md (item closed).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-13 14:46:22 -05:00
co-authored by Claude Fable 5
parent 02cdfd6576
commit 2e9c78d604
8 changed files with 348 additions and 39 deletions
+16
View File
@@ -198,6 +198,22 @@ Scalar
int ty = jt ? (int)jt->GetJointType() : 0;
if (ty < 3) // hinge
{
// task #59 discriminator (BT_HIP_LOG): log hinge writes so the
// jointhip walk-lean can be seen. EXTERIOR clips ramp jointhip
// to ~-8deg on stand->walk and hold it; INTERIOR ('i') clips
// never bind jointhip, so it stays silent. Sampled by joint
// slot so the stream stays readable.
if (jt && move_joints)
{
static const int s_hipLog = getenv("BT_HIP_LOG") ? 1 : 0;
if (s_hipLog)
{
const Radian ang = ((const Hinge *)cursor)->rotationAmount;
if (fabsf((float)ang) > 0.02f) // only the leaning ones
DEBUG_STREAM << "[hip] jointIdx=" << jointIndices[j]
<< " deg=" << ((float)ang * 57.2958f) << "\n" << std::flush;
}
}
if (jt && move_joints) jt->SetHinge(*(const Hinge *)cursor); // FUN_0041cfc8
cursor += 8;
}