vehicleSubSystems Phase 2: authentic aux-screen assignment -> panels build

The engineering-screen cluster panels now build for each subsystem on its real
aux-screen position.  Two pieces:

1. Aux-screen bridge (powersub.cpp BTGetSubsystemAuxScreen): the assignment lives
   on PoweredSubsystem (auxScreenNumber/Placement/Label, resource +0x104/108/10C)
   which our ctor already populates -- but the reconstructed heat-leaf branch is
   NOT byte-exact, so the Make's raw sub[0x1dc]/[0x1e0]/[0x1e4] reads were garbage
   (0xCDCDCDCD).  The bridge casts through the real PoweredSubsystem type + returns
   the NAMED fields (and is the FUN_0041a1a4/0x50f4bc type filter).  Make + Subsystem
   Cluster now read via the bridge.

2. Reconstruct the 4 child gauges the clusters build that were declared-but-undefined
   (only VertTwoPartBar/OneOfSeveral/PixInt existed): HorizTwoPartBar (full, mirrors
   Vert), OneOfSeveralInt (ctor), OneOfSeveralStates (ctor + BecameActive + State
   Connection @004c3324), BitMapInverseWipe/LeakGauge (full) + SeekVoltageGraph's
   Execute/BecameActive/dtor -- their /FORCE-stubbed ctors were segfaulting when a
   cluster built them.

VERIFIED (BT_DEV_GAUGES + BT_VSS_LOG): 7 authentic panels build -- Sensor(scr5,
qsensors) HeatSinkCluster, Myomers(scr6,qmyomers) MyomerCluster, PPC(scr1,10) +
Emitter(scr4,8,7) Energy/Ballistic clusters -- with real labels + placements, 0
crashes, combat un-regressed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-07 07:10:47 -05:00
co-authored by Claude Opus 4.8
parent a02339112a
commit 6fceb58439
3 changed files with 307 additions and 9 deletions
+62 -9
View File
@@ -132,6 +132,16 @@ static void *AttributePointerOf(void *subsystem, const char *name)
//
static void *ResolveLink(void *plug) { (void)plug; return 0; }
//
// Bridge (defined in powersub.cpp) that reads the engineering-screen assignment
// off the real PoweredSubsystem type (auxScreenNumber/Placement/Label) -- the
// reconstructed heat-leaf branch is not byte-exact, so the raw sub+0x1dc/0x1e0/
// 0x1e4 offsets read garbage; the named fields (populated by the PoweredSubsystem
// ctor from the resource) are correct. Returns False for non-PoweredSubsystem-
// derived subsystems (== the vehicleSubSystems type filter).
//
extern bool BTGetSubsystemAuxScreen(Subsystem *sub, int *screen, int *placement, char *label64);
//
// FUN_0041bf44 -- fetch the subsystem linked at slot N (used by the cooling-loop
// lamp to find its cooling master). Stubbed to match ResolveLink above.
@@ -277,10 +287,44 @@ SeekVoltageGraph::SeekVoltageGraph(
//
// @004c68ac -- dtor. Release the destroyed bitmap, GraphicGauge::~GraphicGauge.
//
SeekVoltageGraph::~SeekVoltageGraph()
{
L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer;
warehouse->bitMapBin.Release(destroyedImage);
}
Logical SeekVoltageGraph::TestInstance() const
{
return GraphicGauge::TestInstance();
}
//
// @004c6920 -- BecameActive: previousVoltage = 9999.0f (force first redraw).
//
// @004c6934 -- Execute. If the subsystem is destroyed (subsys+0x40 == 1) draw
void SeekVoltageGraph::BecameActive()
{
previousVoltage = RedrawSentinel; // @0xAC force first redraw
destroyedShown = 0;
}
//
// @004c6934 -- Execute (the seek-voltage curve plot). BRING-UP: the full plot
// (SetupClip/DrawTicks/DrawCursor over a 0..1 voltage polyline) needs the live
// seek-voltage sampler (subsys vtbl+0x3c) + the four attribute indices; the
// attribute resolve is summarised (FindAttributeIndex returns -1), so the plot is
// deferred and Execute is inert until the sampler + attribute reads land. Kept as
// a defined no-op so the gauge's vtable is complete (no /FORCE crash when the
// Myomer/Energy cluster ticks its SeekVoltageGraph child).
//
void SeekVoltageGraph::Execute()
{
// (seek-voltage plot deferred -- see note above.)
}
//
// @004c6934 (original notes preserved) -- Execute. If the subsystem is destroyed
// (subsys+0x40 == 1) draw
// the centred "destroyed" bitmap once. Otherwise, when the live seek voltage
// (subsys vtbl+0x3c sampler) changes: clear (SetupClip @004c6be4), re-plot the
// 0..1 voltage curve as a polyline (step _DAT_004c6bdc up to _DAT_004c6be0,
@@ -751,8 +795,10 @@ SubsystemCluster::SubsystemCluster(
mfd_port, x + 0x10e, y + 0xe, "btpbus.pcc", 5, 1,
inputVoltage, "PowerSource");
// Background: image_names[ subsystem damageZoneIndex@0x1e0 ] if present.
int dzIndex = *(int *)((char *)subsystem_in + 0x1e0); // BEST-EFFORT raw offset
// Background: image_names[ auxScreenPlacement ] if present. (Placement@0x1e0 is
// read via the PoweredSubsystem bridge, not the non-byte-exact raw offset.)
int dzIndex = -1;
BTGetSubsystemAuxScreen(subsystem_in, NULL, &dzIndex, NULL); // auxScreenPlacement
background = NULL;
if (dzIndex >= 0 && image_names[dzIndex] != NULL)
background = new BackgroundBitmap(mfd_mode, renderer_in, owner_ID, // @00471d00
@@ -814,8 +860,9 @@ SubsystemCluster::SubsystemCluster(
(Scalar *)linkTemp, (Scalar *)linkDegrade, (Scalar *)failTemp, "VertTwoPartBar");
leakGauge = new BitMapInverseWipe(ChildRate(), eng_mode, renderer_in, // @004c5b7c
engPort, 0x255, 0xe0, "eleak.pcc", 0, 0xff, 3,
*(int *)((char *)subsystem_in + 0x150), (Scalar *)coolantLeak, "LeakGauge"); // BEST-EFFORT raw
engPort, 0x255, 0xe0, "eleak.pcc", 0, 0xff,
*(int *)((char *)subsystem_in + 0x150) /*third*/, 3 /*frames*/,
(Scalar *)coolantLeak, "LeakGauge"); // BEST-EFFORT raw (subsys+0x150)
operating = False; // @0xC4 this[0x31]
subsystem = subsystem_in; // @0xC0 this[0x30]
@@ -1380,13 +1427,19 @@ Logical
Subsystem *sub = entity->GetSubsystem(i); // entity+0x128[i]
if (sub == NULL)
continue;
if (!SubsystemDisplayFilter(sub)) // FUN_0041a1a4
// Read the engineering-screen assignment via the PoweredSubsystem bridge
// (also the type filter -- False == not PoweredSubsystem-derived).
int auxScreen = 0, placement = -1;
char labelBuf[64];
if (!BTGetSubsystemAuxScreen(sub, &auxScreen, &placement, labelBuf)) // FUN_0041a1a4 + sub[0x1dc]/[0x1e4]
continue;
int group = *(int *)((char *)sub + 0x1dc) - 1; // aux-screen position 1..12
int group = auxScreen - 1; // aux-screen position 1..12
if (getenv("BT_VSS_LOG"))
DEBUG_STREAM << "[vss] i=" << i << " classID=" << (int)sub->GetClassID()
<< " auxScreen[0x1dc]=" << (group + 1) << "\n" << std::flush;
<< " auxScreen=" << auxScreen << " placement=" << placement
<< " label='" << labelBuf << "'\n" << std::flush;
if (group < 0)
{
DebugStream << "Auxiliary screen position = zero\n";
@@ -1400,7 +1453,7 @@ Logical
const AuxScreenGeometry &g = kAuxGeom[group];
int mfdPort = renderer->FindGraphicsPort((char *)g.mfdPortName); // FUN_00447f1c
char *label = (char *)((char *)sub + 0x1e4); // the subsystem label
char *label = labelBuf; // the subsystem label (bridge)
char *tile = (char *)"btwarn.pcc";
switch (sub->GetClassID()) // sub+4