#135 FIXED, two defects: (1) the generator lamp special was mis-reconstructed -- the binary @004cc27c is table_0051d070[generatorNumber] (bytes {0x29,0x1A..0x1D}, 1-based A..D, same shape as the condenser special), not an aux-screen placement probe generators never fill; a leaking generator now flashes its own lamp (benched: '[lamp] 0x1a <- 0x37 (FLASHING)' on a GeneratorA leak; was the field-logged 'NO LAMP RESOLVED'). (2) the eternal loop-button flash: Lamp::SetAlertState/SetState drop their panel notify when the edge lands off-page or in the one-frame mask race of a page transition, and the panel value latches the last-asserted flash forever -- Oracle's 'Loop 6 NEVER stopped' with Condenser6 SET/CLEARED balanced 3/3 in his log (the alarm manager was right; the lamp was stale). The skipped notify is now remembered and delivered at the lamp's next in-mode frame. KB: decomp-reference gains the 0x51d070 table + the stale-flash gotcha.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
14c62f184d
commit
7fa6dc536c
@@ -616,6 +616,20 @@ From the weapon `.SUB` records + the charge-curve `.data` constants (PE-parsed a
|
||||
@00444c80` (lamp map at renderer`+0x1c0c8`) → **`Lamp::SetAlertState @00444e64`** (the flash
|
||||
COUNTER at lamp+0x1C) → the L4 lamp flush `@00474e94` emits `0x37`/`0x13` = `flashFast` RIO
|
||||
states (== T0 L4LAMP.cpp:234-239) → `RIO::SetLamp` (binary `FUN_00476568`; cached wrapper
|
||||
- **#135 (2026-08-11): the GENERATOR special @004cc27c is `table_0051d070[generatorNumber]`**
|
||||
(sub+0x1E0, A=1..D=4, 1-based; bytes byte-read: {0x29, 0x1A,0x1B,0x1C,0x1D}; slot 5 is
|
||||
already string data — bounds-guard 1..4) [T1] — the SAME shape as the condenser special
|
||||
@004cc264 beside it. The port had mis-reconstructed it as an aux-screen placement probe
|
||||
(fields generators never fill) → the field-logged `NO LAMP RESOLVED (generator=1)` silent
|
||||
generator leak; benched fixed (`[lamp] 0x1a <- 0x37 (FLASHING)` on a GeneratorA leak).
|
||||
- **#135 stale-flash gotcha [T0]:** `Lamp::SetAlertState/SetState` notify the panel ONLY when
|
||||
the lamp's modeMask intersects the manager's current mask — an edge landing off-page (or in
|
||||
the one-frame mask race of a page transition) is silently dropped, and the panel value
|
||||
LATCHES the last-asserted flash (Oracle: "Loop 6 NEVER stopped flashing"; his log shows
|
||||
Condenser6 SET/CLEARED balanced 3/3 — the manager was right, the lamp was stale). Port fix:
|
||||
the skipped notify is remembered (`staleAlertNotify`) and delivered by the manager's
|
||||
active-lamp loop at the next in-mode frame (LAMP.cpp). Field SET/CLEARED balance + a stuck
|
||||
flash = this gotcha, not an alarm leak.
|
||||
`@00474d54`). T0-compiled already: LAMP.cpp / L4LAMP.cpp / GAUGALRM.cpp / RENDERER messages.
|
||||
**✅ ALL THREE PIECES BUILT same day (see [[open-questions]] for the full closure note).**
|
||||
Corrections pinned while building: the SENDER is **`MechTech::TechnicalAssistance` @004ad33c**
|
||||
|
||||
@@ -53,6 +53,17 @@ void
|
||||
while ((lamp_pointer=i.ReadAndNext()) != NULL)
|
||||
{
|
||||
Check(lamp_pointer);
|
||||
// #135: an edge that arrived while this lamp's page was not current
|
||||
// (or during the one-frame mask race of a page transition) skipped its
|
||||
// NotifyOfStateChange -- the panel value latches the last asserted
|
||||
// flash, so a missed CLEAR left loop buttons flashing forever. The
|
||||
// lamp is on the ACTIVE list here, so its mode is current: deliver
|
||||
// the missed notification now.
|
||||
if (lamp_pointer->staleAlertNotify)
|
||||
{
|
||||
lamp_pointer->staleAlertNotify = False;
|
||||
lamp_pointer->NotifyOfStateChange();
|
||||
}
|
||||
lamp_pointer->Update();
|
||||
}
|
||||
Check_Fpu();
|
||||
@@ -248,6 +259,7 @@ Lamp::Lamp(
|
||||
previousState = LampStateUndefined;
|
||||
manager = lamp_manager;
|
||||
alertActive = 0;
|
||||
staleAlertNotify = False; // #135
|
||||
|
||||
manager->AddLamp(this);
|
||||
Check_Fpu();
|
||||
@@ -281,6 +293,10 @@ void
|
||||
{
|
||||
NotifyOfStateChange();
|
||||
}
|
||||
else
|
||||
{
|
||||
staleAlertNotify = True; // #135: deliver at next in-mode Update
|
||||
}
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
@@ -311,6 +327,10 @@ void
|
||||
{
|
||||
NotifyOfStateChange();
|
||||
}
|
||||
else
|
||||
{
|
||||
staleAlertNotify = True; // #135: deliver at next in-mode Update
|
||||
}
|
||||
Check_Fpu();
|
||||
}
|
||||
|
||||
|
||||
@@ -78,6 +78,14 @@ protected:
|
||||
*manager;
|
||||
int
|
||||
alertActive;
|
||||
// #135: an alert-state EDGE whose NotifyOfStateChange was skipped by the
|
||||
// mode gate (page not current, or the one-frame mask race during a page
|
||||
// transition). The panel value latches the last asserted flash until the
|
||||
// next assert, so a skipped clear-edge left loop buttons flashing forever
|
||||
// (field: Oracle night-15, "Loop 6 NEVER stopped"). Delivered by Update()
|
||||
// at the lamp's next in-mode frame.
|
||||
Logical
|
||||
staleAlertNotify;
|
||||
};
|
||||
|
||||
//#########################################################################
|
||||
|
||||
@@ -170,7 +170,13 @@ static const int kBTEngBankTop[12] = { 0xF,0xF,0xF,0xF, 0x27,0x27,0x27,0x27, 0
|
||||
// no 0x29) -- overlapping but distinct lamps. Slot 6 (0x29) is also
|
||||
// DAT_0051d070[0], the first per-placement lamp: the two tables abut.
|
||||
static const int kBTCondenserLamp[7] = { 0x7, 0x2F,0x2E,0x2D,0x2B,0x2A, 0x29 };
|
||||
static const int kBTPlacementLamp[5] = { 0x29, 0x1A,0x1B,0x1C,0x1D }; // [auxScreenPlacement]
|
||||
// #135 CORRECTED: these are the GENERATOR leak lamps -- the binary's table at
|
||||
// 0x51d070 (@004cc27c), indexed by generatorNumber 1-BASED (A=1..D=4; slot 0
|
||||
// overlaps the condenser table's last entry and is unused; slot 5 is already
|
||||
// string bytes in the image, hence the bounds guard). The old name/comment
|
||||
// ("auxScreenPlacement") described a mis-reconstruction that indexed this
|
||||
// table with PoweredSubsystem aux fields generators never fill.
|
||||
static const int kBTGeneratorLamp[5] = { 0x29, 0x1A,0x1B,0x1C,0x1D };
|
||||
|
||||
//
|
||||
// @004cc148 -- the fixed (<0x80) map: coolingLoop1..6 -> the heat-display bank.
|
||||
@@ -335,10 +341,15 @@ void
|
||||
{
|
||||
if (the_condition == 2) // CoolantLeaking
|
||||
{
|
||||
int screen = 0, placement = -1;
|
||||
BTGetSubsystemAuxScreen(the_subsystem, &screen, &placement, 0);
|
||||
if (placement >= 0 && placement < 5)
|
||||
lamp_id = kBTPlacementLamp[placement];
|
||||
// #135 FIX: the binary's generator special @004cc27c indexes the
|
||||
// 0x51d070 table by generatorNumber (sub+0x1E0, A=1..D=4) -- NOT by
|
||||
// any aux-screen placement (generators never fill those fields; the
|
||||
// old probe left placement=-1 and a leaking generator annunciated
|
||||
// NOTHING, the field-logged 'NO LAMP RESOLVED (generator=1)').
|
||||
extern int BTGeneratorNumber(::Subsystem *sub); // powersub.cpp
|
||||
int n = BTGeneratorNumber(the_subsystem);
|
||||
if (n >= 1 && n <= 4)
|
||||
lamp_id = kBTGeneratorLamp[n];
|
||||
}
|
||||
}
|
||||
else if (lamp_code < 0x80)
|
||||
|
||||
@@ -1822,6 +1822,17 @@ int BTSubsystemIsGenerator(::Subsystem *sub)
|
||||
return (sub != 0 && sub->IsDerivedFrom(*Generator::GetClassDerivations())) ? 1 : 0;
|
||||
}
|
||||
|
||||
// #135 bridge: the binary's generator lamp special @004cc27c is
|
||||
// `table_0051d070[*(int*)(sub+0x1E0)]` -- indexed by generatorNumber (A=1..D=4),
|
||||
// the same shape as the condenser special beside it. Expose the number so the
|
||||
// alarm-lamp TU can do the authentic lookup (it had been probing the
|
||||
// PoweredSubsystem aux-screen fields, which generators never fill -- the
|
||||
// field-logged 'NO LAMP RESOLVED (generator=1)' silent leak).
|
||||
int BTGeneratorNumber(::Subsystem *sub)
|
||||
{
|
||||
return BTSubsystemIsGenerator(sub) ? ((Generator *)sub)->generatorNumber : -1;
|
||||
}
|
||||
|
||||
// Destruction -> OUT display state (see Generator::MarkGeneratorOut, the [T3
|
||||
// inferred link]): a destroyed generator must reach stateAlarm 4 or the
|
||||
// authored gotoEngineering/engEject FLASH invite (alarm conditions 4/5) never
|
||||
|
||||
Reference in New Issue
Block a user