diff --git a/410console/battletech-port/EGRESS-HOLD-ADDENDUM.md b/410console/battletech-port/EGRESS-HOLD-ADDENDUM.md new file mode 100644 index 0000000..bb5a79f --- /dev/null +++ b/410console/battletech-port/EGRESS-HOLD-ADDENDUM.md @@ -0,0 +1,109 @@ +# 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.