BTL4PB.CPP reconstructed against its AUTHENTIC surviving header (BTL4PB.HPP) from the binary's 0x4d3b74-0x4d40d8 cluster, cross-checked against the surviving RP411 twin -- and the review/camera launch in BTL4.CPP's main() is real code now. btl4.lib 11 -> 12 members, link clean, zero unresolved: the linker pulled the entire playback chain for the first time. The launch decode closed on two identifications: The `if (spool_file)` guard in the decomp means the manager getter is GetStoredSpoolFile -- the empty-spool getter cannot fail, so a review pod with no recorded battle simply starts nothing, which is the right field behaviour. The camera app's ctor (FUN_0047c3fc) sits in the ENGINE range with the (ResourceFile*, ApplicationID) shape: the camera pod's recorder IS the engine's own L4SpoolingApplication -- restored one commit ago -- started with ApplicationID 1 == BTL4. BT shipped no camera app of its own. What the playback app does, all binary-anchored: BTSpoolerTask pumps recorded packets through DispatchPacket -> the client's own ReceiveNetworkPacket; RunMission synchronises the clock (timeBias = Now - the recorded run packet's stamp); the frame loop runs controls ONLY in interactive review (mode 2), then update/interest/renderer/intercom; and StopMission plays the WINNERS CIRCLE -- release the spool, park each player's mech on the dropzone named "win1".."winN" by finishing rank, freeze it (DoNothing performance), and tilt the camera up 45 degrees over the tableau. DOS-authentic ctor shape throughout: the binary's base call is (resource, 0x3eb, DefaultData) -- no windowing parameters ever existed in 4.10; the RP411 twin's HINSTANCE/HWND threading is port drift, dropped. Also fixed from 5.3.105's debt: L4PlaybackNetworkManager chains NetworkManager::DefaultData -- the 1995 header declares no statics of its own; the RP411 self-reference was drift too. One [T3] in source: the idle frame's renderer service (the descendant's ExecuteIdle) has no 1995 entry point; pre-egg the idle frame spins. RUNTIME TEST PENDING, stated plainly: exercising review needs a camera/review egg and a recorded spool on the rig (CAMERA-REVIEW-NOTES.md has the roles). The normal pod path regressed clean (mode gate untouched). The Fail() census moves: BTL4.CPP and SEQCTL.CPP are now stub-free; 22 stubs remain across 15 files. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
71 lines
4.2 KiB
Markdown
71 lines
4.2 KiB
Markdown
# BTL4.CPP — reconstruction notes
|
|
|
|
**Status: FULLY RECONSTRUCTED (2026-08-03) — both launch paths. The review/camera branch links against the real BTL4PB + L4SPLR bricks; no Fail() remains in this TU.**
|
|
|
|
The 4.10 main TU. No original survives anywhere in the archive (OPT.MAK links
|
|
`btl4.obj` as a bare object next to the libs — it was never a lib member).
|
|
|
|
## Evidence base
|
|
|
|
1. **Ghidra decomp of the 4.11 binary** — `C:\VWE\BT411\reference\decomp\all\part_000.c`,
|
|
`FUN_0040109c` (the 524-byte function the Borland startup calls = `main`).
|
|
The 4.10 and 4.11 binaries share the same string pool layout for this TU.
|
|
2. **String pool of the original 4.10 `BTL4OPT.EXE`** (ALPHA_1/REL410/BT), file
|
|
offset ~917884: `"btl4" "HEAPSIZE" "BattleTech v4.10" "btl4.res" "SPOOLSIZE"
|
|
"Spool size = "` — banner text and resource name byte-exact.
|
|
3. **Surviving 1995 launcher-style TU** `CODE/RP/RP_L4/RPL4TOOL.CPP` — house
|
|
style for `main(int, char*[])` and the `ProgName` global pattern.
|
|
4. **BT411's win32 launcher** `game/btl4main.cpp` (adapted from RP's RPL4.CPP)
|
|
independently reconstructs the same skeleton and pins `version[3] = {1,0,6}`
|
|
against the RESOURCE.cpp version check.
|
|
|
|
## Decoded decomp → source mapping
|
|
|
|
| decomp | source |
|
|
|---|---|
|
|
| `FUN_004dbb24(&cout, "BattleTech v4.10", 0); FUN_004d9c38(&cout)` | `DEBUG_STREAM << "BattleTech v4.10" << endl` |
|
|
| `FUN_0047b2ec(argc, argv, &LAB_0047af8c)` | `L4Application::ParseCommandLine(argc, argv, L4Application::ParseToken)` |
|
|
| `FUN_00407218(stack84, "btl4.res", &DAT_004e0070, 3)` | `StreamableResourceFile resources("btl4.res", version)` (match_level=3 is the declared default) |
|
|
| `DAT_004e0070` = 3 bytes | `version[3]` = `{MAJOR_DATA_VERSION, RELEASE_VERSION, MINOR_DATA_VERSION}` = {1,0,6} from BTL4VER.HPP |
|
|
| `DAT_004fd550 < 1` | `L4Application::GetMissionReviewMode() < 1` (inline static accessor) |
|
|
| `new(0x28) FUN_0044f29c(this, DAT_0052140c)` | `new ApplicationManager(GetTicksPerSecond())` (inline friend accessor, TIME.HPP:49) — DAT_0052140c is set to 28.0f by `SystemClock::SystemClock()` (L4TIME.CPP:93) when `L4TIMER=FAST` |
|
|
| `new(0xd4) FUN_004d34c4(this, &resources, 0x3EB, &DAT_0051e8d8)` | `new BTL4Application(&resources)` — 0x3EB/`DefaultData` are the declared default args (BTL4APP.HPP:34) |
|
|
| `FUN_0044f318(mgr, app)` | `application_manager->StartApplication(application)` |
|
|
| `FUN_0044f344(mgr)` | `application_manager->RunMissions()` |
|
|
| vcall slot 0 (mgr, 3) | `delete application_manager` |
|
|
| `return DAT_004efc98` | `return Exit_Code` (APP.HPP:542) |
|
|
|
|
## Review/camera branch (NOT yet reconstructed — staged Fail)
|
|
|
|
Decomp structure for `missionReviewMode >= 1` (mode 1 = camera, 2 = review per
|
|
emulator/CAMERA-REVIEW-NOTES.md):
|
|
|
|
```
|
|
spool_size = getenv("SPOOLSIZE") ? atoi(...) : 0x800000; // "Spool size = " printed
|
|
mgr = new(0x38) MissionReviewApplicationManager(ticksPerSecond,
|
|
(mode != 2) ? 2 : 1, spool_size);
|
|
spool_file = <mgr getter, FUN_0044fa14>;
|
|
if (spool_file)
|
|
mgr->StartApplication(new(0xd8) BTL4PlaybackApplication(&resources, spool_file));
|
|
if (mode == 1)
|
|
mgr->StartApplication(new(0xd8) <camera app, FUN_0047c3fc>(&resources, 1));
|
|
```
|
|
|
|
RECONSTRUCTED 2026-08-03: the branch is real. BTL4PB.CPP reconstructs the
|
|
playback app against its authentic surviving header; L4SPLR.CPP back-dates the
|
|
RP411 descendant onto the authentic 1995 engine header (see each sidecar). Two
|
|
identifications closed it: the `if (spool_file)` guard means the getter is
|
|
GetStoredSpoolFile (the empty-spool getter cannot fail), and the camera app's
|
|
ctor FUN_0047c3fc sits in the engine range with the (ResourceFile*,
|
|
ApplicationID) shape — the camera app IS the engine's L4SpoolingApplication,
|
|
started with ApplicationID 1 == BTL4. RUNTIME TEST PENDING: needs a
|
|
camera/review egg and a recorded spool on the rig (CAMERA-REVIEW-NOTES.md).
|
|
|
|
## Deliberate differences from the binary
|
|
|
|
- `HEAPSIZE` string sits in the pool between ProgName and the banner but is not
|
|
referenced from the decompiled main — it likely belongs to the runtime heap
|
|
init, not this TU. Not reproduced.
|
|
- `Register_Object`/`Start_Registering` debug bookkeeping is absent from the
|
|
optimized binary (DEBUG_LEVEL=0 compiles it out), so it is not written here.
|