Files
CydandClaude Fable 5 f07df88acb 410console: BattleTech egress-hold addendum -- issue closed (~3s hold)
Decoded/disassembled finding from the TeslaRel410 side, verified against
a live DOSBox BTL4OPT pod driven by this console: the post-mission egress
window is a compiled ~3 s (stage-1 timer), not ~30 s, and byte-identical
across all four BTL4OPT builds. Marked won't-fix -- the floor egress lamps
no longer exist on any surviving cockpit. Console takeaway unchanged: send
StopMission promptly at timer end; the pod handles its own (short) close,
no egress delay to implement.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-10 16:30:28 -05:00

6.2 KiB

Addendum: mission-close / egress-hold — decoded + disassembled (2026-07-10)

From the TeslaRel410 side. Verified against a live DOSBox BTL4OPT pod run BY THIS .NET CONSOLE over the host bridge (it works). Full writeup: TeslaRel410/emulator/NET-NOTES.md.

ISSUE CLOSED 2026-07-10 (won't-fix, operator decision). The floor egress lamps no longer exist on any surviving cockpit, so the hold has no restoration value. FINAL, corrected finding (supersedes the "~30s" phrasing below): the pod's post-mission egress window is a compiled ~3 seconds — the game exits at its stage-1 timer (Step-0 proven: a no-loop single-shot boot still held 3.9s then the game self-exited), and the deeper 30s timer is never reached. Byte-identical across all four BTL4OPT builds, so nothing regressed. Console takeaway is unchanged and simple: send StopMission(RunBattleTech) promptly at your timer end; the pod handles its own (short) close. No egress delay to implement. The rest of this file is preserved for the record.

Bottom line for TeslaConsole

The customer-egress window is a HARDCODED ~30s timer inside the GAME, not the console. You do NOT need to implement the egress delay. Just send Application__StopMissionMessage promptly at mission end with RunBattleTechExitCodeID (=3), and the pod runs the whole authentic sequence itself: egress lamps ON -> ~30s hold -> lamps OFF -> exit -> GO.BAT relaunch. The console's only timing responsibility is not to send StopMission too EARLY (let the mission actually end first).

The sequence (game side)

  1. Mission end -> game fades to black hold, sends the wrap-up (ConsolePlayerMechScoreUpdate / ConsoleBTTeamScoreUpdate / RankAndScore). Its StateResponse to your 1/s StateQuery flips state 0 -> 2 (mission-over/hold). It waits INDEFINITELY here for you. CAUTION — "mission end" is NOT the pod's own clock. Bench-confirmed 2026-07-09 (12s mission via this console): the pod does NOT self-end; the egg length= only drives the cockpit clock DISPLAY, which hits 0 and counts back UP while play continues. The console is the game's sole timekeeper — this hold state is only ever entered off the console's close (or an in-game end condition), so in practice steps 1-2 collapse: the console's StopMission at ITS timer end triggers the fade/wrap-up/lamps directly (see step 3).
  2. You send Application__StopMissionMessage(ExitCodeID).
  3. StopMissionMessageHandler (BTL4OPT.EXE @0x47b864, disassembled):
    • calls mission-shutdown/EndMission (0x44eeb4)
    • turns the RIO egress lamps ON (routine @0x47bba8, flag=1; lamps 0x16/0x17/0x1e = the floor/entry cluster; the "LightsOut" string @0x4fd5ac names this family)
    • schedules the lights-out+exit for now + 30.0*timebase + 0.5 (30.0f constant @0x47b8e4) -- the customer-egress hold
  4. ~30s later the timer fires -> lamps swept off -> game exits with the exit code -> pod's BAT loop dispatches it (RunBattleTech = relaunch).

Console message set + exit codes (from CODE/RP/MUNGA/APPMSG.HPP)

Messages: StateQuery, CheckLoad, RunMission, StopMission, KeyCommand, SuspendMission, ResumeMission, LoadMission, Abort.

ExitCodeID (the game's exit status = what the pod's BAT loop runs next):

Null=0, Abort, RunRedPlanet, RunBattleTech, RunSinglePlayerRedPlanet,
RunSinglePlayerBattleTech, DisplayMainTestPattern, DisplayAuxTestPattern,
TestPlasmaDisplay, ResetRIO, RunAudioTest, RunNortonDiskDoctor,
CheckDiskUsage, RefreshRedPlanet, RefreshBattleTech, ChangeScreenMode,
SoftwareReset, ClearCrashlog, KillSpoolFile, RunRedPlanetCamera,
RunBattleTechCamera, RunRedPlanetMissionReview, RunBattleTechMissionReview

= a whole remote-operations menu the console UI could expose (RIO reset, test patterns, plasma test, disk tools, camera/mission-review launches).

Notes / open

  • A configurable pre-StopMission delay is still fine to expose, but the ~30s customer window itself is the game's and is authentic at 30s.
  • Measured lamp-on-to-sweep was only ~3.4s in two live runs; that sweep was likely the teardown GeneralReset, with the real 30s timer firing past the tap window. To confirm on the TeslaRel410 side: one mission with a 90s+ RIO serial tap past mission end (btdis2.py found the constant; a live tap confirms wall-time).
  • Bonus authenticity: the floor lamp is ALSO entry lighting -- on from game-ready until the mission drops (customer climbs in lit).
  • Bench 2026-07-09 (12s mission): pod clock counted UP past 0 with play continuing until the console's stop — confirms the console is the sole timekeeper and step 1 never fires off the pod's own clock. If a self-end path exists in the binary it wasn't reachable with our egg.
  • Cross-ref: the BT411 up-port source (engine/MUNGA/APP.cpp ~1634) has a TWO-stage StopMissionMessageHandler (stop#1 while Running -> EndingMission
    • lamps; stop#2 while Ending -> Stop()/exit; +30s LightsOut = lamps off only). The shipping BTL4OPT.EXE disassembly above (one stop -> lamps + scheduled exit at +30s) is authoritative for the DOSBox pod; the up-port evidently diverges — worth knowing if BT411-built binaries ever drive a real pod.
  • A console-side "egress hold delay" (wait between console timer zero and the StopMission send) was prototyped in TeslaConsole 2026-07-09 and REVERTED: since the pod plays until stopped, that window is overtime play, not lamps-on time. The game's own 30s window is the authentic egress hold.
  • CROSS-BUILD DISASM (TeslaRel410 side, 2026-07-10, stopmission_cmp3.py): the StopMission close is BYTE-IDENTICAL across all four BTL4OPT builds -- BTLIVE (May-96), BTRAVINE (Sep-96), BTDAVE, Rel410 -- so no build regressed it (this settles the operator's "did Rel410 cut the hold?" question: no). Each build's dispatched outer handler (Rel410 @0x47c2c4) is the re-entrant two-stage one and carries BOTH a 3.0f and (via the inner @0x47b864) a 30.0f constant. Confirms the up-port's two-stage structure at the binary level. Whether 30s is honored live is still open: our RIO tap saw only ~3.4s of lamp-on (the 3.0f stage) before the exe recycled -- the 30s LightsOut may be pre-empted by teardown in the loop-conf flow. Not console-actionable either way (prompt StopMission is correct); noted for completeness.