prove generator FAILOVER, not just re-attach: BT_POWER_DETACH_TEST takes a subsystem name

The #62 verification so far only showed a subsystem detaching and re-attaching to
the SAME generator it started on.  That exercises the roster walk but never the
case players actually hit: your generator dies and Auto has to find a DIFFERENT
one.  (Raised by the operator, who also pointed out solo has no way to damage a
generator -- but it does not need one: a generator has its own on/off button.)

BT_POWER_DETACH_TEST now accepts a NAME (=PPC_1, =ERSLaser_1, ...) instead of
firing on whichever powered subsystem happens to tick first, so the scenario can
be aimed at a real weapon.  "1" keeps the old first-one behaviour.

Verified end-to-end, everything through real paths -- the detach via
DetachFromVoltageSource @004b0e30, the generator kill via its actual RIO button
0x1A through the click seam (EmitButton -> RIO queue -> manager drain ->
Generator::ToggleGeneratorOnOff @004b1ed0), no state pokes:

    BT_POWER_DETACH_TEST=PPC_1  BT_BTNTEST=0x1a,300,320  BT_POWER_LOG=1

    [power] TEST: detaching PPC_1 (forcing Auto)
    [power] AutoConnect RE-ATTACHED PPC_1 -> generator GeneratorA
    [btntest] PRESS 0x1a at poll 300            <- GeneratorA switched OFF
    [power] AutoConnect RE-ATTACHED PPC_1 -> generator GeneratorB

So the hunt skips the dead generator (HasVoltage requires GeneratorStateOf()==2
plus real measured voltage, powersub.cpp:860-876) and finds a live one.  Same
result first observed on Avionics; the named form proves it on a WEAPON, which
is the player-visible case.

Second proof in the same output: EXACTLY ONE re-attach line, then silence.  The
hunt re-runs every frame while `mode==Auto && !HasVoltage()`, so an
attached-but-dark weapon (the #21 symptom) would spam that line forever.  One
line then quiet means GeneratorB is really supplying it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joe DiPrima
2026-07-28 13:35:21 -05:00
co-authored by Claude Opus 5
parent 901cf1b459
commit 034e55c7f5
+11 -1
View File
@@ -367,8 +367,18 @@ void
// (file-static one-shot, NOT an instance member: the PoweredSubsystem layout
// is byte-locked by PoweredSubsystemLayoutCheck -- adding a field would
// break sizeof and every offset assert downstream.)
// BT_POWER_DETACH_TEST=1 detaches the FIRST powered subsystem to tick;
// BT_POWER_DETACH_TEST=<name> targets one by name (e.g. PPC_1, ERSLaser_1),
// which is what proves the failover on a WEAPON rather than on Avionics.
// Pair it with BT_BTNTEST=0x1a,<press>,<release> to switch GeneratorA off
// mid-mission through its real RIO button: the hunt must then re-attach the
// subsystem to a DIFFERENT generator, which is the case players actually hit
// (their generator dies) and the one a same-generator re-attach never tests.
static int s_detachTestDone = 0;
if (getenv("BT_POWER_DETACH_TEST") && !s_detachTestDone)
const char *detach_want = getenv("BT_POWER_DETACH_TEST");
if (detach_want != 0 && !s_detachTestDone
&& (detach_want[0] == '\0' || detach_want[1] == '\0' // "1" / empty = first one
|| (GetName() != 0 && strcmp(GetName(), detach_want) == 0)))
{
s_detachTestDone = 1;
DEBUG_STREAM << "[power] TEST: detaching " << GetName()