Gauges: fix blank per-weapon loop/generator lamps (4A/1B/5D boxes)

The SubsystemCluster per-weapon MFD panels render two image-strip lamps in
the TEMP/STATUS area: the cooling-loop number (btploop, 1..6) and the
generator letter (btpbus, A..D). Both drew as completely empty boxes.
Three stacked databinding bugs, all now fixed:

1. Color drop (btl4gau2.cpp): AnimatedSubsystemLamp/AnimatedSourceLamp
   ctors dropped the bg/fg color params the binary passes (bg=0xff,fg=0,
   same as the neighboring temp bar) and hardcoded 0,0 -> OneOfSeveral::
   Execute did SetColor(0)+DrawBitMapOpaque(0), i.e. black-on-black.
   Restored 0xff,0 (verified vs @004c70a4 / caller SubsystemCluster
   @004c8140).

2. Shadow-field trap (btl4gau2.hpp, gotcha #2): both lamp classes
   re-declared `int selected;` while already inheriting it from
   OneOfSeveral (@0xAC). The CoolingLoop/PowerSource connection wrote the
   derived shadow copy while OneOfSeveral::Execute read the base @0xAC
   (always 0) -> every lamp stuck on frame 0 ("OFF"). Removed the
   redeclarations so &selected binds the inherited member. Loop numbers
   now render (verified: PPC->4, Myomers->5, ERMLaser->1/6, etc.).

3. Attribute-table shift (powersub.cpp + btl4gau2.cpp, gotcha #8): the
   generator-letter lamp resolved its source via
   ResolveLink(AttributePointerOf(subsystem,"InputVoltage")), but the
   BT_DEV_GAUGES audio attribute rows shifted the chained attribute ids so
   AttributePointerOf no longer landed on voltageSource@0x1D0 -> the link
   always resolved to 0 (OFF) even though the master PoweredSubsystem ctor
   DID bind voltageSource to its Generator. New BTPowerSourceFrame bridge
   reads the NAMED member via PoweredSubsystem::ResolveVoltageSource() and
   returns Generator::generatorNumber (@0x1E0), bypassing the attribute
   table -- the same pattern as the BTCoolingLoopFrame fix. Generator
   letters now render (verified: PPC_1->GeneratorA="A", Myomers->
   GeneratorD="D", SRM6->GeneratorB="B").

Result: the "4 A / 1 B / 5 D" boxes render with both the loop number and
generator letter, matching the reference. Kept BT_LOOP_LOG-gated
[loopfeed]/[busfeed] feed diagnostics; both pod + glass builds clean.

Awaiting live playtest verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-21 00:08:58 -05:00
co-authored by Claude Opus 4.8
parent c79b9953f9
commit e634709e5d
4 changed files with 120 additions and 14 deletions
+26 -8
View File
@@ -204,9 +204,19 @@ protected:
//
// PowerSourceConnection -- @004c31ec ctor / @004c3258 sampler (vt 0x518e9c).
// Resolves the power source (Resolve(source)) and copies its bus-lamp state
// (+0x1e0); 0 if unresolved.
// The binary resolves the subsystem's InputVoltage link and reads
// resolved+0x1E0 == Generator::generatorNumber (1..4 -> the btpbus generator-
// letter frame A..D; 0 == OFF).
// DATABINDING FIX 2026-07-20 (gotcha 8, sibling of the CoolingLoop fix above):
// the binary's path was ResolveLink(AttributePointerOf(subsystem,"InputVoltage"))
// but the BT_DEV_GAUGES audio attribute rows shifted the chained attribute ids
// so AttributePointerOf no longer lands on voltageSource@0x1D0 -- the link always
// resolved to 0 and every generator lamp drew frame 0 ("OFF"). 'source' now
// carries the SUBSYSTEM directly and BTPowerSourceFrame (powersub.cpp) reads the
// NAMED voltageSource member via ResolveVoltageSource(), bypassing the attribute
// table.
//
extern int BTPowerSourceFrame(void *subsystem);
class PowerSourceConnection : public GaugeConnection
{
public:
@@ -214,8 +224,7 @@ public:
: GaugeConnection(0), source(source), destination(destination) {}
void Update() // @004c3258
{
void *resolved = ResolveLink(source);
*destination = (resolved == 0) ? 0 : *(int *)((char *)resolved + 0x1e0);
*destination = BTPowerSourceFrame(source);
}
protected:
void *source; // @0x10
@@ -707,8 +716,13 @@ AnimatedSubsystemLamp::AnimatedSubsystemLamp(
void *subsystem,
const char *identification_string
):
// COLOR FIX 2026-07-20 (verified vs binary @004c70a4 / caller SubsystemCluster
// @004c8140): the ctor DROPPED the background/foreground color params the binary
// passes and hardcoded 0,0 -- so Execute's SetColor(0)+DrawBitMapOpaque(0) drew
// the loop/gen boxes black-on-black (invisible). The binary passes bg=0xff,fg=0
// (the MFD on-color, same as the neighboring temp bar) -- restored.
OneOfSeveral(rate, mode_mask, renderer_in, graphics_port_number, // FUN_004c4d88
x, y, True /*fromImageStrip*/, image, 0, 0, columns, rows,
x, y, True /*fromImageStrip*/, image, 0xff, 0, columns, rows,
identification_string)
{
selected = 0; // @0xAC this[0x2B]
@@ -735,8 +749,10 @@ AnimatedSourceLamp::AnimatedSourceLamp(
void *source,
const char *identification_string
):
// COLOR FIX 2026-07-20 (same drop as AnimatedSubsystemLamp above): restore the
// binary's bg=0xff,fg=0 so the generator-letter bus lamp draws (was 0,0 = blank).
OneOfSeveral(rate, mode_mask, renderer_in, graphics_port_number,
x, y, True, image, 0, 0, columns, rows, identification_string)
x, y, True, image, 0xff, 0, columns, rows, identification_string)
{
selected = 0;
AddConnection(new PowerSourceConnection(&selected, source)); // FUN_004c31ec
@@ -1402,7 +1418,9 @@ SubsystemCluster::SubsystemCluster(
else
powerSourceA = new AnimatedSourceLamp(ChildRate(), mfd_mode, renderer_in, // @004c7160
mfd_port, x + 0x10e, y + 0xe, "btpbus.pcc", 5, 1,
inputVoltage, "PowerSource");
subsystem_in, "PowerSource"); // pass the SUBSYSTEM -- BTPowerSourceFrame
// reads voltageSource by name (attribute-shift
// databinding fix); NOT the inputVoltage slot
// Background: image_names[ auxScreenPlacement ] if present. (Placement@0x1e0 is
// read via the PoweredSubsystem bridge, not the non-byte-exact raw offset.)
@@ -1444,7 +1462,7 @@ SubsystemCluster::SubsystemCluster(
else
{
powerSourceB = new AnimatedSourceLamp(ChildRate(), eng_mode, renderer_in, // @004c7160
engPort, 0x1a, 0xd0, "btebus.pcc", 5, 1, inputVoltage, "PowerSource");
engPort, 0x1a, 0xd0, "btebus.pcc", 5, 1, subsystem_in, "PowerSource"); // see powerSourceA
generatorVoltageBar = new ScalarBarGauge(ChildRate(), eng_mode, renderer_in, // @004c721c
engPort, 0x89, 0x82, 0x93, 0x13b, "evolt.pcc", 0xff, 0,