Footstep chain progress (each step empirically verified):
- The FootStep watcher is an AudioMatchOf<Logical> (AudioLogicalTrigger extends
AudioMatchOf, NOT AudioTriggerOf): authored config match=1 -> Start(2.0) on a
DirectPatchSource. [trigcfg]/[matchcfg] ctor dumps added.
- The pulse was pinned at 1: the decay lived in IntegrateMotion, which the
current gait path NEVER CALLS. Moved to Mech::PerformAndWatch (provably
per-frame) with a time-based 150ms window sized to the ~10Hz watcher poll.
The matcher now fires per stride (14/run, was 1).
- Every footstep Start is DROPPED at the renderer: the source's volumeScale is
0 (five VolumeAudioHandler sends of exactly 0 = inert/one-shot primes). The
volume arrives through the authored control chain (AudioControlMultiplier
inputs ctl 100+; one 0 input pins the product). Chain scales identified on
this entity: LocalVelocity (live), LocalAcceleration (live), Myomers.
SpeedEffect (=1.0 healthy; one authored scale maps [0,1]->[1,0] INVERTED),
UnstablePercentage (INERT PAD -- always 0!), HeatSink.CurrentTemperature.
PRIME SUSPECT: an UnstablePercentage-fed multiplier input primes 0 once and
never updates (the pad never changes), pinning footstep volume at 0.
- SF2 numbering fact recorded: 38 presets in AUDIO1 / 5 in AUDIO2 have
wPreset != file index (gap at preset 77); my table keys by wPreset. The
184x ProgramButton01 (bank1 patch83) storm at ~7/s needs an identity check
against index-numbering (it may be the wrong sample for that patch id).
Diagnostics added (BT_AUDIO_SPATIAL/BT_ATTRBIND_LOG): [trigcfg]/[matchcfg]
ctor dumps, [matchfire] with component ptr+class, [volset] VolumeAudioHandler,
[mult0] multiplier zero-products, scale sends with authored boundaries,
[fswatch] dedicated footstep watcher tracer (g_btFootStepAddr), SetupPatch
ENTRY with bank/patch/state, Simulation::DebugAudioWatcherCount.
NEXT: back UnstablePercentage with a real (live) member -- it is the mech's
stability 0..1 (the stabilityAlarm/gyro family) -- or confirm via a one-run
chain dump which multiplier input pins the FS source; then the footstep
transient should clear the 0.3 drop gate at walking speed.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
User: "when I start moving all the sounds fade away, no footsteps." Diagnosis
chain (all empirical, BT_AUDIO_SPATIAL/BT_ATTRBIND_LOG traces):
- The audio head DOES track the mech (listener-relative positioning verified
while driving) -- not a spatial bug.
- The idle sounds correctly STOP on leaving the standing state; the MOVING
sounds never started because every POLLED audio watcher was dead:
the reconstructed Mech::PerformAndWatch replaced the engine performance but
dropped the ExecuteWatchers() step from the engine tail (Simulation::
PerformAndWatch = Perform -> ExecuteWatchers -> WriteSimulationUpdate).
Only PUSHED StateIndicator watchers (SetState->Execute) ever fired -- which
is exactly why state sounds worked but footsteps/motion-scaled audio didn't.
FIX: poll ExecuteWatchers() (AreWatchersDelayed-gated) before the update
write. Immediately unlocks the polled family: MissileLoaded01/LaserLoaded01
ready dings, ProgramButton01, motion scales (PlayNote 15 -> 30 per run).
- FootStep (0x1e) backed REAL: was the inert attrPad (an AudioLogicalTrigger
polls it -- threshold-crossing pulse per foot plant). New footStep member,
pulsed by SetBodyAnimation on entering any locomotion clip 1..0x17 (runtime
stride alternation MEASURED as body states 12<->13 -- the enum-name numbering
does not match runtime clip ids), decayed by IntegrateMotion (~1/3 s).
- Footstep volume is speed-scaled (AudioMotionScale on LocalVelocity): at
standstill the transient start computes volume 0 and the renderer drops it
(LowAudioVolumeThreshold) -- so footfalls are audible at real walking speed.
Diagnostics kept (BT_AUDIO_SPATIAL): spatial dist/vol per source, CLIPPED/DROP/
START at the request gate, vol=0 factor breakdown, scale->0 sends, trigger
notifications, watcher poll-rate probe.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Clean, self-contained extraction of the BattleTech-specific work from the
reverse-engineering workspace -- engine + game + content + build, with nothing
from Red Planet or the raw archive dumps. Builds green (Win32) and runs the
single-player drive->animate->target->fire->damage->destroy loop out of the box.
Layout:
engine/ MUNGA + MUNGA_L4 shared 2007 engine, carrying our BT render/loader
work (bgfload/L4D3D/L4VIDEO: BSL bit-slice decode, LOD/ground/shadow
models) + image codec; the minimal rp/ headers the audio HAL needs
game/ reconstructed BT logic + surviving-original BT source + fwd shims
+ WinMain launcher
content/ full runtime tree (BTL4.RES, VIDEO/, GAUGE/, AUDIO/, eggs, BTDPL.INI)
docs/ format specs + reconstruction ledgers
reference/ raw Ghidra pseudocode (recon source-of-truth) + decomp exporter
tools/ MP console emulator + map/resource scanners
One top-level CMake builds munga_engine lib + bt410_l4 game lib + btl4.exe.
All paths relativized (186 fwd shims + ~437 CMake abs paths -> repo-relative);
DXSDK is the one external, overridable via -DDXSDK. Verified: builds to a
byte-identical 2.27MB exe and runs combat (TARGET DESTROYED, 0 crashes) against
the bundled content.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>