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>
4.0 KiB
4.0 KiB
id, title, status, source_sections, related_topics, key_terms
| id | title | status | source_sections | related_topics | key_terms | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| asset-formats | Asset Formats — MOD/SKL/ANI/BMF/BSL/textures/gauges/collision | established | PROGRESS_LOG.md §5; docs/ASSET_PIPELINE.md; docs/BGF_FORMAT.md |
|
|
Asset Formats
All reverse-engineered. Geometry (BGF) has its own topic (bgf-format); the full pixel/material
spec is docs/ASSET_PIPELINE.md. Full list: docs/PROGRESS_LOG.md §5.
Definition / skeleton / animation
.MOD— INI mech/object definition: skeleton, skins, collision, gauges, physics, animations, class. The.MODphysics (MoverMass/drag/MaxAcceleration) governed thrust VEHICLES + collisions, NOT walk gait (locomotion). [T1].SKL— INI joint skeleton.[joint] parent=, Type=(hingex/y/z|ball|balltranslate), Object=part.bgf, dzone=, tranx/y/z, pitch/yaw/roll. Build a DCS tree; neutral pose ≈ translations (pyr≈0). [T1].ANI— INI keyframe animation.[HEADER] framecount/framerate(30)/skeletonfile;[frameN]joint→pitch yaw rollradians for EVERY joint type (ANIMTOOL.cpp:140-142 parses the triple as EulerAngles unconditionally — the old "balltranslate→translate" note was wrong [T0]); a balltranslate joint ADDITIONALLY gets a per-frame translation from the separate[KeyJointPos]section (ANIMTOOL.cpp:478-483 packs EulerAngles+Vector3D; JMOVER/seqctl apply SetRotation + SetTranslation). For the rootjointlocal, KeyJointPos.y = the gait vertical bob;[RootTranslation]per-keyframex y zwhere.z= forward root SPEED (units/s). Walk anims have no baked root translation — forward motion is animation-driven from.z(locomotion). Walk/run CYCLE clips author NO body pitch — root keys are a ≤1.5° roll sway only; the authored LEAN lives in the transition (rwl/rwr/wrl/wrrjointhip ~7-12°) +bmpstagger (~25°) clips (2026-07-13 sweep of all 331 source ANIs). [T1]
Materials / textures
.BMF—DIV-BIZ2(FILETYPE=1) material+texture LIBRARY (no pixels). Material → DIFFUSE colorMATERIAL_TEXTURE→texture→TEXTURE_MAPimage basename. Tags:0x18 BITSLICE(BSL slice select),0x28ramp ref,0x26emissive,0x30/0x31ramp def. [T1]
- Texture pixels:
.tga(Truevision),.vtx(DIV-VTX2, trailing RGB), and.bsl(DIV-BSL2— a BIT-SLICED container: w*h 32-bit texel words holding SIX independent 4-bit GRAYSCALE sub-images (nibble pair-swapped, byte 0 pad) OR RGB444/RGBA4444 (sliceType 7/8). The BMF0x18 BITSLICEtag picks the slice, absent=0). Decoding BSL as RGB = the "rainbow/graffiti mech" bug. Reference reader:DivLoader/VGCDivLoader.cpp:323-410; archive-only — in-repo reimplementation:engine/MUNGA_L4/image.cpp. [T2] .VMF—DIV-VIZ2material SOURCE. Carries theSCROLLanimation +MAP{}image binding for effects (beams/muzzle/smoke/sky). THE key effects asset (rendering). [T2]- material-ramp — the IG board colours no-normal geometry by a 2-endpoint RAMP; details in bgf-format + rendering. [T2]
Collision / damage / subsystems
.SLDcollision solids (Block/YCyl/Cone/Ramp/Wedge). Terrain is modeled AS collision volumes; see locomotion ground model + combat-damage. [T1].DZM= INI damage-zone→material map (mech skin damage states)..DMG/.TBLdamage zones/tables,.SUBsubsystems (weapon params — DischargeTime/RechargeRate/WeaponRange),.CTLcontrol maps. [T1]
Cockpit HUD assets (gauges-hud)
.GIMvector MFD/radar line maps +.GATcolor table;.PCCZSoft PCX 8-bit gauge rasters (fonts helv15/helv42, label strips, dials). [T1]
Key Relationships
- Geometry detail: bgf-format; pixel/material spec:
docs/ASSET_PIPELINE.md. - Consumed by: rendering, locomotion (SKL/ANI), combat-damage (SLD/DZM/SUB), gauges-hud (GIM/PCC).