diff --git a/context/open-questions.md b/context/open-questions.md index 9823ccb..9686dd6 100644 --- a/context/open-questions.md +++ b/context/open-questions.md @@ -169,17 +169,29 @@ register. ⚠ The audit also flags the damage-economy item as SELF-CONTRADICTOR exactly is the all-roster-hosts-connected launch wait, and can absent seats stay `Opening` without stalling? Go/no-go = the 2-node late-attach spike in the plan doc. Phase 1 (round carousel) is console-only and has no engine unknowns. [[multiplayer]] -- **Glass panel dead-button backlog (input-coverage audit 2026-07-20) [T1 census].** 8 of the 72 - panel buttons dispatch a streamed message with NO reconstructed handler (silently ignored): - 0x13 → Mech `DuckRequest` @0049fa00 (CROUCH — `duckState` attr + SQUAT clips exist!), 0x28 → - Mech `BalanceCoolant` @0049f728, 0x1A-0x1D → Generator A-D `ToggleGeneratorOnOff` @004b1ed0, - 0x12 → ThermalSight toggle (pvision unported), 0x14 → Searchlight `ToggleLamp` (body - reconstructed, handler-set unwired — note the 1995 latent bug below: even wired, the light - never turns on in the original). Plus page-gated Eng-page meanings: `ToggleCooling` @004ad6f8 - (msg 3), `ToggleSeekVoltage` @004ba478/@004b8a48 (msg 0xb energy / 9 Myomers), `EjectAmmo` - @004bb9b8 (msg 0xb ammo weapons), and MechRIOMapper's own Keypress @004d2514 (id 0x19). - Filed as the Gitea "glass panel: unreconstructed button handlers backlog" issue; tables in - [[decomp-reference]] §2026-07-20; census in `docs/GLASS_COCKPIT.md`. +- **Glass panel dead-button backlog (input-coverage audit 2026-07-20) — ✅ CLOSED 2026-07-26.** + The 8 buttons that dispatched a streamed message with NO reconstructed handler are all wired + now; this entry stays as the index of where each one landed: + 0x13 → Mech `DuckRequest` @0049fa00 (**CROUCH — wired 2026-07-26**, the last one; see below), + 0x28 → Mech `BalanceCoolant` @0049f728 (2026-07-21, issue #20), + 0x1A-0x1D → Generator A-D `ToggleGeneratorOnOff` @004b1ed0 (`powersub.cpp`), + 0x12 → ThermalSight / 0x14 → Searchlight `ToggleLamp` (both 2026-07-25, #61), + `ToggleCooling` @004ad6f8 msg 3 (2026-07-20, `heatfamily_reslice.cpp`), + `ToggleSeekVoltage` @004ba478 msg 0xb energy (`emitter.cpp`) / @004b8a48 msg 9 Myomers, + `EjectAmmo` @004bb9b8 msg 0xb ammo (`projweap.cpp`). + Still open from that census: **MechRIOMapper's own Keypress @004d2514 (id 0x19)**. + Tables in [[decomp-reference]] §2026-07-20; census in `docs/GLASS_COCKPIT.md`. + ⚠ This entry was stale in BOTH directions for weeks (`docs/INPUT_PATH_AUDIT.md` flagged it) — + most of the list had been reconstructed while the prose still called it dead. Check the code, + not the census, before reconstructing anything here. +- **`DuckState` has no CODE consumer, and that is authentic [T1].** `Mech::DuckRequest` sets + `duckState`(attr 0x37, binary `mech+0x398`) to 1 and nothing else: the flag has exactly two + writers in the whole binary (that handler and the mech reset) and ZERO readers. Its consumer is + a DATABINDING — `content/GAUGE/L4GAUGE.CFG` drives a 3-frame `bduck.pcc` widget off `DuckState` + on the map's legend column, verified live (the crouch icon lights grey→orange on a press). So + the button is COMPLETE as a request flag + indicator. What is NOT known: whether the 1995 game + ever consumed it for posture/collision (no SQUAT clip name survives in the decomp or in + `content/`, only `DuckServo01.wav` in AUDIO1.RES). Do not invent a crouch pose to "finish" it. - **Searchlight-driven fog swap — STILL DEFERRED, but the "ORIGINAL 1995 LATENT BUG" premise is ❌ RETRACTED (2026-07-25, #61).** The arcade swaps fog between `fog=` (lights on) and `nosearchlightfog=` (off) via `PullFogRenderable` watching the Searchlight's `lightState`. diff --git a/context/pod-hardware.md b/context/pod-hardware.md index 2747f24..4da12ee 100644 --- a/context/pod-hardware.md +++ b/context/pod-hardware.md @@ -52,10 +52,12 @@ handler chain, so the Eng-page "Coolant" button now toggles the shown weapon's c sub 3 = Reservoir, 4-9 = Condenser1-6, 10-13 = GeneratorA-D): **0x2C = the COOLANT FLUSH button** (Reservoir InjectCoolant, hold-to-flush — works), **0x2F/0x2E/0x2D/0x2B/0x2A/0x29 = the per-condenser VALVE buttons** (MoveValve, Cond1-6 — work), **0x1A-0x1D = Generator A-D -ON/OFF** (`ToggleGeneratorOnOff` id 4, binary table @0050fb90 fn @004b1ed0 — DEAD until -reconstructed). Newly decoded from the binary message tables: **0x13 → Mech `DuckRequest` -(0x1a @0049fa00 — the manual's CROUCH button)**, **0x28 → Mech `BalanceCoolant` (0x16 -@0049f728)**, **0x12 → ThermalSight `ToggleLamp` (id 3, table @0x51120C fn @004b860c)** and **0x14 → +ON/OFF** (`ToggleGeneratorOnOff` id 4, binary table @0050fb90 fn @004b1ed0 — ✅ **WIRED**, +`powersub.cpp`). Newly decoded from the binary message tables: **0x13 → Mech `DuckRequest` +(0x1a @0049fa00 — the manual's CROUCH button)** — ✅ **WIRED 2026-07-26**, the last handler in +this census; press-only, sets `duckState` and the map legend's `bduck.pcc` widget lights (see +[[open-questions]] for why it has no code consumer) —, **0x28 → Mech `BalanceCoolant` (0x16 +@0049f728)** ✅ **WIRED 2026-07-21 (#20)**, **0x12 → ThermalSight `ToggleLamp` (id 3, table @0x51120C fn @004b860c)** and **0x14 → Searchlight + Searchlight2 `ToggleLamp` (id 3, table @0x51117C fn @004b838c)** — ✅ **BOTH WIRED 2026-07-25 (#61)**, previously default-constructed blackholes; verified live (0x14 → `lightState 0→1`, 0x12 → `thermalActive 0→1`). ⚠ The fn addresses were **swapped** in this file diff --git a/game/reconstructed/mech.cpp b/game/reconstructed/mech.cpp index 43f6dad..a2878f5 100644 --- a/game/reconstructed/mech.cpp +++ b/game/reconstructed/mech.cpp @@ -465,6 +465,7 @@ const Receiver::HandlerEntry MESSAGE_ENTRY(Mech, TakeDamage), MESSAGE_ENTRY(Mech, PlayerLink), MESSAGE_ENTRY(Mech, BalanceCoolant), // id 0x16 @0049f728 (issue #20) + MESSAGE_ENTRY(Mech, DuckRequest), // id 0x1a @0049fa00 (CROUCH, 2026-07-26) }; // @@ -486,6 +487,32 @@ void DEBUG_STREAM << "[valve] BALANCE (all valves -> 1)" << std::endl; } +// +// @0049fa00 -- DuckRequest (id 0x1a): the CROUCH button (RIO 0x13). The +// binary's whole body, verbatim: +// +// if (0 < *(int *)(message + 0xc)) *(undefined4 *)(this + 0x398) = 1; +// +// this+0x398 is duckState (attribute 0x37) -- the mech reset is the only other +// writer in the binary (part_012.c:9439, the same reset that zeroes +// incomingLock and sets distanceToMissile = FLT_MAX, which is how we already +// map that region). Nothing in the decompiled code READS it: it is published +// as an attribute, so its consumer is a databinding (the SQUAT clips), not a +// call. So this handler is complete as-is -- the flag IS the feature's code +// side, and a crouch implementation here would be a stand-in for data we have +// not yet identified. See context/pod-hardware.md. +// +void + Mech::DuckRequestMessageHandler(ReceiverDataMessageOf *message) +{ + if (message->dataContents <= 0) // press only (msg+0xc) + { + return; + } + duckState = 1; + DEBUG_STREAM << "[duck] DuckRequest: duckState -> 1" << std::endl << std::flush; +} + Receiver::MessageHandlerSet Mech::MessageHandlers( ELEMENTS(Mech::MessageHandlerEntries), diff --git a/game/reconstructed/mech.hpp b/game/reconstructed/mech.hpp index 8448b4c..2ba25b6 100644 --- a/game/reconstructed/mech.hpp +++ b/game/reconstructed/mech.hpp @@ -1193,6 +1193,22 @@ protected: enum { BalanceCoolantMessageID = 0x16 }; void BalanceCoolantMessageHandler(ReceiverDataMessageOf *message); + // @0049fa00 -- "DuckRequest" (Mech handler table @0x50BDF8, id 0x1a; the + // pod's CROUCH button, RIO address 0x13 -- the manual gives it a whole + // section). The last unregistered id in the Mech table; until now a + // press was silently swallowed by Receiver::Receive. + // + // The binary's ENTIRE body is two lines: press-only (msg+0xc > 0), then + // duckState@0x398 = 1. It is a one-shot REQUEST flag, not a posture + // toggle -- the handler never clears it, and the only other writer in + // the whole binary is the mech reset (0). duckState has NO code reader + // anywhere in the decomp; it is published as attribute 0x37, so whatever + // consumes it consumes it through DATABINDING (the SQUAT clips), not + // through a call. Reconstructed exactly: setting the flag is the + // authentic behaviour, and inventing a crouch here would be a stand-in. + enum { DuckRequestMessageID = 0x1a }; + void DuckRequestMessageHandler(ReceiverDataMessageOf *message); + // --- damage-routing support (mechdmg / mech4) ----------------------- // Typed access to the inherited Entity::damageZones[] (engine stores DamageZone*; // our entries are Mech__DamageZone, populated by the Mech ctor). Defined in