118 lines
6.6 KiB
Markdown
118 lines
6.6 KiB
Markdown
# Egress-hold / floor-lighting — CLOSED (won't-fix), findings preserved
|
|
|
|
Status: **CLOSED 2026-07-10 — WILL NOT FIX** (operator decision). The floor
|
|
egress lights were a curiosity only: no surviving Tesla cockpit still has the
|
|
floor lamps installed, so reproducing the ~30s hold has no restoration value.
|
|
The investigation is fully documented here and in NET-NOTES.md for the record;
|
|
we will likely not return to it. The Step 1 patch below is a COMPLETE, ready
|
|
recipe if a future need ever arises — it is not planned work.
|
|
|
|
Summary of the closed finding: the pod's post-mission egress window is a
|
|
compiled ~3s (the game exits at its stage-1 timer; the deeper 30s timer is
|
|
never reached). It is byte-identical across all four BTL4OPT builds
|
|
(May-96..Rel410) = NOT a Rel410 regression. Effective behavior is authentic
|
|
as-is; the ~3s is what the game does.
|
|
|
|
Context in NET-NOTES.md ("EGRESS DELAY = COMPILED IN, TWO-PHASE").
|
|
|
|
## Step 0 RESULT (2026-07-10, net_full.conf single-shot, RIO tap)
|
|
|
|
Booted single-shot (netnub then DOS `pause`, NO loop.bat). Floor lamp:
|
|
mission-end bright @108.8s -> off @112.7s = **3.9s window**, then the game
|
|
(btl4opt) EXITED on its own to the DOS `pause` (dosbox left at COMMAND).
|
|
So the ~3s egress is the GAME'S OWN behavior, NOT a GO.BAT-loop artifact --
|
|
the process exits AT the stage-1 (3.0f) timer; the inner 30s timer is never
|
|
reached. Entry lighting this run: 77.4s->93.3s = 15.9s (varies with boot).
|
|
=> Not a free conf-fix. But since the lamps stay on for exactly the stage-1
|
|
duration and the exit fires when it elapses, **Step 1 (extend the 3.0f
|
|
constant to 30.0f) directly extends the honored hold to ~30s.** Proceed to
|
|
Step 1 when picked up.
|
|
|
|
## Problem restated
|
|
|
|
The pod's StopMission close is a two-stage, re-entrant handler (byte-identical
|
|
in BTLIVE May-96 / BTRAVINE Sep-96 / BTDAVE / Rel410, so not a build regression):
|
|
|
|
- OUTER handler (Rel410 @0x47c2c4, dispatched): first StopMission sets a flag
|
|
@[this+0xd4], schedules itself to re-fire in `3.0*timebase + 0.5` (3.0f
|
|
literal @0x47c350), returns. The +3s RE-ENTRY runs destructive cleanup
|
|
(0x44e13c, 0x44fa6c, base shutdown via 0x44eeb4) then calls the inner handler.
|
|
- INNER handler (Rel410 @0x47b864): base shutdown, egress lamps ON
|
|
(0x47bba8 flag=1; lamps 0x16/0x17/0x1e), schedules a +30s LightsOut/exit
|
|
(30.0f literal @0x47b8e4).
|
|
|
|
Observed: the process is recycled by GO.BAT in ~3.4s (the 3.0f stage). The
|
|
30s LightsOut is scheduled AFTER teardown has begun, so the exe dies before
|
|
it fires -- the 30s is effectively dead. Goal: a real ~30s (ideally
|
|
configurable) floor-lamps-on customer-egress hold before the pod exits.
|
|
|
|
Precondition already true: the floor lamp is lit at mission end and through
|
|
the wait (tap: FLOOR bright at mission end, off at the ~3.4s teardown), so a
|
|
longer PRE-teardown wait = a longer visible lamps-on egress window.
|
|
|
|
## Step 0 -- diagnose the pre-emption (cheapest, do first)
|
|
|
|
Confirm WHICH teardown races the 30s and whether it's config-specific before
|
|
touching the binary.
|
|
- Run a mission and grep nn.log at close for the "Sending EndMission..."
|
|
string and any LightsOut trace; timestamp against the RIO-tap lamp events
|
|
(scratchpad lamp_read.py) and the netnub relaunch.
|
|
- Test a NON-looping boot (single `netnub -p -f btl4opt` with a DOS `pause`
|
|
after, NOT loop.bat) so nothing recycles the exe -- if the 30s LightsOut
|
|
then fires (lamps stay on ~30s), the pre-emption is the GO.BAT loop timing,
|
|
not an in-handler race, and the "fix" may be purely a loop-conf change.
|
|
- If lamps still drop at ~3s even without the loop, the destructive cleanup
|
|
in the outer handler's re-entry is the culprit -> go to Step 1/2.
|
|
|
|
## Step 1 -- PREFERRED: one-constant binary patch (extend stage-1 to 30s)
|
|
|
|
Rationale: the outer handler's FIRST stage schedules +3s and returns WITHOUT
|
|
running the destructive cleanup (that's the re-entry). Extending stage-1 from
|
|
3s to 30s keeps the floor lamps on (already lit) for ~30s before the
|
|
destructive re-entry -- an authentic egress hold, with a single 4-byte edit.
|
|
|
|
- Target (Rel410): the 3.0f literal at VA 0x47c350 -> patch bytes
|
|
`00 00 40 40` (3.0f) to `00 00 F0 41` (30.0f). Backup first
|
|
(BTL4OPT.EXE.pre_egress), assert the original bytes before writing, like the
|
|
RIO/idle patches. Per-build literal addresses: find via stopmission_cmp3.py
|
|
(it prints the outer handler VA per build: BTRAVINE @0x47c2b0,
|
|
BTLIVE/BTDAVE @0x48a3c0; the 3.0f `fld` is a few insns in -- confirm with
|
|
btdis2.py `dis <handler>` then read the `fld dword ptr [X]` operand).
|
|
- Make it CONFIGURABLE without re-patching: better than a hardcoded 30, tie
|
|
the value to an env/INI the device already reads, OR expose it via a small
|
|
device hook (see Step 3). Simplest first cut = hardcode 30.0f and verify.
|
|
- Verify: RIO tap shows FLOOR lamp on for ~30s post-StopMission before the
|
|
sweep+exit; console still recovers; net_loop still recycles after.
|
|
- Risk: LOW. One literal, reversible. Watch that the scheduler is wall/real
|
|
time not frozen sim-time (Step 0 settles this); if sim-time is frozen at
|
|
mission end the timer won't advance and this won't help -> Step 2.
|
|
|
|
## Step 2 -- ALTERNATIVE: reorder so the inner 30s survives
|
|
|
|
If Step 1's stage-1 timer can't be used (e.g. frozen sim-time), instead make
|
|
the inner handler's existing 30s LightsOut fire before teardown: NOP or move
|
|
the destructive cleanup calls (0x44e13c/0x44fa6c/base 0x44eeb4) in the outer
|
|
re-entry so lamps-on + the 30s schedule run first and the process only exits
|
|
when LightsOut fires. Riskier (control-flow surgery, must not leak resources
|
|
or hang); needs the disasm of 0x44e13c/0x44fa6c to know what's safe to defer.
|
|
|
|
## Step 3 -- FALLBACK: device/GO.BAT egress window (no binary patch)
|
|
|
|
If binary patching is undesirable, synthesize the hold outside the game:
|
|
- net_loop.conf: after the game exits and before netnub relaunch, insert a
|
|
~30s DOS delay (e.g. a small TSR/CHOICE-style timeout) so the pod idles in
|
|
the egress window; the vpxlog/RIO device drives the floor lamp ON for that
|
|
window (device already owns the RIO serial path -- add a "hold floor lamp N
|
|
seconds on game-exit" hook keyed by an env var, e.g. VWE_EGRESS_MS).
|
|
- Pro: fully configurable, no game binary change, works across all builds.
|
|
- Con: the lamp is device-driven, not game-driven -- cosmetic only, and the
|
|
timing is approximate. Good enough for venue theater.
|
|
|
|
## Recommendation
|
|
|
|
Do Step 0 first (may reveal it's just a loop-conf issue = free fix). If a real
|
|
delay is needed, Step 1 (one-constant patch, made configurable) is the clean
|
|
path; Step 3 is the no-patch fallback. Tools: scratchpad btdis2.py,
|
|
stopmission_cmp3.py, lamp_read.py. Existing patch-toolchain precedent + backup
|
|
discipline in tesla-cockpit-emulator-state (RIO EXE patches).
|