Files
BT411/context/wintesla-port.md
T
arcattackandClaude Opus 4.8 224092aaff KB: reconcile the context system with the day's work
- decomp-reference.md: the binary ATTRIBUTE-TABLE section -- 16-byte
  {id,name,off+1,0} row format (alignment warning), the walker technique,
  and the three recovered tables (Mech ids 21-56 incl the corrected
  EyepointRotation@0x360 / RearFiring@0x410 / DistanceToMissile@0x400
  labels; HeatSink 3-12; Torso 3-15; the weapon RearFiring 'b' marker).
- combat-damage.md: the REAR-FIRE + look-view system (roster survey: the
  Blackhawk's ERMLaser_2/3 are the game's only rear weapons; every missile
  rack forward), the missile mount-frame launch truth, and the BANKED
  full Missile flight-model decode (three performances, proximity fuse).
- wintesla-port.md: post-Phase-4 closures (instability model live, F14
  static filter baked, the footstep warm-up bug + its trace-cap lesson);
  deferred list trimmed to F21/HRTF.
- AUDIO_FIDELITY.md: status block -- F14 FIXED, warm-up bug noted.
- open-questions.md: "which mechs used rear fire" answered from data;
  remaining look-view key bindings noted.
checkctx: CLEAN.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-16 18:07:15 -05:00

13 KiB
Raw Blame History

id, title, status, source_sections, related_topics, key_terms
id title status source_sections related_topics key_terms
wintesla-port The WinTesla Windows Port — the base everything builds on established PROGRESS_LOG.md §5b, §8
source-completeness
rendering
build-and-run
multiplayer
WinTesla
L4D3D
MUNGA
RP
DPL

The WinTesla Windows Port

The Elsewhen RP411 archive is a working Windows port of the MUNGA engine (VS2005, WinTesla.sln). It means the hardest infrastructure is already solved — the bt411 build sits on top of it. Full detail: docs/PROGRESS_LOG.md §5b, §8.

What WinTesla already did (do NOT rebuild)

  • Renderer bypass: DONEMUNGA_L4/L4D3D.cpp + DXUtils replace libDPL / the IG board with Direct3D9. No libdpl.lib in the tree. (The early from-scratch D3D9 viewer was retired and removed.) [T1]
  • Audio: BACKEND now REAL + soundbank loaded; only game-triggering remains [T2, updated 2026-07-15]. OpenAL replaces the HMI "SOS" engine and the renderer→device→buffer→source→play chain IS all implemented (L4AUDRND/L4AUDRES/L4AUDLVL; PatchLevelOfDetail::PlayNote really calls alSourcePlay). The "no sound, ever" root cause was DEEPER than a gate — both audio backend DLLs shipped in engine/lib/ were no-op STUBS: (a) libsndfile-1.dll exports 15 funcs BY ORDINAL ONLY (no names), sf_open() always returns NULL; (b) OpenAL32.dll (72KB) imported only KERNEL32 — no dsound/wasapi/winmm — so it returned fake handles (ctx=0x00000001, alGenSources→0) and never touched the hardware. So the chain ran clean and silent. FIXES (commit 5b46655): OpenAL32.dll → real OpenAL Soft 1.25.2 Win32 (drop-in: the exe imports the 25 AL funcs by NAME; alSourcePlay now reaches AL_PLAYING). libsndfile DROPPED — replaced by LoadWavPCM() in L4AUDRES (a tiny in-tree RIFF/WAVE fmt+data reader, no external dep). Gates fixed earlier: the AWE_FRONT/AWE_REAR env-var gate in MakeAudioRenderer was relaxed to default-on (BT_NO_AUDIO=1 disables). Soundbank recovered: 241 samples cracked from AUDIO1/2.RES (SF2 v1.0) by tools/sf2extract.pycontent/AUDIO/*.wav + the allPresets[2][128] table (audiopresets.cpp, replacing the zero-init btstubs stub); all 241 load (alErr=0). In-game triggering now WORKS (commit 7b1e469): enabling audio unlocked L4AudioRenderer::CreateEntityAudioObjects, which binds AudioStateWatchers to entity/subsystem state attrs BY NAME (the attribute-pointer databinding, same as gauges) and calls AddAudioWatcher on the resolved StateIndicator. The reconstruction had pointed the Mech's state attrs at the scalar read-pad attrPad (fine for a gauge that READs a value, fatal for a state watcher that calls a METHOD → AV in SChainOf::Add on 0xCDCDCDCD). FIXED: the Mech's AnimationState/ ReplicantAnimationState (driven from SetBodyAnimation) and CollisionState (driven from ProcessCollision via collisionTemporaryState) are now real StateIndicator members — verified: walking fires SetupPatch+PlayNote/alSourcePlay (footstep/gait patches 78/80/116). So mech movement/animation/collision audio is live. Subsystem STATE audio DONE (commits 5ba541e/0e05a22/dcdd7dd): the audio watcher TYPE per attribute was recovered via a MakeObjectImplementation ClassID trace (class 28 = AudioStateTrigger/StateIndicator). KEY: 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, level@0x14 = currentState. The reconstruction had modeled that tail as an opaque _tail (never constructed → AddAudioWatcher AV'd on 0xCDCDCDCD). FIX: GaugeAlarm54 now has three REAL constructed sockets + AddAudioWatcher; SetLevel fires them on change (empty sockets = no-op, so other alarms/weapons unaffected; levelB/LevelCountB untouched; sizeof stays 0x54). Then registered each state attr → its subsystem's own alarm (own AttributePointers[] chained to the parent): Generator.GeneratorState→stateAlarm, Condenser.CondenserState→condenserAlarm, Reservoir.ReservoirState→reservoirAlarm, AmmoBin.AmmoState→ammoAlarm (+ chained AmmoBin's bare index so SimulationState resolves too). GeneratorOn→generatorOn. audiostate skips 85 → 0 — every StateIndicator audio attribute across the mech + all subsystems binds to a real indicator, and the alarms are already SetLevel'd by the sims, so generator/condenser/reservoir/ammo state sounds fire on transition. Still inert (read 0, silent, non-crashing — no modeled backing member in the size-locked layouts, a polish follow-up): ReportLeak (Logical), Torso.MotionState (Enum), Torso.SpeedOfTorsoHorizontal (Scalar). NOW REAL (fidelity Phase 1, commit fc7f311): ConfigureActivePress published at the MechSubsystem BASE (binary attr id 2, descriptor @0x50de5c → member @+0x110 — the field previously misnamed vitalSubsystemIndex; idle 1, driven 0/1 by MechWeapon::ConfigureMappablesMessageHandler), AmmoBin.FireCountdownStartedcookOffArmed@0x18C, L4MechControlsMapper.TargetRangeExponenttargetRangeExponent@0x1a4. The bring-up guards [T3, self-clearing] stay: a NULL subsystem attr → inert pad (was a fatal Fail); an AudioStateWatcher on an unconstructed indicator (chain@+0x18 null/0xCDCDCDCD) → skip. Both pass automatically once a subsystem is built. Diagnostics: BT_AUDIO_LOG (chain + skips/redirects), BT_ATTRBIND_LOG (every attr bind), BT_AUDIO_TEST (proof-of-life buffer0).
  • Audio FIDELITY pass (2026-07-16, commits fc7f311 + 691e885; the full audit ledger is docs/AUDIO_FIDELITY.md, 37 findings). Settled facts [T1 unless noted]:
    • Patch numbering = SF2 wPreset. Any tooling must key presets on wPreset, never on phdr record order. AUDIO1/2.RES are SF2 v1.0 (16-byte shdr, NO name/rate/pitch field); pitch metadata rides generators: 55 = SBK samplePitch (root*100+cents, on every zone), 58 = overridingRootKey, 51/52 = coarse/fineTune. EMU8000 v1 base rate = 44100 Hz → a zone's true data rate is baked into its WAV: rate = round(44100·2^(((6000rootCents)+tune)/1200)) (tools/sf2extract.py); the engine's note-60 pitch model (BTNotePitchFactor) then reproduces original playback at every note. SBK initialAttenuation(48) is INVERTED (127 = full volume; 0.375 dB/step [T3 exact curve], baked into the PCM).
    • Full-zone table: 603 zones / 241 presets in audiopresets.cpp; the authored MIDI note SELECTS zones by keyRange in SetupPatch/PlayNote (key-splits: Loaded/Jam family low-36 clunk vs high-84 blip; Warnings01 8-way klaxon split), layers attach together, MAX_PRESET_SAMPLES=25 (AllExplosion). Authored loop REGIONS apply via AL_SOFT_loop_points; authored releaseVolEnv (1.13.9 s on ~20 looping presets) fades on Stop (PRESET_serviceReleaseFades, serviced from AudioHead::Execute).
    • Distance/volume/doppler: OpenAL distance model is AL_NONE — the AUTHORED GetDistanceVolumeScale() curve multiplies in CalculateSourceVolumeScale (Dynamic3D + Static3D); per-source AL_GAIN = volume_scale² (GM CC7 squared law); alDopplerFactor(0) — the authored GetDopplerCents() (AUDIO.INI model, consumer decomp part_008.c:7466) adds into the Dynamic3D pitch chain.
    • Audio clock: FUN_0044e19c is ApplicationManager::GetFrameRate — the original audio "frames" were SYSTEM CLOCK TICKS; MakeAudioRenderer calibrates at SystemClock::GetTicksPerSecond() (fallback 1000), never the old garbage divisionParameters+0x10 read.
    • Published localVelocity smoothing is authentic [T1]: Mech::Execute (FUN_004ab430) runs the localVelocity components through AverageOf running-average filters (part_012.c:15169-15179); the port's ~0.25 s exponential filter in mech4.cpp reconstructs it.
    • Phases 3+4 SHIPPED (2026-07-16, commits 0ca7d26..0e2401f). Phase 3 EFX: L4AUDEFX bridge — per-source lowpass (Dyn3D = highFreqCutoffScale×brightness UNGATED, Static/Direct = brightness; AWE 1008000 Hz → 5 kHz-ref gainhf [T3 curve]), one EAXReverb slot at global_reverb_scale 0.3 (3D wet / cockpit Direct dry), Direct position-enum placement. Phase 4 attributes (all [T1] from binary attribute tables, walked as 16-byte {id,name,off+1,pad} rows): HeatSink table @0x50e438 (ids 3..12) confirms every heat binding + adds ReportLeak id 12 @0x138 = coolantActive (serves all 19 leak watchers via PoweredSubsystem⊂HeatSink); Mech table @0x50c0xx (ids 21..56): IncomingLock@0x3fc / DistanceToMissile@0x400 (real members, Missile::MoveAndCollide reports, PerformAndWatch latches; old maxSpeed@0x400 was a misread of the FLT_MAX far default), CollisionSpeed@0x4B4 (=|impact velocity| at contact-arm), ReduceButton@0x340, FootStep@0x394, RearFiring@0x410 (old stateFlags misread); Torso table (ids 3..15): full publish onto existing members (SpeedOfTorsoHorizontal=twistVelocity@0x1E8 abs'd, MotionState=statusFlags@0x20C, ==2 = limit-hit frame). F5 footStep = CONTACT LEVEL: (jointlocal.y <= *ANI hdr[2] threshold) per frame, states 0/1 retain (SelectSequence now captures hdr[2]; the 150 ms pulse is retired). F19: the authored footstep volume = LocalAcceleration |lin| [0,10]→ctl100 + LocalVelocity |lin| [0,0.6]→ctl101 (ALL motion watchers extract |linearMotion|, motionValue=3); localAcceleration.linear = d(published velocity)/dt (binary part_012.c:15186-15195); the mech2.cpp step broadcast is REMOVED. attrnull count = 0 — every authored audio attribute binds a real member.
    • Post-Phase-4 closures (2026-07-16): UnstablePercentage is LIVE (the instability model @0x3F0 byte-decoded + reconstructed — accel-sway² + gun-the-engine + turn-in-place terms, feeds gyro swayBias + the audio alarm; commit c51d64a). The F14 per-zone static resonant low-pass is BAKED (RBJ biquad at the AWE 1008000 Hz curve, float pipeline + peak normalization; 232 zones incl the LaserLoaded charge hum fc=57 Q=87; c581553). The footstep 1020 s warm-up bug is fixed (a11a697): an idle source's watcher chain executes only at Start attempts and each hop is audio-frame-gated, so the authored fill-0 N=30 smoothers starved behind the 0.3 transient drop gate — fixes: AudioScaleOf sends EVERY poll (the bitwise change-gate froze on our deterministic gait floats), recursive gate-free Component::PrimeWatchers(30) on every transient Start request (AUDREND), and localAcceleration via the binary's exact 15-sample ring buffers. LESSON: trace caps saturate early and fake "per-stride" rates — always timestamp before inferring cadence.
    • Still deferred: F21 attack velocity/time (all captured events were default 1), F22 HRTF (user has 2 speakers; enable via alsoft.ini hrtf=true for headphones).
  • L4 HAL on Windows + the VS build system: DONE. [T1]
  • Red Planet game logic: COMPLETE & buildableVTV/VTVMPPR/WEAPSYS/.... RP is at/near playable. [T1]
  • Multiplayer: the DOS NETNUB driver is already replaced by a ~3.5k-line WinSock2 TCP reimplementation (MUNGA_L4/L4NET.CPP) + the master/replicant distributed-sim core. See multiplayer. [T1]

What BT still needs (the only remaining work below the game layer is NONE)

Everything below the game layer — engine, renderer, audio, HAL, build — exists and is shared. The ONLY thing BT needs is its game-logic source, which is gone (see source-completeness) → it must be reconstructed, with the three anchors (BT headers + the WinTesla engine to compile against + RP's parallel code + the binary oracle). [T2]

Build implications

  • WinTesla.sln is VS2005 and hard-depends on the legacy DirectX SDK (June 2010) (d3dx9, dinput, dxerr — all removed from the modern Windows SDK). The DXSDK is installed at C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\. [T2]
  • The shared engine builds GREEN to munga_engine.lib via CMake/MSVC Win32 (see build-and-run). Recipe gotchas (include-path shadowing, the CAMMGR/time.h fixes, the ATL shim) are in docs/PROGRESS_LOG.md §8. [T2]

Roadmap position

Old plan ("build a libDPL shim + port the engine") is superseded — WinTesla did it. New plan: reuse the WinTesla engine (shared) + reconstruct the BT game library (BT410_L4 + game logic). The from-scratch libDPL shim is no longer needed. Phases 4-8 (BT game layer + pod bring-up) still apply. [T2]

Key Relationships