The pod behaviour Cyd described -- "on a jam or bay fire the display eng button
for the system flashes" -- is authored data + a five-stage chain, now running:
MechTech::TechnicalAssistance (@004ad33c, per frame)
edge-scans every monitored subsystem's GetStatusFlags() 7-bit condition
mask (TechStatusType: Destroyed 0, Damaged 1, CoolantLeaking 2,
Overheating 3, AmmoBurning 4, Jammed 5, BadPower 6)
-> Start/StopEntityAlarmMessage (@00436688 id 7 size 0x20 / @004366b8 id 8
size 0x1C; broadcast @004364e4; port shape: direct
Start/StopEntityAlarmImplementation calls on the gauge renderer)
-> GaugeAlarmManager::Activate(alarmModel) -- alarmModel = MechTech+0x100 =
the 'mechalrm' ModelList (id 83) -> SearchList(83, type 31) -> the baked
GaugeAlarmStream (id 331, 11 items {condition, lampCode}), decoded:
Destroyed -> gotoEngineering + engCooling + engBusMode
CoolantLeaking -> gotoEngineering + engCooling
AmmoBurning -> gotoEngineering + engEject
Jammed -> gotoEngineering + engEject
BadPower -> gotoEngineering + engBusMode
-> BTL4GaugeAlarmManager::ReadGaugeAlarmStreamItem -- THE REAL BODY, from
@004cc2fc + helpers @004cc108/148/1a0/264/27c + tables @0051cf1c..0x51d084
(gotoEngineering 0x80 = the subsystem's QUAD-SELECT bezel button via
lamp[aux]/mode[aux] tables; 0x81+ descend the eng-page bank; Condenser /
Generator specials on CoolantLeaking; <0x80 = the heat-bank fixed map).
btl4galm.cpp's old bodies were admitted fabrications and its provenance
note ("no override body exists in the image") was wrong -- corrected.
-> LampManager::FindLamp (@00444c80) -> Lamp::SetAlertState (@00444e64, a
COUNTER so stacked alarms hold the flash) -> L4Lamp::NotifyOfStateChange
emits RIO flashFast states 0x37/0x13 (== T0 L4LAMP.cpp:234-239) -> the
pod's physical lamps AND the glass panels (PadRIO IS rioPointer there).
FOUR load-bearing defects found and fixed en route -- each independently fatal
to the feature:
1. HeatableSubsystem's Derivation chained Subsystem directly, SKIPPING
MechSubsystem (written before the WAVE-1 re-basing) -- so EVERY subsystem
on both family branches failed IsDerivedFrom(MechSubsystem), which is
exactly MechTech's monitor filter: the status scan watched NOTHING.
2. MechSubsystem::GetStatusFlags was non-virtual (binary: vtable slot 12) --
the scan's MechSubsystem* call bound statically to the base tier and the
weapon bits could never surface.
3. ProjectileWeapon::GetStatusFlags sat in a Ghidra export gap -- raw-disasm
@004bbf88: base | 0x20 (weaponAlarm==5 Jammed) | 0x10 (linked bin
cookOffArmed@0x18C AmmoBurning). The port had "defer to base".
4. Mech::Reset's respawn sweep blanket-cast every roster entry to
MechSubsystem and called RespawnRepair -- wrong for the Subsystem-level
entries (MechTech 0xBDC, SubsystemMessageManager 0xBD3). On MechTech the
recon damageZone slot lands on its subsystemMonitors chain head: NULL
while the scan was broken (fix #1's bug MASKED this one), but the moment
the monitors populated, RespawnRepair virtual-called through a
SubsystemMonitor as if it were a DamageZone -> load-time crash in
StateIndicator::SetState (caught with cdb; call [edx+14h] on code bytes).
The sweep now filters IsDerivedFrom(MechSubsystem) before the cast.
Also: GUID identities pinned -- 0x50f4bc = PoweredSubsystem::ClassDerivations
(via @004b1208 = its TestInstance; btl4gau2's two "Generator" comments were
wrong, swept), 0x50fb60 = Generator's. A shadow-field instance documented for
the deferred de-shadow: MechSubsystem::damageZone re-declares the PUBLIC engine
Subsystem::damageZone (SUBSYSTM.h:159) -- mechtech's naive `sub->damageZone`
read the never-written engine member (0 monitors again); now reads the recon
member via GetDamageZoneProxy(). Logged in open-questions.
Wiring: BTL4GaugeRenderer now constructs + assigns the BTL4GaugeAlarmManager
(the base ctor NULLs it and Activate Check()s it); MechTech's Report*/
StatusMessageSink stubs are real; alarmModel confirmed baked (= 83) at runtime.
VERIFIED LIVE (scratchpad/lampflash.py, BT_LAMP_LOG chain trace):
[techstat] MechTech id 32 monitors 29 subsystems, alarmModel 83
[techstat] LRM15_1 condition 4 SET (alarmModel 83) <- bay fire armed
[galarm] condition 4 code 0x80 -> lamp 0xd mode 0x1 FLASH
[lamp] 0xd <- 0x37 (FLASHING) <- the select button
[galarm] condition 4 code 0x85 -> lamp 0xb mode 0x4 FLASH <- engEject
[techstat] LRM15_1 condition 4 CLEARED <- detonation clears
[techstat] AmmoBinLRM15_1 condition 0 SET <- bin Destroyed
Regressions: baytest PASS (bay fire kills), baypurge PASS (purge extinguishes),
sim3 3-pod brawl PASS with ZERO crashes (6 kills, organic heat-route bay fires,
respawns clean through the new sweep filter).
Env: BT_LAMP_LOG ([techstat]/[galarm]/[lamp]). KB: gauges-hud (the flash
section), decomp-reference (the GaugeAlarm closure + tables + GUIDs),
open-questions (built-note + the de-shadow deferred item), btl4gau2 comment
sweep. checkctx CLEAN.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
362 lines
15 KiB
C++
362 lines
15 KiB
C++
//===========================================================================//
|
|
// File: btl4galm.cpp //
|
|
// Project: BattleTech Brick: Gauge Renderer Manager //
|
|
// Contents: BTL4GaugeAlarmManager -- the BattleTech override of the MUNGA //
|
|
// GaugeAlarmManager. It supplies the two per-item stream virtuals //
|
|
// that the base class declares pure ("not overridden!"): it knows how //
|
|
// to compile a named cockpit-gauge alarm definition into a memory //
|
|
// stream (CreateGaugeAlarmStreamItem) and how to instantiate a live //
|
|
// GaugeAlarm for a given subsystem/condition from that stream //
|
|
// (ReadGaugeAlarmStreamItem). //
|
|
//---------------------------------------------------------------------------//
|
|
// Date Who Modification //
|
|
// -------- --- ---------------------------------------------------------- //
|
|
// 02/22/96 CPB Initial coding. //
|
|
//---------------------------------------------------------------------------//
|
|
// Copyright (C) 1996, Virtual World Entertainment, Inc. All rights reserved //
|
|
// PROPRIETARY AND CONFIDENTIAL //
|
|
//===========================================================================//
|
|
//
|
|
// RECONSTRUCTED -- IMPORTANT PROVENANCE NOTE
|
|
// ------------------------------------------
|
|
// ⚠ 2026-07-25 (#47): THE CENTRAL CLAIM BELOW IS WRONG. The BTL4 override
|
|
// bodies DO exist in the shipped image, at @004cc148..@004cc2fc -- immediately
|
|
// BELOW the @004cc40c boundary this note drew:
|
|
// @004cc2fc ReadGaugeAlarmStreamItem: stream-reads {trigger level, lamp
|
|
// code}; when the subsystem's alarm level matches, maps the lamp
|
|
// (<0x80 fixed via @004cc148; >=0x80 SUBSYSTEM-RELATIVE eng-page
|
|
// button via @004cc1a0; Condenser @004cc264 / power-family
|
|
// @004cc27c specials), FindLamp @00444c80 on the renderer's lamp
|
|
// map (+0x1c0c8), Lamp::SetAlertState(@00444e64, the FLASH
|
|
// counter), and records the lamp on the GaugeAlarm's lampList.
|
|
// @004cc294 the Create-side sibling.
|
|
// This is the #47 ENG-BUTTON ATTENTION FLASH (jam / bay fire); the authored
|
|
// data survives as the type-31 GaugeAlarmStream in BTL4.RES (exactly 1:
|
|
// ModelList 'mechalrm' 83 -> stream 331). The bodies below ARE now the real
|
|
// re-transcriptions from those addresses (2026-07-25, same day). The
|
|
// original (wrong) note is preserved for the record:
|
|
//
|
|
// btl4galm.obj links after btl4grnd.obj and before btl4vid.obj (BTL4.MAK
|
|
// BTL4_OBJS order). In the shipped optimised image (BTL4OPT.EXE) there is **no
|
|
// distinct, separately-emitted BTL4GaugeAlarmManager override body**:
|
|
// * the only GaugeAlarmManager code in the binary is the MUNGA base class in
|
|
// gaugalrm.cpp (recovered/all/part_006.c, @00448928..@00448f48), including
|
|
// the two "not overridden!" trap virtuals
|
|
// CreateGaugeAlarmStreamItem @00448ab8 (asserts GAUGALRM.CPP:0x71)
|
|
// ReadGaugeAlarmStreamItem @00448ad4 (asserts GAUGALRM.CPP:0x7e)
|
|
// and the base driver helpers that CALL those virtuals
|
|
// GaugeAlarmManager::CreateGaugeAlarmStream @00448af0
|
|
// GaugeAlarmManager::BuildAlarmsForModel @00448d00
|
|
// * no subclass vtable (one whose Create/Read slots point into BattleTech
|
|
// code) appears in vtables.tsv, and no caller constructs a subclass
|
|
// (the base ctors @00448ebd/@00448edc/@00448efb have no external callers).
|
|
// The code region the linker reserved for btl4galm.obj (@004cc40c..@004cdac0)
|
|
// actually holds a 3-D HUD-model builder (PNAME1..8.bgf), i.e. the compiler
|
|
// folded BTL4GaugeAlarmManager's tiny overrides away / it was never instantiated
|
|
// in this build configuration.
|
|
//
|
|
// This file is therefore reconstructed to MATCH THE SURVIVING BTL4GALM.HPP and
|
|
// the base driver's calling contract (the argument order, the GaugeAlarm object
|
|
// it expects, and the "undefined alarm type ... resource not built" diagnostic
|
|
// the base prints when the virtual returns False). Bodies below are BEST-EFFORT
|
|
// (low confidence): they describe what the override must do for the base driver
|
|
// to function, not bytes lifted from this image.
|
|
//
|
|
// Base contract (recovered, high confidence):
|
|
// GaugeAlarmManager::CreateGaugeAlarmStream @00448af0
|
|
// - opens the "gaugeAlarm" sub-resource of a model record (FUN_00404720,
|
|
// "gaugeAlarm" @004eecc9), counts its entries, makes a MemoryStream
|
|
// (0x18), and for each entry calls the virtual
|
|
// this->CreateGaugeAlarmStreamItem(stream, entry_name, entry_data)
|
|
// (entry_name @entry+8, entry_data @entry[1]); if it returns 0 it prints
|
|
// "Model file '<model>' has undefined alarm type '<name>' -
|
|
// resource not built." (strings @004eecd4/@004eece1/@004eecfe)
|
|
// and aborts the build. On success it bakes the stream (FUN_00406f3c).
|
|
// GaugeAlarmManager::BuildAlarmsForModel @00448d00
|
|
// - for each baked alarm record it makes a GaugeAlarm (FUN_004489e8,
|
|
// 0x28 bytes; vtable PTR_FUN_004eed7c; ctor stores entity@+0xc,
|
|
// subsystem@+0x10, condition@+0x14), adds it to the manager's alarm list
|
|
// (this+4, list-insert vtbl+4), then calls the virtual
|
|
// this->ReadGaugeAlarmStreamItem(alarm, entity, subsystem, condition,
|
|
// stream)
|
|
// once per record to configure it.
|
|
//
|
|
// Engine-internal helper map (from the base + the BattleTech alarm bricks):
|
|
// FUN_004489e8 GaugeAlarm ctor FUN_00448a28 GaugeAlarm dtor
|
|
// FUN_00448ebd GaugeAlarmManager base ctor (chains a ChainOf<GaugeAlarm*>)
|
|
// FUN_0040385c Verify(msg,file,line)
|
|
// FUN_004dbb24 DebugStream << (char*) FUN_004db78c DebugStream << (int)
|
|
// DAT_00524e20 DebugStream (warning channel)
|
|
// MemoryStream write/read = (*stream + 0x20)(stream,&v,4) / (*stream+0x1c)(...)
|
|
//
|
|
|
|
#include <bt.hpp>
|
|
#pragma hdrstop
|
|
|
|
#if !defined(BTL4GALM_HPP)
|
|
# include <btl4galm.hpp>
|
|
#endif
|
|
#if !defined(APP_HPP)
|
|
# include <app.hpp>
|
|
#endif
|
|
|
|
|
|
//
|
|
// THE REAL OVERRIDE BODIES (Gitea #47, 2026-07-25) -- re-transcribed from the
|
|
// binary at @004cc294 (Create) / @004cc2fc (Read) + the mapping helpers
|
|
// @004cc108/@004cc148/@004cc1a0/@004cc264/@004cc27c and their data tables
|
|
// @0051cf1c..@0051d084. The previous bodies here were admitted fabrications
|
|
// ("threshold/range/state/flash" types that exist nowhere in the image); the
|
|
// provenance note at the top of this file records why.
|
|
//
|
|
// The STREAM FORMAT (verified against the shipped resource -- BTL4.RES carries
|
|
// ModelList 'mechalrm' id=83 -> GaugeAlarmStream id=331, 11 items):
|
|
// { int32 condition; int32 lampCode; } per item
|
|
// where condition = the MechSubsystem TechStatusType (the @0x50de74 name table:
|
|
// Destroyed 0, Damaged 1, CoolantLeaking 2, Overheating 3, AmmoBurning 4,
|
|
// Jammed 5, BadPower 6) and lampCode = the @0051cf1c vocabulary below.
|
|
//
|
|
// The shipped 'mechalrm' authoring (decoded 2026-07-25):
|
|
// Destroyed -> gotoEngineering + engCooling + engBusMode
|
|
// CoolantLeaking -> gotoEngineering + engCooling
|
|
// AmmoBurning -> gotoEngineering + engEject
|
|
// Jammed -> gotoEngineering + engEject
|
|
// BadPower -> gotoEngineering + engBusMode
|
|
// ("on a jam or bay fire the display eng button for the system flashes" --
|
|
// Cyd's pod testimony, verbatim in the data.)
|
|
//
|
|
|
|
//
|
|
// @0051cf1c -- the lamp-code name vocabulary ({char*, code} pairs, 0-terminated).
|
|
//
|
|
struct BTLampNameEntry { const char *name; int code; };
|
|
static const BTLampNameEntry kBTLampNames[] =
|
|
{
|
|
{ "coolingLoop1", 0x00 },
|
|
{ "coolingLoop2", 0x01 },
|
|
{ "coolingLoop3", 0x02 },
|
|
{ "coolingLoop4", 0x03 },
|
|
{ "coolingLoop5", 0x04 },
|
|
{ "coolingLoop6", 0x05 },
|
|
{ "gotoEngineering", 0x80 },
|
|
{ "engGeneratorA", 0x81 },
|
|
{ "engGeneratorB", 0x82 },
|
|
{ "engGeneratorC", 0x83 },
|
|
{ "engGeneratorD", 0x84 },
|
|
{ "engEject", 0x85 },
|
|
{ "engBusMode", 0x86 },
|
|
{ "engCooling", 0x87 },
|
|
{ "engBackToQuad", 0x88 },
|
|
{ 0, 0 }
|
|
};
|
|
|
|
//
|
|
// The lamp-resolution tables, byte-verified from the image:
|
|
// @0051cf9c quad-page mode masks [12] (aux screens 1..12)
|
|
// @0051cfcc eng-page mode masks [12]
|
|
// @0051cffc quad-select button lamp ids [12] (code 0x80 gotoEngineering)
|
|
// @0051d02c eng-page bank-top lamp ids [12] (codes 0x81.. descend from it)
|
|
// @0051d058 per-condenser lamps (index = condenserNumber @0x1D4, 1-based)
|
|
// @0051d070 per-placement lamps (index = auxScreenPlacement @0x1E0)
|
|
//
|
|
static const int kBTQuadModeMask[12] = { 0x1,0x1,0x1,0x1, 0x20,0x20,0x20,0x20, 0x400,0x400,0x400,0x400 };
|
|
static const int kBTEngModeMask[12] = { 0x2,0x4,0x8,0x10, 0x40,0x80,0x100,0x200, 0x800,0x1000,0x2000,0x4000 };
|
|
static const int kBTQuadLamp[12] = { 0xF,0xD,0xB,0x9, 0x27,0x25,0x23,0x21, 0x7,0x5,0x3,0x1 };
|
|
static const int kBTEngBankTop[12] = { 0xF,0xF,0xF,0xF, 0x27,0x27,0x27,0x27, 0x7,0x7,0x7,0x7 };
|
|
static const int kBTCondenserLamp[6] = { 0x7, 0x2F,0x2E,0x2D,0x2B,0x2A }; // [condenserNumber]
|
|
static const int kBTPlacementLamp[5] = { 0x29, 0x1A,0x1B,0x1C,0x1D }; // [auxScreenPlacement]
|
|
|
|
//
|
|
// @004cc148 -- the fixed (<0x80) map: coolingLoop1..6 -> the heat-display bank.
|
|
//
|
|
static int BTFixedLampOf(int code)
|
|
{
|
|
static const int kFixed[6] = { 0x2F, 0x2E, 0x2D, 0x2C, 0x2B, 0x2A };
|
|
return (code >= 0 && code < 6) ? kFixed[code] : -1;
|
|
}
|
|
|
|
//
|
|
// @004cc108 -- map an authored lamp NAME to its code.
|
|
//
|
|
static Logical BTLampCodeOf(const char *data, int *out_code)
|
|
{
|
|
for (const BTLampNameEntry *e = kBTLampNames; e->name != 0; ++e)
|
|
{
|
|
if (strcmp(data, e->name) == 0) // FUN_004d4b58
|
|
{
|
|
*out_code = e->code;
|
|
return True;
|
|
}
|
|
}
|
|
return False;
|
|
}
|
|
|
|
static Logical BTLampLog()
|
|
{
|
|
static int s_on = -1;
|
|
if (s_on < 0) s_on = (getenv("BT_LAMP_LOG") != 0) ? 1 : 0;
|
|
return s_on ? True : False;
|
|
}
|
|
|
|
//
|
|
// BTL4GaugeAlarmManager::CreateGaugeAlarmStreamItem -- @004cc294 [T1]
|
|
//
|
|
// iVar1 = FUN_004ac194(name, &condition); // MechSubsystem::LookupStatusType
|
|
// if (!iVar1) return 0;
|
|
// iVar1 = FUN_004cc108(data, &code); // the @0051cf1c vocabulary
|
|
// if (!iVar1) return 0;
|
|
// stream->WriteBytes(&condition, 4); // (*stream+0x20)
|
|
// stream->WriteBytes(&code, 4);
|
|
// return 1;
|
|
//
|
|
// (Bake-side only -- the shipped BTL4.RES already carries the baked stream; this
|
|
// matters when re-baking resources from notation.)
|
|
//
|
|
Logical
|
|
BTL4GaugeAlarmManager::CreateGaugeAlarmStreamItem(
|
|
MemoryStream *mem_stream,
|
|
const char *alarm_name,
|
|
const char *alarm_data
|
|
)
|
|
{
|
|
int condition, code;
|
|
|
|
if (!MechSubsystem::LookupStatusType(alarm_name, &condition)) // FUN_004ac194
|
|
{
|
|
return False; // -> "has undefined alarm type ... resource not built"
|
|
}
|
|
if (!BTLampCodeOf(alarm_data, &code)) // FUN_004cc108
|
|
{
|
|
return False;
|
|
}
|
|
mem_stream->WriteBytes(&condition, sizeof(condition));
|
|
mem_stream->WriteBytes(&code, sizeof(code));
|
|
return True;
|
|
}
|
|
|
|
//
|
|
// BTL4GaugeAlarmManager::ReadGaugeAlarmStreamItem -- @004cc2fc [T1]
|
|
//
|
|
// Read one {condition, lampCode} item; when the item's condition equals the
|
|
// condition being ACTIVATED, resolve the lamp:
|
|
// * Condenser-derived (0x50e4fc) + condition CoolantLeaking(2):
|
|
// lamp = @0051d058[condenserNumber@0x1D4] (its own loop button)
|
|
// * Generator-derived (0x50fb60) + condition CoolantLeaking(2):
|
|
// lamp = @0051d070[auxScreenPlacement@0x1E0] (its radar-rail button)
|
|
// * else code < 0x80: the fixed heat-bank map (@004cc148)
|
|
// * else code >= 0x80: PoweredSubsystem-derived only (0x50f4bc -- the same
|
|
// gate BTGetSubsystemAuxScreen applies) + auxScreen@0x1DC > 0:
|
|
// 0x80 gotoEngineering: lamp = @0051cffc[aux], mode = @0051cf9c[aux]
|
|
// 0x81..: lamp = @0051d02c[aux] - (code - 0x81), mode = @0051cfcc[aux]
|
|
// then FindLamp(lamp, mode) on the renderer lamp manager (@00444c80), start it
|
|
// flashing (Lamp::SetAlertState(True) @00444e64 -- a COUNTER, alarms stack), and
|
|
// record it on the GaugeAlarm lampList so ~GaugeAlarm un-flashes on Deactivate.
|
|
// A lamp code that resolves to no lamp is silently skipped (iVar2 = -1 path).
|
|
//
|
|
// (0x50f4bc = PoweredSubsystem::ClassDerivations, NOT Generator -- pinned via
|
|
// @004b1208 = PoweredSubsystem::TestInstance in the powersub method cluster;
|
|
// 0x50fb60 = the Generator one, adjacent to its message table @0x50fb90.)
|
|
//
|
|
void
|
|
BTL4GaugeAlarmManager::ReadGaugeAlarmStreamItem(
|
|
GaugeAlarm *alarm,
|
|
Entity * /*the_entity*/,
|
|
Subsystem *the_subsystem,
|
|
Enumeration the_condition,
|
|
MemoryStream *mem_stream
|
|
)
|
|
{
|
|
int item_condition = -1, lamp_code = -1;
|
|
mem_stream->ReadBytes(&item_condition, sizeof(item_condition)); // (*stream+0x1c)
|
|
mem_stream->ReadBytes(&lamp_code, sizeof(lamp_code));
|
|
|
|
if ((int)the_condition != item_condition)
|
|
{
|
|
return;
|
|
}
|
|
|
|
extern int BTSubsystemIsCondenser(::Subsystem *sub); // heat.cpp (0x50e4fc)
|
|
extern int BTCondenserNumber(::Subsystem *sub); // heat.cpp (+0x1D4)
|
|
extern int BTSubsystemIsGenerator(::Subsystem *sub); // powersub.cpp (0x50fb60)
|
|
extern bool BTGetSubsystemAuxScreen(::Subsystem *sub, int *screen, int *placement, char *label64); // powersub.cpp (0x50f4bc gate + 0x1DC/0x1E0)
|
|
|
|
int lamp_id = -1;
|
|
int mode = -1; // local_10: stays -1 for the fixed/family paths
|
|
|
|
if (BTSubsystemIsCondenser(the_subsystem))
|
|
{
|
|
if (the_condition == 2) // CoolantLeaking
|
|
{
|
|
int n = BTCondenserNumber(the_subsystem);
|
|
if (n >= 0 && n < 6)
|
|
lamp_id = kBTCondenserLamp[n];
|
|
}
|
|
}
|
|
else if (BTSubsystemIsGenerator(the_subsystem))
|
|
{
|
|
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];
|
|
}
|
|
}
|
|
else if (lamp_code < 0x80)
|
|
{
|
|
lamp_id = BTFixedLampOf(lamp_code);
|
|
}
|
|
else
|
|
{
|
|
int screen = 0, placement = -1;
|
|
if (BTGetSubsystemAuxScreen(the_subsystem, &screen, &placement, 0) // PoweredSubsystem gate
|
|
&& screen > 0)
|
|
{
|
|
int aux = screen - 1; // +0x1DC - 1
|
|
if (aux < 12)
|
|
{
|
|
if (lamp_code == 0x80) // gotoEngineering
|
|
{
|
|
lamp_id = kBTQuadLamp[aux];
|
|
mode = kBTQuadModeMask[aux];
|
|
}
|
|
else // engGeneratorA..engBackToQuad
|
|
{
|
|
lamp_id = kBTEngBankTop[aux] - (lamp_code - 0x81);
|
|
mode = kBTEngModeMask[aux];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lamp_id < 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
//
|
|
// @004cc2fc tail: FindLamp on the gauge renderer lamp manager, flash it,
|
|
// and record it on the alarm. (DAT_004efc94+0x4c = the gauge renderer.)
|
|
//
|
|
GaugeRenderer *renderer = (GaugeRenderer *)application->GetGaugeRenderer();
|
|
if (renderer == 0)
|
|
{
|
|
return;
|
|
}
|
|
Lamp *lamp = (renderer->GetLampManager() != 0)
|
|
? renderer->GetLampManager()->FindLamp((LampID)lamp_id, (ModeMask)mode)
|
|
: 0;
|
|
|
|
if (BTLampLog())
|
|
DEBUG_STREAM << "[galarm] condition " << (int)the_condition
|
|
<< " code 0x" << std::hex << lamp_code
|
|
<< " -> lamp 0x" << lamp_id << " mode 0x" << mode << std::dec
|
|
<< (lamp ? " FLASH" : " (no lamp registered -- skipped)") << "\n" << std::flush;
|
|
|
|
if (lamp != 0)
|
|
{
|
|
lamp->SetAlertState(True); // FUN_00444e64 -- the flash counter
|
|
alarm->lampList.Add(lamp); // un-flashed by ~GaugeAlarm on Deactivate
|
|
}
|
|
}
|