5b8c814029798df31b7a7356593af65263252001
5
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9dcb4752de |
Audio Phase 4c (AUDIO_FIDELITY F17/F19): impact scaling + the authored footstep feed
F17 CollisionSpeed (binary id 24 @0x4B4): real member captured as |worldLinearVelocity| when the contact accumulator arms (0->1) -- the authored AttackVolume [0.9,1] / Brightness [0.7,1] scales over impact speed [0,25] now make harder hits sound louder and brighter. ReduceButton (id 46 @0x340): real watchable member (the keyboard rig never presses it). UnstablePercentage stays deferred: its sway/overspeed model @0x3F0 is the known gyro-ledger gap (live writer unexported); binding without the model would be a stand-in. F19 footstep feed (the invention is dead, long live the authored chain): new [motionscalecfg/motiontrigcfg] traces recovered the authored configs -- EVERY motion watcher extracts |linearMotion| (motionValue=3); the footstep volume mixer is fed by LocalAcceleration [0,10] -> ctl100 (per-stride kick) + LocalVelocity [0,0.6] -> ctl101 (0.4 base while moving). The port never wrote Mover::localAcceleration, so ctl100 read 0 and the old mech2.cpp step-intensity broadcast (patch-sniffing, invented curve) fought the live authored scale. Now: localAcceleration.linear = d(published velocity)/dt -- EXACTLY the binary's derivation ((avgVel - prev)/avgDt into +0x1e4, part_012.c:15186-15195) -- and the broadcast is REMOVED. Regression (30s, walk throttle): stable; footfalls deliver through the wholly-authored chain with per-stride VARYING gains (0.61/0.72/0.62 -- real step dynamics, impossible under the old constant-curve invention). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
99757a947d |
Audio: footstep chain traced to the END -- gait VINDICATED; audio clock 18x unit mismatch found (task #50)
MAJOR RESULT -- THE GAIT IS CORRECT, the enum was mislabeled: LoadLocomotionClips (binary-verified slot map) proves namedClip==&animationClips[5]: clips 6/7 = wwr/wwl (WALK cycle), 12/13 = rrr/rrl (RUN cycle -- what autodrive uses at full throttle), 10/11 = wrr/wrl, 14/15 = rwr/rwl, 16-21 = reverse set. The mech2.cpp "MechAnimationState" enum (0x3c-stride name table) does NOT match the runtime clip ids -- it is the mislabel (12/13 are NOT StandToReverse). The authored AudioStateTriggers on AnimationState (statecfg dump: states 1,2,5,8,9,10,11,14,15,16,17,20,21,22,23,26,27 -> Start) align EXACTLY with the TRANSITION clips under the true map; the CYCLING strides (6/7, 12/13) have no state triggers because the FootStep pulse attribute serves them -- our FootStep reconstruction is the authentic design. DO NOT renumber the gait. Footstep chain, fully mapped (all empirtical): pulse -> AudioMatchOf(match=1) -> Start on the FootFall DirectPatchSource -> DROPPED at volume 0. Volume path: an AudioControlMixer (2 inputs, never fed) <- an AudioControlSplitter <- AudioControlSequence timeline events. The sequences DO fire -- but only value-0 events (the tick-0 initializers); the later (real-volume) events never land. NEW ROOT-CAUSE CANDIDATE [T3]: audio clock unit mismatch. The renderer is constructed with DefaultRendererRate=30 (calibrationRate: Seconds_To_Frames = s*30) but AudioHead::Execute sets audioFrameCount = Now().ticks which advances ~550/s (measured via the [audioclock] probe) -- sequence event scheduling runs ~18x off the authored timing. Fix candidate: calibrate the audio renderer to the actual Now().ticks rate (or drive audioFrameCount at the calibrated 30/s). Also corrected en route: FUN_004b9550/95b8 are MechWeapon ConfigureMappables/ ChooseButton (mapper EnterConfiguration +0x38), NOT Myomers::ConnectToMover; +0x31c there is fireImpulse. Myomers::speedEffect has NO binary writer found beyond the ctor 1.0f (its 'mover coupling' stand-in is spurious). Diagnostics added: [statecfg] AudioStateTrigger ctor dump, [split] splitter forwards, [seqev] sequence timeline events, [audioclock] frame-rate probe. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
5ba541ed56 |
Audio: subsystem STATE sounds -- GaugeAlarm54 IS a StateIndicator; register Generator/Condenser/Reservoir state (task #50)
The audio subsystem binds AudioStateWatchers (class 28) to per-subsystem state attrs (GeneratorState/CondenserState/ReservoirState) BY NAME. Recovered the watcher TYPE per attribute via a MakeObjectImplementation ClassID trace. Root cause of the subsystem-state crash: the binary's 0x54-byte subsystem alarm (FUN_0041b9ec, reconstructed as GaugeAlarm54) IS a StateIndicator -- its "three sub-indicators" @0x18/0x2c/0x40 are the audio/video/gauge watcher SChains, and level@0x14 is currentState. The reconstruction had modeled that tail as an opaque `_tail`, so the sockets were never constructed -> AddAudioWatcher AV'd on 0xCDCDCDCD. - GaugeAlarm54: give it the three REAL, constructed SChainOf<Component*> sockets + AddAudioWatcher/Video/Gauge; SetLevel now fires the watchers on a level CHANGE (empty sockets = no-op, so the ~all other alarms are unaffected). levelB (weapon LevelCountB "reset source") is left untouched -- weapons unchanged. sizeof stays 0x54 (static_assert holds -> SChainOf<Component*> is 0x14, layout exact). - Register the state attrs -> the subsystem's own alarm (own AttributePointers[] chained to the parent): Generator.GeneratorState->stateAlarm, Condenser. CondenserState->condenserAlarm, Reservoir.ReservoirState->reservoirAlarm. Those alarms are already SetLevel'd by the sim, so the state audio fires on transition. - AudioStateWatcher guard now validates the +0x18 SOCKET (what AddAudioWatcher touches), not the +0 vtable -- GaugeAlarm54 is non-polymorphic at +0 (raw header) but has a real socket at +0x18. audiostate skips 85 -> 10 (only AmmoBin AmmoState/SimulationState left). The Logical/Scalar/Enum subsystem attrs (ReportLeak/GeneratorOn/ConfigureActivePress/ MotionState/SpeedOfTorsoHorizontal/TargetRangeExponent) stay inert (read 0, silent, non-crashing) -- they need backing members in size-locked layouts (a polish wave). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
7b1e469ffa |
Audio: in-game TRIGGERING works -- real StateIndicator attrs + audio-watcher databinding (task #50)
Enabling audio unlocked L4AudioRenderer::CreateEntityAudioObjects, which binds AudioStateWatchers to entity/subsystem state attrs BY NAME (attribute-pointer databinding) and calls AddAudioWatcher on them. The reconstruction pointed the Mech's state attrs at the scalar read-pad `attrPad` (fine for gauges that READ a value, fatal for a state watcher that calls a METHOD) -> AV in SChainOf::Add on 0xCDCDCDCD. Root-caused via cdb + a BT_ATTRBIND_LOG trace in AttributeWatcher. Mech-level state audio now REAL + driven (verified: walking fires SetupPatch + PlayNote/alSourcePlay, patches 78/80/116): - AnimationState (0x1f) / ReplicantAnimationState (0x20): real StateIndicators (0x21 states covering MechAnimationState 0..0x20), driven from SetBodyAnimation so footstep/gait/transition sounds fire on animation change. - CollisionState (0x16): real 4-state StateIndicator driven from ProcessCollision via collisionTemporaryState (the deferred @4aa741 per-frame zero + the part_012.c:15406-15413 contact tail, InitialHit accumulation; the 1-vs-2 Slide split awaits the 0x240/0x244 floats still stubbed by fieldAt()). - @0x44c CORRECTED: "ammoState (0/1 leaking/2 dry)" was a mislabel -> it is collisionTemporaryState (never read as ammo). Bring-up guards [T3, temporary, self-clearing] so audio-on is STABLE while the subsystem state models are still stubs (Generators/Condensers/Myomers/Torso/ Avionics/Reservoir/ControlsMapper -- ~15 subsystems, ~40 attrs: GeneratorState, CondenserState, ReportLeak, ...): a NULL subsystem attr redirects to an inert pad (was a fatal Fail); an AudioStateWatcher on an unconstructed StateIndicator (null/ 0xCDCDCDCD) skips instead of AV. Both pass automatically once the subsystem is reconstructed. Those subsystem sounds stay silent until then (their audio wave). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
7b7d465e5e |
Initial commit: bt411 -- standalone Windows BattleTech (Tesla 4.10 port)
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>
|