#98: leaking condensers now flash the RIGHT button -- half of them flashed the wrong one, one flashed nothing
Field reports were all "intermittent": "the display buttons aren't always
flashing or lighting up on leaking components" (Oracle), "I'm getting leaks but
no indicators" (Lynx), "I am getting indicators sometimes" (Sauron). It is not
intermittent -- it is per-condenser, and three of the six were wrong.
condenserNumber is 1-BASED (verified live: 'Condenser6' reports 6), which the
lamp table's own comment stated. The guard was `n >= 0 && n < 6` -- a 0-based
bound -- and the table it indexed was missing 0x2C:
condenser 1..3 -> 0x2F 0x2E 0x2D correct
condenser 4 -> 0x2B WRONG (loop 5's button)
condenser 5 -> 0x2A WRONG (loop 6's button)
condenser 6 -> rejected NOTHING flashes
So a leak in loop 6 annunciated nowhere, loops 4-5 lit a neighbour's button, and
loops 1-3 were fine -- which from the cockpit reads exactly as "sometimes".
Condenser N drives cooling-loop N, whose six lamps are the same ones the
coolingLoop1..6 codes already resolve through, so the fix routes condensers
through that verified map (BTFixedLampOf(N-1)) and retires the duplicate,
partly-wrong table rather than patching it.
⚠ PROVENANCE: the retired table cited @0051d058 as byte-verified. That address
holds gauge-type NAME STRINGS, not lamp ids, and a byte search for the six loop
ids as consecutive int32 finds nothing -- so neither the old table nor the new
mapping is byte-verified. The correction rests on three checkable things: the
1-based numbering (live), the guard contradicting its own documented indexing,
and six condensers mapping onto the six cooling-loop lamps of the verified fixed
map. [T2 -- behaviour verified, not byte-grounded.]
Also adds the missing diagnostic on the silent path: an alarm item that matched
its condition but resolved no lamp now names the subsystem and why, instead of
returning quietly. That is what found this, and it immediately surfaced a
SECOND gap for someone to pick up: a destroyed HeatSink (condition 0) resolves
no lamp either, because it is neither Condenser nor Generator nor a
PoweredSubsystem with an aux screen.
Verified (scratchpad/night8/leaklamp.sh, BT_LAMP_LOG):
before [galarm] condition 2 ... sub 'Condenser6' -> NO LAMP RESOLVED
after [galarm] condition 2 ... -> lamp 0x2a FLASH
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
bb7a6abe70
commit
0254d9ef34
@@ -163,7 +163,8 @@ static const int kBTQuadModeMask[12] = { 0x1,0x1,0x1,0x1, 0x20,0x20,0x20,0x20, 0
|
||||
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]
|
||||
// (the per-condenser lamp table that used to live here is retired: condenser N
|
||||
// resolves through BTFixedLampOf(N-1), the same six cooling-loop lamps. #98)
|
||||
static const int kBTPlacementLamp[5] = { 0x29, 0x1A,0x1B,0x1C,0x1D }; // [auxScreenPlacement]
|
||||
|
||||
//
|
||||
@@ -287,9 +288,25 @@ void
|
||||
{
|
||||
if (the_condition == 2) // CoolantLeaking
|
||||
{
|
||||
//
|
||||
// #98 -- "I'm getting leaks but no indicators" / "the display
|
||||
// buttons aren't ALWAYS flashing on leaking components".
|
||||
//
|
||||
// condenserNumber is 1-BASED (verified live: 'Condenser6' reports 6),
|
||||
// which the old table's own comment said -- but the guard was
|
||||
// `n >= 0 && n < 6`, a 0-based bound. Condenser 6 was therefore
|
||||
// REJECTED outright and could never annunciate, and the table it
|
||||
// indexed was missing 0x2C, so condensers 4 and 5 flashed the NEXT
|
||||
// loop's button instead of their own. Three of six correct, one
|
||||
// silent, two lying -- exactly the "sometimes" players reported.
|
||||
//
|
||||
// Condenser N drives cooling-loop N, whose six lamps are the same
|
||||
// ones the coolingLoop1..6 codes resolve to, so use that verified
|
||||
// map rather than a second, partly-wrong copy of it.
|
||||
//
|
||||
int n = BTCondenserNumber(the_subsystem);
|
||||
if (n >= 0 && n < 6)
|
||||
lamp_id = kBTCondenserLamp[n];
|
||||
if (n >= 1 && n <= 6)
|
||||
lamp_id = BTFixedLampOf(n - 1); // loop N -> its own button
|
||||
}
|
||||
}
|
||||
else if (BTSubsystemIsGenerator(the_subsystem))
|
||||
@@ -331,6 +348,21 @@ void
|
||||
|
||||
if (lamp_id < 0)
|
||||
{
|
||||
// DIAGNOSTIC (#98): this is the SILENT path -- the item matched the
|
||||
// condition but no lamp could be resolved for this subsystem, so nothing
|
||||
// flashes and nothing was logged. Players see "leaking but no
|
||||
// indicator". Name the subsystem and why it fell through, so the
|
||||
// mapping gap is visible in a field log instead of being invisible.
|
||||
if (BTLampLog())
|
||||
DEBUG_STREAM << "[galarm] condition " << (int)the_condition
|
||||
<< " code 0x" << std::hex << lamp_code << std::dec
|
||||
<< " sub '" << (the_subsystem && the_subsystem->GetName()
|
||||
? the_subsystem->GetName() : "?")
|
||||
<< "' -> NO LAMP RESOLVED (condenser=" << BTSubsystemIsCondenser(the_subsystem)
|
||||
<< " condenserNumber=" << (BTSubsystemIsCondenser(the_subsystem)
|
||||
? BTCondenserNumber(the_subsystem) : -1)
|
||||
<< " generator=" << BTSubsystemIsGenerator(the_subsystem)
|
||||
<< ")" << std::endl << std::flush;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env bash
|
||||
# #98: which leaking components actually FLASH their panel button?
|
||||
#
|
||||
# Players: "the display buttons aren't always flashing or lighting up on leaking
|
||||
# components" (Oracle), "I'm getting leaks but no indicators" (Lynx), "I am
|
||||
# getting indicators sometimes" (Sauron). Intermittent, not simply unwired.
|
||||
#
|
||||
# The chain is: HeatSink::GetStatusFlags raises bit 0x4 (CoolantLeaking) when
|
||||
# coolantActive && HeatModelActive -> MechTech::TechnicalAssistance sees the bit
|
||||
# CHANGE and calls ReportStatusSet -> GaugeAlarmManager::Activate -> the
|
||||
# per-item lamp resolve in btl4galm.cpp.
|
||||
#
|
||||
# BT_LAMP_LOG prints all three stages:
|
||||
# [techstat] <sub> condition 2 SET / CLEARED -- the edge the alarm rides
|
||||
# [galarm] ... -> lamp 0x.. FLASH -- resolved and flashing
|
||||
# [galarm] ... -> NO LAMP RESOLVED (...) -- matched but no lamp (NEW)
|
||||
#
|
||||
# Damage the mech steadily so heat subsystems take crits and start leaking.
|
||||
set -x
|
||||
. /c/git/bt411/scratchpad/night6/bench_common.sh
|
||||
cd /c/git/bt411/content || exit 1
|
||||
taskkill //F //IM btl4.exe > /dev/null 2>&1
|
||||
sleep 2
|
||||
sed "s/^map=.*/map=grass/; s/^time=.*/time=day/" MP.EGG > LEAK.EGG
|
||||
|
||||
LOG=leaklamp_${1:-post}.log
|
||||
rm -f "$LOG"
|
||||
|
||||
# Self-damage keeps crits landing on the heat family; autofire keeps heat LOAD
|
||||
# up, which is what coolantDraw (= zoneDamage x heatLoad) scales with.
|
||||
BT_LAMP_LOG=1 BT_COOL_LOG=1 BT_DMG_LOG=1 \
|
||||
BT_SPAWN_ENEMY=1 BT_AUTOFIRE=1 BT_AF_PERIOD=2 \
|
||||
BT_SELF_DAMAGE=4 BT_SELF_DAMAGE_ZONE=${2:-dz_rarm} \
|
||||
bt_launch "$LOG" LEAK.EGG 0x03
|
||||
|
||||
sleep 150
|
||||
taskkill //F //IM btl4.exe > /dev/null 2>&1
|
||||
sleep 2
|
||||
|
||||
echo "=== coolant-leak status edges (condition 2) ==="
|
||||
grep -E "^\[techstat\].*condition 2" "$LOG" | sort | uniq -c | sort -rn | head -15
|
||||
echo "=== lamp resolution ==="
|
||||
grep -E "^\[galarm\]" "$LOG" | sed 's/[0-9a-fx]\{3,\}/N/g' | sort | uniq -c | sort -rn | head -12
|
||||
Reference in New Issue
Block a user