KB: document the 3 per-weapon loop/generator lamp databinding bugs

context/gauges-hud.md: new section recording the color-drop + shadow-field +
attribute-table-shift fixes for the btploop/btpbus lamps (commit e634709),
with the lesson that gauge value feeds must read named members through a
complete-type bridge, not AttributePointerOf+ResolveLink. Notes the eng-page
GeneratorVoltageConnection as the remaining sibling on the old path.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-21 00:09:48 -05:00
co-authored by Claude Opus 4.8
parent e634709e5d
commit 0477802971
+31
View File
@@ -136,6 +136,37 @@ log, `[ctrlmap] installing` ×2) — the tree then rebuilds bound to the NEW mec
`Remove(0)` flushes each gauge (`Update(gaugeRate_A)`, GAUGREND.cpp:3465) before deleting it, so
gauge CONNECTIONS may read the freed mech once more (plain reads; Execute stays SEH-guarded).
## Per-weapon panel loop/generator lamps — 3 stacked databinding bugs (2026-07-21) [T2 render-verified]
Each `SubsystemCluster` (@004c8140) per-weapon MFD panel draws two image-strip lamps in the
TEMP/STATUS area: **cooling-loop number** (`btploop.pcc`, frames OFF/1..6, `AnimatedSubsystemLamp`
@004c70a4, fed by `CoolingLoopConnection``BTCoolingLoopFrame`) and **generator letter**
(`btpbus.pcc`, frames OFF/A..D, `AnimatedSourceLamp` @004c7160, fed by `PowerSourceConnection`).
These are the "4 A / 1 B / 5 D" boxes in the reference. Both rendered COMPLETELY BLANK; three
independent bugs stacked (all fixed, commit e634709):
1. **Color drop** — both lamp ctors dropped the bg/fg color params the binary passes (bg=0xff,
fg=0, same as the sibling temp bar) and hardcoded `0,0`, so `OneOfSeveral::Execute` did
`SetColor(0)`+`DrawBitMapOpaque(0)` = black-on-black. Restored `0xff,0`.
2. **[[shadow-field]] trap (gotcha #2)** — `AnimatedSubsystemLamp`/`AnimatedSourceLamp` each
RE-DECLARED `int selected;` while already inheriting it from `OneOfSeveral` (@0xAC). The
connection's `&selected` bound the derived shadow copy; `OneOfSeveral::Execute` read the base
@0xAC (always 0) → every lamp stuck on frame 0 ("OFF"). Removing the redeclarations (so
`selected` resolves to the inherited member) fixed the loop NUMBER.
3. **Attribute-table shift (gotcha #8 / [[attribute-pointer]])** — the generator 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 resolved to 0 (OFF) even though the master
`PoweredSubsystem` ctor DID bind `voltageSource` to its Generator (`[busattach]` showed
bound=1). Fix: new `BTPowerSourceFrame(subsystem)` bridge (powersub.cpp) reads the NAMED member
via `PoweredSubsystem::ResolveVoltageSource()` and returns `Generator::generatorNumber`
(@0x1E0), bypassing the attribute table — same pattern as `BTCoolingLoopFrame`. The lamp caller
now passes `subsystem_in` (not the `InputVoltage` attribute slot). **Lesson: gauge value feeds
must read named members through a complete-type bridge, NOT `AttributePointerOf`+`ResolveLink`
— the attribute table's chained ids are unstable under the audio rows.** The eng-page
`GeneratorVoltageConnection` (evolt voltage bar, btl4gau2.cpp:1737) still uses the same
`AttributePointerOf("InputVoltage")` path and is the remaining sibling to convert.
Diagnostics retained (env `BT_LOOP_LOG`): `[loopfeed]` (BTCoolingLoopFrame) + `[busfeed]`
(BTPowerSourceFrame) print each lamp's resolved frame + source.
## The secondary screen's THREE views (Damage / Critical / Heat) — mode-gated [T0/T1/T2]
The `sec` port stacks three mode-gated mech-schematic layers at offset (50,0) over the
always-on radar/heading/speed/messageBoard (`Secondary1`): **Damage** (`ModeSecondaryDamage`,