diff --git a/engine/MUNGA/PLAYER.cpp b/engine/MUNGA/PLAYER.cpp index 4ca2c72..0713efa 100644 --- a/engine/MUNGA/PLAYER.cpp +++ b/engine/MUNGA/PLAYER.cpp @@ -415,6 +415,23 @@ void // Check(this); Check(application); + + // #156 (BT, field-caught watching the fade live): ONLY the local mission + // player may drive application state. A REPLICANT player copy mirrors the + // remote master's simulationState through its update-record header -- so at + // mission end every replicant player on this node also reads + // MissionEndingState here, and its fadeTimeRemaining was never armed by a + // MissionEnding message (ctor value, already <= 0) -> it dispatched the + // second StopMissionMessage on its FIRST tick and Stop() killed the mission + // loop instantly: the 3.0s fade window (and the fade itself) never rendered. + // Receipts: [fade-clk] interleaving remaining=3,2.976,... with a stray + // remaining=-0.976 from the replicant copy. The 1995 pod's replicant + // players never executed this arm; the port's replicant-executable wave + // made them tick, so gate the app-control arm to the owner. + if (GetInstance() == ReplicantInstance) + { + return; + } switch (GetSimulationState()) { case MissionStartingState: @@ -442,6 +459,10 @@ void } break; case MissionEndingState: + // #156 diag: the 3.0s fade window's actual clock, tick by tick. + if (getenv("BT_FADE_LOG")) + DEBUG_STREAM << "[fade-clk] slice=" << time_slice + << " remaining=" << fadeTimeRemaining << "\n" << std::flush; fadeTimeRemaining -= time_slice; if (fadeTimeRemaining <= 0.0f) { diff --git a/engine/MUNGA_L4/L4VIDEO.cpp b/engine/MUNGA_L4/L4VIDEO.cpp index ef1d668..faf8ae0 100644 --- a/engine/MUNGA_L4/L4VIDEO.cpp +++ b/engine/MUNGA_L4/L4VIDEO.cpp @@ -8504,9 +8504,21 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte fn = fogNear * local + kNearFloor; ff = fogFar * local + kFarFloor; s_T += fdt; - if (local <= 0.0f) { s_phase = 0; } // re-armed; final frame stays black + // FIELD-CAUGHT (first live watch): completing into phase 0 hit + // the restore branch -- the world POPPED BACK for the ~2s + // between fade end and teardown, which read as "no fade at + // all". The binary's zone fog STAYS closed after the fade-out + // (nothing reopens it until the next mission's flash). Hold + // black in a terminal phase instead; the next MissionStarting + // edge re-arms through it. + if (local <= 0.0f) { s_phase = 5; } break; } + case 5: // held black until the next mission starts + r = 0.0f; g = 0.0f; b = 0.0f; + fn = kNearFloor; ff = kFarFloor; + if (st == gBTFadeStart) { s_phase = 1; s_T = 0.0f; } + break; } if (r >= 0.0f) { @@ -8516,10 +8528,10 @@ void DPLRenderer::ExecuteImplementation(RendererComplexity, RendererOrigin::Inte D3DCOLOR_XRGB((int)(255 * r), (int)(255 * g), (int)(255 * b))); mDevice->SetRenderState(D3DRS_FOGENABLE, TRUE); } - else if (s_phase == 3 || s_phase == 0) + else if (s_phase == 3) { - // Out of the fade: restore the style planes once so a fade that - // ended mid-style leaves the world exactly on its authored fog. + // Fade-in complete: restore the style planes once so the world + // lands exactly on its authored fog. static int s_prev = -1; if (s_prev != s_phase) {