Went to source animationClips[] and found two things: a bug in what 5.3.91 committed, and a naming trap that has already cost BT411 a shipped defect. THE BUG, MINE. I sized animationClips[AnimationCount] -- 0x1d, from the enum. Wrong. The name table stops at 0x1d but the ARRAY does not: slot 0x20 (mech+0x64c) is the bump/crash clip the mech binds on a hard wall impact. So the array is [AnimationSlotCount] = 0x21 and Set*Animation's Verify bounds against that instead. Sizing a real array off a name table that stops earlier reads fine and corrupts whatever sits next door; caught by reading the clip loader, not by the compiler. THE SLOT MAP, recovered from LoadLocomotionClips and now written down in full (suffix, meaning, and which measured constant each clip yields): 5 swr stand -> walk standSpeed 6/7 wwr/wwl forward walk CYCLE walkStrideLength = (s6+s7)/(d6+d7) 8/9 wsr/wsl walk -> stand 10/11 wrr/wrl walk -> run reverseSpeedMax 12/13 rrr/rrl run CYCLE reverseStrideLength 14/15 rwr/rwl run -> walk 16/17 sbr/sbl stand -> back gimpSpeedMax 18/19 bbr/bbl reverse CYCLE gimpStrideLength (NEGATED here) 20/21 bsr/bsl back -> stand 22/23 wgl/wgr walk -> limp gimpLeft/RightSpeedMax 24/25 ggr/ggl limp CYCLE gimpLeft/RightStrideLength 26/27 gsl/gsr limp -> stand 0x20 bmp bump / crash stagger THE TRAP: THE "gimp*" MEMBERS ARE THE REVERSE FIGURES, NOT THE LIMP ONES. gimpSpeedMax and gimpStrideLength are measured from sbr and bbr/bbl -- the reverse gait. The real limp has its own gimpLeft*/gimpRight* pair. This is the same bad naming that produced the states-16-19 misreading recorded in 5.3.91, and it has now caused the same error twice from two directions. Also settled: gimpStrideLength's negative sign is applied AT MEASUREMENT, not authored into the data -- which is where the fold in the transition machines comes from. And the limp clips are OPTIONAL: the loader probes for wgl and leaves hasGimpClips 0 with slots 22-27 unfilled if the model lacks it, so the deferred gimp branch must check that before routing into the limp machine. THE ENUM IS NOT THE SLOT MAP, and MECH.HPP now says so at the enum itself. The names are verbatim from the binary and authoritative AS NAMES, but slot 0x0e takes the run-to-walk clip while the table calls it RightReverseAnimation, and the forward walk alternates 6/7 rather than the pair the WalkForward names suggest. Read the slot map for "what does this play"; read the enum for "what did the original call this index". ATTRIBUTION NOTE: the four clip helpers (ResolveAnimationClip @004a7f50, MeasureClipStride @004a8054, LoadLocomotionClips @004a80d4, LoadLocomotionClipsExt @004a86c8) are exactly the four addresses the manifest lists under mech2.cpp that BT411 files under mech3. The manifest's attribution comes from the binary's own file tagging, so they belong here -- which also accounts for all 12 of mech2's functions. BT 51/51. Still nothing calls the gait. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
source410 — literal reconstruction of the missing BT 4.10 game source
Everything in this directory is RECONSTRUCTED, not recovered. The authentic surviving
source lives in CODE/ and is never mixed with this tree. The goal here is an
archival-grade recreation of the d:\tesla_bt\ translation units that exist only inside
BTL4OPT.EXE (the shipped 4.10 binary), written in the 1995 VWE house style against the
1995 MUNGA/MUNGA_L4 engine headers that DID survive.
Ground rules
- Never copy a reconstructed file into
CODE/— the assembled buildable tree (originals + reconstructions) is produced by a script into a build directory, so provenance stays unambiguous file-by-file. - Every
.CPPhere has a.NOTES.mdsidecar carrying the evidence: the binary address map, decomp references, which sibling sources supplied each idiom, and every judgment call with its tier ([T1] decomp-proven … [T4] style guess). The.CPPitself stays clean 1995 style — no modern annotations inside. - Assert line numbers are constraints. The binary's
Fail()sites record the original file+line (BTL4APP.CPP:400etc.); reconstructed files are shaped so those calls land on their recorded lines. A file that can't meet its line constraints yet says so in the sidecar. - Layout mirrors the original tree:
BT/(bt.lib, 36 TUs) andBT_L4/(btl4.lib, 13 TUs + BTL4.CPP), matching the survivingBT.MAK/BTL4.MAK.
What drives the work
- The per-TU manifest:
C:\VWE\BT411\reference\BT410_SOURCE_MANIFEST.md(tooltools/manifest410.py; method logphases/phase-03-bt410-source-manifest.md). - The decomp:
C:\VWE\BT411\reference\decomp\all\part_*.c(+section_dump.txtstrings). - The port's semantic reconstructions:
C:\VWE\BT411\game\reconstructed\(WinTesla-hosted; each literal file here re-hosts one back onto the 1995 engine APIs). - Style/idiom exemplars: surviving
CODE/BT/*.CPP,CODE/RP/RP_L4/*.CPP,CODE/RP/MUNGA*/**(the 1995 engine source itself).
Status (2026-07-19)
Compile verification is LIVE: ./compile410.sh --sweep (BC4.52 + the authentic OPT.MAK
flags; the period compiler is the reviewer). backdate.py mechanizes WinTesla→1995 header
back-dating (donors: C:\VWE\BT412\engine\MUNGA\*.h).
| item | state |
|---|---|
| THE WHOLE TREE COMPILES (2026-07-19) | ✅ 11/11: all 10 surviving originals + the BTL4APP.CPP pilot build clean under BC4.52 + authentic OPT flags (./compile410.sh --sweep) |
| BT/BTCNSL.HPP + BT/BTSCNRL.HPP | ✅ reconstructed — console wire IDs recovered from the binary (Killed=9, Damaged=10, ScoreUpdate=13, DeathWithoutHonor=15 [T1]; TeamScore=12 [T4 GUESS — verify]); see BTCNSL.NOTES.md |
| BT_L4/BTL4APP.CPP (pilot reconstruction) | ✅ compiles (18.5KB obj); 12/12 functions, Fail() at recorded line 400 |
| Staged header family (13: mech/mechsub/heat/powersub/mechweap/emitter/mechmppr/btplayer/projtile/missile + btl4mppr/btl4vid) | ✅ [T3] interface-proven by every surviving consumer; layouts parked in reserved[] blocks — see STAGED-HEADERS.NOTES.md + MECH-LAYOUT.md |
| MUNGA backfills (VDATA, ROTATION, VECTOR2D, AUDREND, APP, LAMP, GAUGREND, GAUGE) | ✅ compile-proven (BACKFILLS.NOTES.md) |
Next work package — the mech-family, REVISED (round-3 finding, 2026-07-19): the plan to "reconstruct mech.hpp first" was the wrong order. A full read of the port's mech.hpp shows it is a hybrid (1995 skeleton + Recon proxies + port-only members + relocated fields), and substantial regions of the binary's 0x854-byte Mech object remain UNMAPPED — the port declares "the remaining members up to sizeof==0x854" in its mech2-4 slices. A literal MECH.HPP that precedes those TU reconstructions would be fiction. Corrected order:
- MECH.HPP is the CAPSTONE, grown incrementally with each mech-family TU
reconstruction (mech.cpp → mech2-4 → subsystem TUs), starting as an interface +
known-ordered members with explicit
reserved[]filler for unmapped regions (sidecar-tracked), tightened as each TU pins its slice. - The dependent headers (
mechsub,mechmppr,btl4mppr,emitter+mechweap,btplayer,projtile,missile) ship WITH their TUs against the staged MECH.HPP. - The blocked originals (BTTOOL, GAUSS, PPC, BTREG) and the BTL4APP pilot compile green as those land — BTREG last (it includes the whole game-header world). Offset oracles for every stage: BT411 CLASSMAP.md, decomp-reference.md §3, and the port headers' static_assert-locked members.
Toolchain — IN HAND (2026-07-19)
Borland C++ 4.52, archived at ../../BORLAND/BC45/, chosen by byte-match: the fleet's own
CODE/RP/CW32.LIB is identical to 4.52's (and not 4.5's). BCC32/TLINK32/TLIB/MAKE run natively
on Win11. The shipped BTL4OPT.EXE recipe is CODE/BT/OPT.MAK (plain bcc32,
-DLBE4;DEBUG_LEVEL=0;DEBUG_STREAM=cout, -5 -a4 -ff -k- -V -Jg -x- -RT- + the full -O set,
PCH btopt.csm; link -Tpe -ax with c0x32.obj + dpmi32.lib + cw32.lib = Borland PowerPack
DPMI32, not Phar Lap TNT). Compile verification of reconstructed TUs is therefore possible
file-by-file; the current blocker for full closure is the 1995 engine header gap (vdata.hpp
first — only the drifted WinTesla VDATA.h survives, in BT412/engine). Include order for
builds: CODE/BT/* over CODE/RP/*, -DNO_PRECOMPILED_HEADERS until the mech-family headers
are reconstructed. Remaining gap: TASM32 (JOYSTICK.ASM only).
Link campaign (build410, 2026-07-19)
source410/build410.sh assembles BTL4OPT.EXE: merged-engine mass compile (152/152 green
— the ENTIRE surviving engine compiles), BT TUs (11/11), tlib libs (munga 1.25MB / mungal4
with the prebuilt-1995 objs / bt / btl4), then the authentic tlink32 link rooted by a probe
main (build scaffold). First true link run: 52 unresolved externals
(UNRESOLVED-LEDGER.txt) = the measured remaining gap. Kill-lists: l4gauge.cpp back-date
(14 widget statics), the missing-engine-body back-date wave (~24: rotation, player, team,
l4app, explode, dropzone, terrain, cultural, subsystm-statics, netclient...), the prebuilt
RANDOM.obj fold, and the staged game-TU statics blocks (MECH.CPP et al. — each TU file opens
with its binary-evidenced Derivation/SharedData statics and grows into the full body).
Link-lib arbitration: SOS = SOSDBXC+SOSMBXC (the 32-bit Borland-flat variants; SOSMW*=16-bit),
WATTCP excluded (it belongs to the 16-bit NetNub TSR — the game talks to it via shared
memory), filestrm = the RP-era pair (BT-tree pair is post-4.10 drift; override layer).