teleport-poisoned finite difference, not heat, not the reset, not velocity
The one-line fix is the binary's own SECOND Reset instruction, dropped in
transcription: FUN_00408440(mech+0x58c, param_2) ==
accelPrevPos = origin.linearPosition;
+0x58c is the previous-position memory of the AccelerationLastFrame ring feed
(+0x81c/0x824/0x828/0x82c). The port reconstructed the ring faithfully (ctor
part_012.c:9836, derivative :15169) but Reset never re-seeded its cache, so the
first post-respawn sample computed |newPos - prevPos|/dt = TELEPORT DISTANCE/dt
(~1e5) into the velocity ring; the ring-mean derivative spiked
AccelerationLastFrame (pure forward, with an opposite-sign echo ~15 frames later
as the sample rotated out of the 15-ring); and the myomer integrator @004b8d18
turned it into a one-tick pendingHeat deposit of ~3e9:
termAccel = (1-accEff) * |v| * |a| * m * dt
= 0.2 * 40 * 1.04e5 * 75000 * 0.044 = 2.75e9
snapping the freshly-reset myomers from T=77 to T~9000 against failT=2000 ->
speedEffect 0 -> speedDemand *= 0 -> "respawned unable to move until it cools".
WHY ~8% IN THE FIELD: the deposit needs |v| in the same 1-2 frames, so only
pilots whose throttle was still forward at the respawn -- physical lever /
HOTAS, exactly who reported it -- had gait-republished speed in the spike
frames. Idle-throttle respawns deposit ~nothing. (And frozen-subset-of-
died-hot: died hot == was running hard == lever still forward.)
MEASURED, same abusive bench (0.95 throttle + continuous autofire):
before: deposits up to 3.35e9, every one 3-4 lines after a Mech::Reset;
4-6 of 7 respawns frozen; post-reset myomers T 7700-12100
after: deposits >1e7: ZERO across 7 respawns; frozen: ZERO;
post-reset myomers T 77-178 (vs degradeT=1000)
THEORIES KILLED ON THE WAY, each by operand data, in order:
* stale pendingHeat carryover (bounded to 1 frame, +1.2K -- gates agent)
* slow accumulation during the death window (consumers tick the wreck)
* conduction from a hot neighbour (roster-wide snapshot: ALL partners 77;
flow trap: zero e6 flows into the myomers, ever)
* drag/impulse writers (both trapped: never fired)
* my own earlier "velocity-driven, players accelerate to top speed" close of
the ticket -- arithmetically impossible (input ceiling ~6.5e5/frame ~=
60 deg/s; the observed snap was 1,100-21,000 deg/s) and corrected in
context/subsystems.md, which carried the wrong paragraph.
* the localAcceleration zero-fill (+0x1dc) restored along the way is KEPT --
the binary does it -- but it was NOT the cause; the snapshot is rebuilt
from the position difference one frame later.
Probes kept (all BT_HEAT_LOG-gated): roster-wide [myofreeze] at-death/at-reset/
post-reset (T + heatEnergy + pendingHeat per subsystem), the [heatflow]
conduction trap with full operands, the [myodep] deposit trap with mech
identity + acceleration components. Engine MOVER.cpp traps reverted -- they
proved their negative (drag/impulse innocent) and do not belong in engine
source.
Gotcha #30 records the class: when the binary's Reset writes a cell you don't
recognize, that write IS the spec -- transcribe the whole zero/seed list; any
prev-value cell backing a finite difference must be re-seeded at every
teleport; and derived state (T) sampled at the reset proves nothing about the
backing producers.
The operator called the shape of this two days ago: "maybe the math gets screwy
in respawning while some systems are ticking while values are being reset."
That is precisely what it was.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018SgmXGNMXavXiafKXf9MDC
BattleTech 4.11 (bt411)
A standalone Windows port of Virtual World Entertainment's arcade BattleTech (Tesla platform, release 4.10, ~1995–96), reconstructed on the shared RP411 Windows engine. The game boots, renders, and runs a single-player drive → animate → target → fire → damage → destroy loop across all 8 maps, with two-instance multiplayer entity replication working.
This repo is a clean, self-contained extraction of the BattleTech-specific work from the larger reverse-engineering workspace — engine + game + content + build, with nothing from Red Planet or the raw archive dumps. It builds and runs out of the box.
License: the game content (
content/) and the original binary are proprietary to Virtual World / the pod owner. This repository is private; do not redistribute.
Versioning
4.10 = the 1995 arcade release. 4.11 = this win32 reconstruction. Dev builds are
4.11.<build> where <build> is the git commit count — monotonic and zero-maintenance —
plus the short commit hash (4.11.311 (980c9cd)); a trailing + on the hash means the exe was
built from an uncommitted working tree. The stamp regenerates every build
(tools/btversion.cmake → build/btversion.h) and shows in the boot banner (btl4.log line 2)
and the window title. To identify any player's build, ask for the title bar or the top of their
btl4.log.
Layout
CMakeLists.txt one build: munga_engine lib + bt410_l4 game lib + btl4.exe
engine/
MUNGA/ shared 2007 sim/render engine (149 .cpp + headers)
MUNGA_L4/ Win32/D3D9 HAL + renderer + asset loaders (44 .cpp), incl.
our BT work: bgfload / L4D3D / L4VIDEO + the image codec
shim/ minimal ATL shim (USES_CONVERSION/W2A)
lib/ OpenAL32 / libsndfile import libs + runtime DLLs
game/
reconstructed/ the reconstructed BT game logic (mech, subsystems, HUD, app; ~47 .cpp)
original/BT,BT_L4 surviving original BT source + all BT headers
fwd/ header shims forwarding <NAME.hpp> -> the engine's NAME.h
btl4main.cpp WinMain launcher / entry point
content/ runtime data: BTL4.RES, VIDEO/, GAUGE/, AUDIO/, *.EGG, BTDPL.INI
context/ progressive knowledge graph — 18 on-demand topic files (routed by CLAUDE.md)
docs/ format specs + reconstruction ledgers + PROGRESS_LOG.md (full history)
reference/
decomp/ raw Ghidra pseudocode — source-of-truth for ongoing recon
ghidra_scripts/ the headless decomp exporter
glossary.yaml term / acronym definitions
phases/ restructuring / investigation logs
tools/ btconsole.py (MP console emulator), map/resource scanners
run/ run.cmd helper
CLAUDE.md knowledge-base ROUTER — identity, protocols, quick-lookup, conventions
Prerequisites
- Visual Studio 2019 BuildTools (MSVC v142, x86). The Community install on the original dev box was broken, hence the explicit BuildTools instance in the configure line below; adjust to your install.
- CMake ≥ 3.20.
- Legacy DirectX SDK (June 2010) — the engine uses
d3dx9/dinput/dxerr, removed from the modern Windows SDK. Default pathC:/Program Files (x86)/Microsoft DirectX SDK (June 2010); override with-DDXSDK=<path>. (The installer may throw a harmless S1023 error — dismiss it; the SDK headers/libs install before the failing redist step.)
OpenAL/libsndfile import libs + DLLs are vendored under engine/lib/; the DLLs are copied next to
the exe automatically at build time.
Build (32-bit / Win32)
cmake -S . -B build -G "Visual Studio 16 2019" -A Win32 ^
-DCMAKE_GENERATOR_INSTANCE="C:/Program Files (x86)/Microsoft Visual Studio/2019/BuildTools"
cmake --build build --config Debug
Must be Win32 — the DirectX SDK link libs are Lib/x86. The link uses /FORCE: the 1995
headers define free functions/globals without inline/extern, so identical symbols appear in
many translation units (~124 LNK2005); /FORCE:MULTIPLE keeps the first. UNRESOLVED tolerates
a dead offline-tool factory in mech3.cpp that is never called at runtime. (Cleanup task: move
those definitions to single TUs + neutralize the dead factory, then drop /FORCE.)
Run
run\run.cmd REM boots DEV.EGG (grass / day)
run\run.cmd DBASE.EGG REM any egg in content/
The working directory must be content/ (the engine resolves BTL4.RES, VIDEO\,
BTDPL.INI, and eggs relative to cwd); run.cmd handles that. Maps available in BTL4.RES:
cavern grass rav polar3 polar4 arena1 arena2 dbase — switch via a copied egg's map= field.
Useful env-var flags (default OFF unless noted)
The authentic stack (gait, collision, real controls) is default-on; set =0 to fall back.
Debug/harness flags: BT_FORCE_THROTTLE=1 (auto-walk), BT_SPAWN_ENEMY=1 (spawn a target dummy),
BT_FORCE_FIRE=1 (auto-fire), BT_HEAPCHECK=1 (whole-heap validation — slow), BT_BSL=0 (legacy
texture decode), BT_DEV_GAUGES=1 (render the cockpit MFDs in a dev window), BT_LOG=<file>.
Interactive: WASD drive, A/D turn, Q/E torso twist, R/F torso pitch aim,
Space / 1-4 fire, X all-stop, V view, M control mode. An Xbox-type controller
works out of the box. All bindings are user-editable in content/CONTROLS.MAP (delete it to
restore the compiled-in WASD default; content/CONTROLS_NUMPAD.MAP is an alternate profile). The
complete env-gate table is in context/decomp-reference.md §6 (routed from CLAUDE.md);
controls/pad details in context/pod-hardware.md.
Multiplayer
Modern path (relay + operator console). Pods make ONE outbound connection to a relay/console, so internet play needs no per-player port forwarding and CGNAT-safe LAN discovery just works. Run the operator station:
python tools/btoperator.py # PySide6 GUI: build the mission egg (validated dropdowns),
# start the relay, watch pods arrive, assign seats, LAUNCH,
# end the timed mission, export player join.bat scripts
Players run one universal join.bat (internet, seat assigned by the relay) or join_lan.bat
(same LAN, auto-discovers the console) or play_solo.bat (offline practice) — see players/.
The pod waits patiently if the session isn't up yet. Full architecture, wire format, and the
D1 relay/UDP design: context/multiplayer.md.
Legacy mesh (two instances, one box), still supported:
instance A: btl4.exe -egg MP.EGG -net 1501 (BT_LOG=mp_a.log)
instance B: btl4.exe -net 1601 (BT_LOG=mp_b.log)
console: python tools/btconsole.py MP.EGG 127.0.0.1:1501 127.0.0.1:1601
-net <port> enables networked mode. Verified end-to-end: full entity/movement replication,
cross-pod combat + kills, per-pilot paint + callsigns, timed missions, 4-pod live sessions, and a
spectator/broadcast camera seat (hostType=1 vehicle=camera) with auto-directed coverage and
a live ranking window.
Status & continuing the work
The engine, renderer, audio, HAL, build, locomotion, collision, damage, render fidelity, the full
cockpit gauge / MFD system (every config binding resolves + every widget builds), and the
projectile / missile weapon families are done. Active fronts: per-subsystem polish (the gyroscope
integrator; the 0xBD3 message manager that gates the valve / status-message control routes) and
cross-pod MP combat. reference/decomp/ holds the raw pseudocode every reconstruction is verified
against.
Start with CLAUDE.md — it is the router into the progressive knowledge base: a quick-lookup
table pointing to the context/*.md topic files (loaded on demand), the evidence-tier and
convention rules, and context/open-questions.md for what's deferred / next. The complete
pre-restructure history is preserved verbatim in docs/PROGRESS_LOG.md; docs/*.md holds the
detailed running ledgers.