context-system: complete migration -> CLAUDE.md is now a 160-line router (zero context lost)

Full migration of the 2236-line monolithic CLAUDE.md into the progressive-context
knowledge graph (per spark-lesson / expert-seed.md), so the deep RE knowledge loads
on-demand instead of every session.

ZERO CONTEXT LOST:
- docs/PROGRESS_LOG.md = the complete old CLAUDE.md, VERBATIM (byte-identical) -- the
  lossless safety net + the "full detail" quick-lookup fallback.
- 18 context/*.md topic files (1343 lines) digest every section (§1-3 -> project-overview,
  §4 -> content-archives, §5 -> asset-formats/bgf-format, §5a -> source-completeness,
  §5b/§8 -> wintesla-port, §7/§10 -> locomotion, §10a -> build-and-run, §10b ->
  reconstruction-method, §10c -> combat-damage + reconstruction-gotchas, §10d -> subsystems,
  render notes -> rendering, gauges -> gauges-hud, MP -> multiplayer, §9 -> open-questions).
- reference/glossary.yaml (53 terms). decomp-reference.md = the offsets/ClassIDs/addresses hub.

CLAUDE.md (160 lines) = router: identity, answer/reason protocols, quick-lookup table,
evidence tiers (T0 engine-truth / T1 decompiled+verified / T2 reconstructed+runtime /
T3 guarded / T4 hypothesis), conventions + DO-NOT (the systemic bug classes), structure.
Retains the load-bearing work directives (build recipe pointer, "keep current" mandate).

Knowledge graph validates CLEAN (scratchpad/checkctx.py -- all [[links]] + quick-lookup +
docs refs resolve; [[name]] -> topic file or glossary term). docs/*.md ledgers stay as the
detailed logs; context/*.md are the curated digests that route into them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-07 22:19:50 -05:00
co-authored by Claude Opus 4.8
parent 1cd57ade85
commit f914fc040a
18 changed files with 3208 additions and 2388 deletions
+83
View File
@@ -0,0 +1,83 @@
---
id: locomotion
title: "Locomotion — gait, the ground model, collision, shadow"
status: established
source_sections: "PROGRESS_LOG.md §7, §10 (gait/ground/collision/shadow); docs/P3_LOCOMOTION.md"
related_topics: [asset-formats, decomp-reference, reconstruction-gotchas, combat-damage, rendering]
key_terms: [RootTranslation, ground-model, SequenceController, MechControlsMapper, SLD, joint]
open_questions:
- "Authentic per-mech turn-rate constant (currently bring-up constant)"
- "Body-callback gimp handlers (states 16-19); airborne callbacks"
---
# Locomotion
Walking, the gait controller, the ground/collision model, and the shadow. All DEFAULT-ON now
(`BT_GAIT_CUTOVER`, `BT_GAIT_SM`, `BT_COLLISION`, `BT_REAL_CONTROLS` — set `=0` to fall back). Full
detail: `docs/P3_LOCOMOTION.md` + `docs/PROGRESS_LOG.md §7, §10`.
## Walk speed is animation-driven (not physics)
Each `.ANI` has a `[RootTranslation]` where **`.z` = forward root SPEED** (world units/s). The
engine `AnimationInstance::Animate(dt, move_joints)` integrates `movement += Δt·rootTrans.z` and
moves the body that far → feet plant by construction (no stride constant; k=1). Idle anims have
z=0. The `.MOD` physics governed thrust VEHICLES, NOT walk gait. [T1]
## The two-channel gait (real controls)
The BT `SequenceController` (`seqctl.cpp`, from `SelectSequence@004277a8`+`Advance@0042790c`) drives
locomotion. Under `BT_REAL_CONTROLS` two channels run:
- **LEG channel** writes the skeleton JOINTS from the live demand (a local sim; its joint writes are
overwritten by the body).
- **BODY channel** is the DISPLAYED motion — travel comes from the SAME Advance that writes the
displayed joints (`move_joints=1`), so display == travel BY CONSTRUCTION (v4 fix — killed the
desync class). [T2]
The gait STATE MACHINE (`AdvanceBodyAnimation`, mech2.cpp) slews `bodyCycleSpeed` toward the demand
through walk/run caps (`LoadLocomotionClips`, mech3.cpp:326 — measures `walkStride`/`standSpeed` via
`legAnimation.SelectSequence`). Transition callbacks (`Mech::BodyClipFinished @0x4a6d8c`,
`LegClipFinished @0x4a6928` — PE-parsed jump tables) alternate walk 6↔7 / run 12↔13 + walk→run. [T2]
**Aliasing bug class (namedClip):** `namedClip[]`@0x5e0 == `animationClips[]`@0x5cc+0x14 (ONE array);
`gimpBaseClip`@0x64c == `animationClips[0x20]`; `bodyAnimationState`@0x728 == `bodyStateAlarm.level`.
Declared-separate members don't see each other's writes — alias them.
## The AUTHENTIC 1995 ground model (default-on, `BT_GROUND_REAL`)
Decoded by the 10-agent `ground-model-decode` workflow (binary `FUN_004a9b5c` = the master perf).
**NO GRAVITY anywhere** — accelerations zeroed every frame. Vertical position = an ABSOLUTE per-frame
ground SNAP:
1. ctor lifts `collisionTemplate->minY` by 5% of volume X-width (the probe height + wall-vs-floor separation).
2. per frame `MoveCollisionVolume()` re-finds the containing node in the zone's **BoundingBoxTree**
(BOXTREE.cpp — NOT a heightfield).
3. probe `q = origin + (0, lift, 0)``FindBoundingBoxUnder(q, &h)` (h = distance down to the highest
solid top; 1 = miss).
4. snap gate `h > 1e-4`: `origin.y -= (h lift)` ⇒ y = surfaceY exactly. **MISS ⇒ NOTHING** (y holds,
no runaway). Up-slope bounded by the lift window (implicit step allowance); walk-offs drop instantly.
5. `GetCurrentCollisions``ProcessCollisionList``Mech::ProcessCollision` (@0x4abb40, vtbl+0x3c):
BoxedSolid resolver → StaticBounce → owner classification. Crushable icon (flags&0x8000) = damage
0.00123f sentinel = move stands; damage>0 = **FULL FRAME REJECTION** (walls block, never slide);
impactVel²>40 = crash-anim (SetLegAnimation(0x20)). [T2]
KEY: `FindSmallestNodeContainingColumn`/`FindBoundingBoxUnder` (`FUN_0040e36c`/`0040e5f0`, BOXTREE.CPP)
are ALIVE in the 2007 engine — the "heightfield" labels were wrong (caused two reverted attempts). A
master mech needs a **CollisionAssistant** (GetCurrentCollisions iterates it unchecked). BT solids
ship ZERO tiles (h never negative). [T2]
## Knockdown / crash + the desync/stutter fixes
Wall impacts iv²>40 (~6.3 u/s) bind the `bmp` stagger clip. Two documented bug fixes: (a) the
knockdown must stagger BOTH channels (`SetBodyAnimation(0x20)` + `SetLegAnimation(0x20)`) or display
+ travel split permanently (foot-slip); (b) a contact-hysteresis gate (0.4 s `gBlockCooldown`)
stops the knockdown re-firing on sustained/glancing contact. `localVelocity` is zeroed while crashed
(spec-faithful) so a knocked mech can't keep advancing. [T2]
## Controls (`BT_REAL_CONTROLS`, default-on)
`MechControlsMapper` (mechmppr.cpp @004afbe0; btl4mppr.cpp mappers) interprets input → `speedDemand`
/ `turnDemand`. ⚠ **WndProc NEVER receives WM_KEYUP** (the engine's per-frame reader `GetMessage`s
them out) → poll `GetAsyncKeyState` per frame, gated on foreground. Virtual controls: W/S sweep a
persistent throttle LEVER with a zero detent; A/D a momentary auto-centering stick. [T2]
## Shadow (default-on, `BT_SHADOW_TILT`)
BT 4.10's shadow is the flat `*_tshd.bgf` proxy drawn as blend-pass geometry, posed by `jointshadow`
(terrain tilt) + `jointtshadow` (torso twist). Terrain-tilt samples the collision surface gradient;
a depth-bias (`D3DRS_DEPTHBIAS`, decal-style) stops it z-fighting/vanishing on inclines. Polar maps
have STUB `*_tshd` (shadow authored-off on snow). Also the visual-ground conform (`btvisgnd.cpp`,
render-only lift to the visible terrain triangles — presentation only, never touches localOrigin). [T2]
## Key Relationships
- Detail: `docs/P3_LOCOMOTION.md`. Uses: [[asset-formats]] (SKL/ANI), [[decomp-reference]] (offsets).
- Feeds: [[combat-damage]] (collision→damage), [[rendering]] (shadow/visual-conform).