diff --git a/context/open-questions.md b/context/open-questions.md index 08a65bf..4313744 100644 --- a/context/open-questions.md +++ b/context/open-questions.md @@ -59,6 +59,22 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR (task #8 "landed" vs the kShotDamage=12 bring-up residue) — audit before reworking. ## Deferred subsystems / feeds (authentic path scoped, marked in code) +- **Searchlight-driven fog swap — DEFERRED, and it is an ORIGINAL 1995 LATENT BUG (task #63, + 2026-07-13) [T1 decomp].** The arcade swaps fog between `fog=` (lights on) and `nosearchlightfog=` + (off) via `PullFogRenderable` watching the Searchlight's `lightState`. It never fires — in the PORT + because `PullFogRenderable` is never constructed, AND in the BINARY ITSELF because the Searchlight + never lights: `ToggleLamp` (@004b860c) toggles `commandedOn` @0x1DC but `SearchlightSimulation` + (@004b841c) reads `requestedOn` @0x1E0, which is zeroed by the ctor and never written — no + 0x1DC→0x1E0 bridge exists (self-consistent sibling ThermalSight reads the field it toggles, 0x1DC). + So `lightState` is perpetually 0. The port reproduces this faithfully (searchlight.cpp:189). + **DECISION: left as-is + documented (faithful to the buggy original); port keeps the static + lights-ON `fog=`.** A working swap is a DESIGNER-INTENT deviation, fully scoped if ever wanted: + (1) sim reads `commandedOn` (mirror ThermalSight); (2) construct `PullFogRenderable` at + btl4vid.cpp `MakeMechRenderables` reticle-build/inside pass (== arcade part_014.c:5173, Dynamic, + bound per Searchlight `lightState` via a new `LightStatePtr()` accessor); (3) a toggle input (the + authentic cockpit button-5→`ToggleLamp` dispatch is a controls-family reconstruction; a dev key + stands in). Also flags a deferred **`Mech::ControlsAllowLights()`** (searchlight.hpp:158 stub). + See [[rendering]] fog section. Verified inert live: BT_FOG_LOG shows zero `SetFogStyle(2/3)`. - **Factory capability-roster loops 2-4 are STILL DEAD (task #57 discovery).** mech.cpp's post-roster loops add to `heatableSubsystems`(0x51155c)/`weaponRoster`(0x511830)/ `damageableSubsystems`(0x50e4fc) through the local `SubProxy` stub whose `IsDerivedFrom` diff --git a/context/rendering.md b/context/rendering.md index ba52583..0cc598a 100644 --- a/context/rendering.md +++ b/context/rendering.md @@ -67,15 +67,24 @@ DECLOUDS must stay in the sky pass). Authored TEXTURE **SCROLL** (BMF TEXTURE ta arcade. Night fog is dark BY DESIGN (distance→murk, not light haze); day pages author light haze. Env: `BT_FOGMODE=table|vertex|off`, `BT_WEATHER=clear|fog|soup`, `BT_FOG="near far r g b"` (all branches); `[fog] resolved`/`[fog] model`/`[fogstyle]` (BT_FOG_LOG) log lines. [T1 pipeline / T0 arcade model / T2 fix] - **⚠ SEARCHLIGHT SWAP IS INERT [T1, verified 2026-07-13].** The arcade swaps the active fog between - `fog=` (headlight ON) and `nosearchlightfog=` (OFF, darker/tighter) via `PullFogRenderable::Execute` - (L4VIDRND.cpp:4601, edge-triggered on two light attrs → `SetFogStyle(searchLightOn/OffFogStyle)`). In - the port **`PullFogRenderable` is NEVER CONSTRUCTED** (grep: only its .h decl + .cpp def; no `new`), and - `searchLightOn/Off` is called from nowhere else — so the swap never fires (BT_FOG_LOG: over 22s only - `SetFogStyle(0)`, zero style 2/3). Fog is STATIC at the searchlight-ON (`fog=`) values; the - `nosearchlightfog=` variant is dead. Reconstruction gap: wiring needs the mech's headlight/searchlight - state (Searchlight subsys 3032) bound to a `PullFogRenderable` constructed at viewpoint/mech setup. - Core per-map/time/weather fog is unaffected (uses the lights-ON set, the normal play state). + **⚠ SEARCHLIGHT SWAP IS INERT — and it was inert in the ARCADE too (task #63 workflow, 2026-07-13).** + The arcade swaps the active fog between `fog=` (headlight ON) and `nosearchlightfog=` (OFF, + darker/tighter) via `PullFogRenderable::Execute` (L4VIDRND.cpp:4601, edge-triggered on two light attrs → + `SetFogStyle(searchLightOn/OffFogStyle)`). TWO independent reasons it never fires: + (1) **Port:** `PullFogRenderable` is NEVER CONSTRUCTED (grep: only its .h decl + .cpp def; no `new`); + `searchLightOn/Off` is called from nowhere else (BT_FOG_LOG: over 22s only `SetFogStyle(0)`, zero 2/3). + (2) **Original 1995 LATENT BUG [T1, decomp]:** even if wired, the Searchlight never lights — + `ToggleLamp` (@004b860c) toggles `commandedOn` @0x1DC (part_013.c:6087) but `SearchlightSimulation` + (@004b841c) reads `requestedOn` @0x1E0 (part_013.c:5978), which the ctor zeroes and NOTHING ever writes; + no bridge 0x1DC→0x1E0 exists anywhere in the binary. So `lightState`@0x1D8 is perpetually 0. The + self-consistent sibling **ThermalSight** reads the SAME field it toggles (0x1DC) — the tell that + Searchlight's sim reads the wrong slot. The port reproduces this faithfully (searchlight.cpp:189 reads + requestedOn). **DECISION (2026-07-13): left as-is + documented** (faithful to the buggy original); the + port keeps the static lights-ON `fog=` values. To make the swap WORK is a DESIGNER-INTENT fix that + DEVIATES from the shipped binary — repair the sim to read `commandedOn` (mirror ThermalSight) + construct + `PullFogRenderable` at btl4vid.cpp `MakeMechRenderables` (the reticle-build/inside pass, == arcade + part_014.c:5173, ExecutionType Dynamic, bound to each Searchlight `lightState`) + a toggle input. See + [[open-questions]]. Core per-map/time/weather fog is unaffected. - **Projection / stencil (task #55):** the BTDPL.INI `viewangle=60` is the **HORIZONTAL** FOV — authentic 60×47 frustum at 4:3; fovY derived via `BTFovYFromHorizontal` (L4VIDEO.cpp), applied at all 5 projection sites (it was mis-applied as vertical). The device depth-stencil is now diff --git a/context/subsystems.md b/context/subsystems.md index 6ae46c2..3a3097c 100644 --- a/context/subsystems.md +++ b/context/subsystems.md @@ -41,6 +41,11 @@ Making a base byte-exact GROWS every subclass — they must be re-based TOGETHER - **WAVE 3** — power bus (Generator/PoweredSubsystem) + Emitter/PPC fire-path (end-to-end fire; heat conducts to the central sink via the linked-sink roster). - **WAVE 4** — standalone readouts: Sensor/Searchlight/ThermalSight/AmmoBin (de-shim, gate fixes). + - ⚠ **Searchlight has an ORIGINAL latent bug [T1, task #63]:** `SearchlightSimulation` (@004b841c) + reads `requestedOn`@0x1E0 (never written) while `ToggleLamp` (@004b860c) toggles `commandedOn`@0x1DC + — no bridge, so `lightState`@0x1D8 is perpetually 0 (lamp never lights). Present in the 1995 binary + (sibling ThermalSight reads the field it toggles, 0x1DC); the port reproduces it faithfully. Left + as-is by decision; it makes the searchlight→fog swap inert. See [[open-questions]] + [[rendering]] fog. - **WAVE 5** — Torso (aim twist/elevation; joint-I/O reconstructed; the BLH record disables torso → faithfully no visible twist). - **WAVE 6** — Myomers (mover-coupled; structural un-stub is INERT — no live mover/heat coupling).