four ENG-page lamps were invisible, not missing: the ctors dropped their colour parameters
Playtest report: "generators don't seem to have an Auto setting" / "no auto mode is ever displayed", plus the operator's own memory that the BUS MODE button once stepped through three states. The state machine was NEVER wrong: @004b0abc has exactly two branches (<2 -> Auto(2); ==2 -> detach + Off(0)), Manual(1) is set only by the four SelectGenerator buttons, and the auto-hunt gates on ==2 -- all byte-verified, and the #62 re-attach fires live. Manual is a one-way door out of BUS MODE by design: a single cycle button cannot know WHICH generator manual should mean. Verified on-screen by the operator this session: A-D returns to manual, BUS MODE toggles auto/off thereafter. What was actually broken: the connect-mode lamp -- and three siblings -- never drew a pixel. OneOfSeveralStates (@004c5470) and OneOfSeveralInt (@004c5148) forward caller-supplied background/foreground colours in the binary; the recon dropped both parameters and hardcoded 0,0 into the base. A BitMap-strip lamp draws SetColor(bg) + DrawBitMapOpaque(fg,...), so 0/0 painted colour-0 on colour-0: invisible. Affected: btemode (connect mode, 1x3 -- THE report), btecmode (coolant on/off, 1x2), and both bteseek gear-step lamps (1x4). The cluster call sites pass 0xff/0, byte-verified (@004c866c disasm; part_014.c:1479-1481, :2146-2147). Same dropped-element family as issue #42's MoveToAbsolute. THE TRAP THAT WAS NOT LANDED, recorded so it stays unlanded: with the lamp first made visible, the frames appeared inverted against the levels (art reads AUTO/MANUAL/OFF top-down; levels run OFF/MANUAL/AUTO), and a row=(rows-1)-selected "fix" was proposed. An adversarial workflow proved it wrong: the gauge blit addresses SOURCE rows BOTTOM-UP (Video16BitBuffered::DrawBitMapOpaque, L4VB16.cpp:3846-3850 -- sTop = map_max_y - sTop, rows walked upward), the 1995 blit @0046bdfc performs the identical flip, and the vertical strips are AUTHORED bottom-up to match. Identity level->row therefore draws the pod-correct display; the inversion would have created the very bug it claimed to cure. Two of five investigators (and the first human pass) assumed top-down; the engine source overruled all three. Convention + warning now recorded in context/gauges-hud.md. btecmode doubles as the standing tripwire: a second vertical strip that must show ON when coolant is available -- if it ever reads inverted, the bottom-up verdict is falsified. Also corrected: @004c552c is OneOfSeveralStates' EXECUTE override (clamp >= 0, chain the base draw) -- the port had the body on BecameActive under a wrong label; vtable-diffed against OneOfSeveral (0x518b24 vs 0x518bf0). BecameActive is inherited. Behaviorally inert today (the state source never goes negative), byte-faithful now. README: the "KNOWN ISSUE -- automatic re-attach is not working yet" text is replaced with how power routing actually works (A-D = manual, BUS MODE = auto then off, two presses off / one back to auto). That text shipped in 600, which already contained the #62 fix -- players were being TOLD auto was broken while it worked, which is half of how a painted-out lamp became "no auto mode". Diagnostic kept: BT_GENSEL_TEST=<id> now drives any of the five power-routing message ids (4..8, default 7) and pulses four times, so the whole mode cycle is observable headlessly under BT_FIRE_LOG ([gensel] lines). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
c32d02b3cc
commit
901cf1b459
@@ -1466,8 +1466,9 @@ SubsystemCluster::SubsystemCluster(
|
||||
engPort, 0x254, 0x13b, "bteloop.pcc", 7, 1, subsystem_in, "CoolingLoop");
|
||||
|
||||
modeLamp = new OneOfSeveralInt(ChildRate(), eng_mode, renderer_in, // @004c5148
|
||||
engPort, 400, 10, "btecmode.pcc", 1, 2,
|
||||
(int *)((char *)subsystem_in + 0x134), "OneOfSeveralInt"); // BEST-EFFORT raw offset
|
||||
engPort, 400, 10, "btecmode.pcc", 0xff, 0, 1, 2, // colours byte-verified:
|
||||
(int *)((char *)subsystem_in + 0x134), "OneOfSeveralInt"); // part_014.c:1479-1481
|
||||
// (+0x134 = coolantAvailable)
|
||||
|
||||
if (inputVoltage == NULL)
|
||||
{
|
||||
@@ -1488,9 +1489,16 @@ SubsystemCluster::SubsystemCluster(
|
||||
// stateLamp gate: IsDerivedFrom 0x50f4bc = POWEREDSUBSYSTEM (#47 correction --
|
||||
// the old 'Generator' label was wrong; every powered subsystem passes).
|
||||
if (IsGeneratorDerived(subsystem_in))
|
||||
// bg=0xff fg=0 -- byte-verified from the binary's own call site
|
||||
// @004c866c (`push 3 / push 1 / push 0 / push 0xff / push
|
||||
// "btemode.pcc"`). These were previously dropped and hardcoded 0/0
|
||||
// inside the ctor, which painted the lamp in colour 0: the connect
|
||||
// mode cycled correctly but nothing was ever drawn, so Auto looked
|
||||
// like it did not exist.
|
||||
stateLamp = new OneOfSeveralStates(ChildRate(), eng_mode, renderer_in, // @004c5470
|
||||
engPort, 0xbe, 0, "btemode.pcc", 1, 3,
|
||||
(Entity *)((char *)subsystem_in + 0x2b8), "OneOfSeveralStates"); // BEST-EFFORT raw
|
||||
engPort, 0xbe, 0, "btemode.pcc", 0xff, 0, 1, 3,
|
||||
(Entity *)((char *)subsystem_in + 0x2b8), "OneOfSeveralStates"); // +0x2b8 = modeAlarm
|
||||
// (offset static_asserted)
|
||||
else
|
||||
stateLamp = NULL;
|
||||
}
|
||||
@@ -1748,7 +1756,7 @@ MyomerCluster::MyomerCluster(
|
||||
(AttributeAccessor *)&seekValue, "edestryd.pcc", False, "EngrGraph");
|
||||
|
||||
seekStepLamp = new OneOfSeveralInt(ChildRate(), eng_mode, renderer_in, // @004c5148
|
||||
engPort, 0xf, 0, "bteseek.pcc", 1, 4,
|
||||
engPort, 0xf, 0, "bteseek.pcc", 0xff, 0, 1, 4, // colours byte-verified: part_014.c:2146-2147
|
||||
// gauge-complete wave: 0x800 was OOB for a 0x358 Myomers (garbage) -> the seek
|
||||
// gear step is Myomers::currentSeekVoltageIndex@0x320 (the analog of the
|
||||
// EnergyWeaponCluster's Emitter::seekVoltageIndex@0x3f0; same 1..4 semantics).
|
||||
@@ -1934,7 +1942,7 @@ EnergyWeaponCluster::EnergyWeaponCluster(
|
||||
"edestryd.pcc", True, "EngrGraph");
|
||||
|
||||
seekStepLamp = new OneOfSeveralInt(ChildRate(), eng_mode, renderer_in, // @004c5148
|
||||
engPort, 0xf, 0, "bteseek.pcc", 1, 4,
|
||||
engPort, 0xf, 0, "bteseek.pcc", 0xff, 0, 1, 4, // colours byte-verified: part_014.c:2146-2147
|
||||
(int *)((char *)subsystem_in + 0x3f0), "OneOfSeveralInt"); // BEST-EFFORT raw
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user