Files
BT412/scratchpad/wf_2_PrepEngr_decode.md
T
arcattackandClaude Opus 4.8 4a4ec6855c gauge-complete P4e: SectorDisplay reconstructed + registered -> radar SECTOR X/Z read-out LIVE
The "sectorDisplay" cockpit primitive (Secondary overlay, the radar SECTOR X/Z
coordinate read-out) was PROSE-ONLY in btl4gau3 (placeholder Make, no ctor/
methodDescription/registration) -> the config line was parse-SKIPPED and never built.

Reconstructed byte-verified from the disassembly (ctor @4c9e10, Execute @4ca07c,
methodDescription PE-parse): SectorDisplay : GraphicGauge, sizeof 0xC4. Its Execute
reads the linked mech's world position and shows two 100-unit sector numerics:
  numericA = Round(-localOrigin.z * 0.01) + 500
  numericB = Round( localOrigin.x * 0.01) + 500
(rounding = round-to-nearest == FUN_004dcd94, corrected from the reviewer's wrong
"truncate" claim; 0.01 const PE-verified; -Z/+X axis + fchs confirmed from asm).
Overridden slots: LinkToEntity(9) caches the subject, BecameActive(3, non-inactivating),
Execute(16) -> satisfies the container-Execute rule. Layout overflow-locked
(static_assert sizeof<=0xC4). Make/ctor/dtor mirror the registered PilotList sibling;
the config image name is copied (nameCopy) since Execute reads it per-frame.
Registered in BTL4MethodDescription[].

VERIFIED LIVE (BT_SECTOR_LOG): Make port=1 pos=(125,579) image=helv15.pcc gridCached=1;
Execute -Z=960.4 X=361.6 -> sectorA=510 sectorB=504 (Round(9.6)+500=510, Round(3.6)+500=504
-- authentic 100-unit sectors from live mech position). Gauge composite renders full,
no crash. The skip list is now exactly the two remaining widgets (prepEngr x12, messageBoard).

Also: a permanent BT_GAUGE_SKIP_LOG diagnostic (GAUGREND.cpp, gated) that logs each
unregistered gauge primitive the dev-parse skips -- the tool that pinned this down
(earlier "not built" runs were killed before the lazy gauge-renderer init).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-07 21:25:48 -05:00

24 KiB
Raw Blame History

I now have complete, definitive coverage. The vtables.tsv row 0051a040 shows PrepEngr's slots …4c7d14 4173b8 417938 4c7e48… — byte-identical in shape to BackgroundBitmap's …471d7c 4173b8 417938 471dec… (dtor, 2 inherited, BecameActive). This confirms FUN_004c7e48 is the BecameActive slot and PrepEngrScreen is a GraphicGaugeBackground. Everything is traced. Here is the full spec.


PrepEngrScreen — decode & reconstruction spec (config keyword prepEngr)

Bottom line up front: the existing btl4gau2.hpp stub for PrepEngrScreen is wrong in three ways and there is no methodDescription/Make, so prepEngr(...) is parse-skipped (12 CFG calls never build). It is NOT an Execute-driven Gauge with a child chain — it is a GraphicGaugeBackground painted on activation (identical base/vtable shape to the engine's BackgroundBitmap). Corrections: (1) base = GraphicGaugeBackground, not Gauge; (2) the overridden slot is BecameActive(), not Execute(); (3) screenNumber@0x6C and mech@0x70 are swapped in the stub.


1. Identity

Field Value Citation
Class name PrepEngrScreen id-string s_PrepEngr_00519a9d = "PrepEngr", part_014.c:1193
Config keyword prepEngr L4GAUGE.CFG:4595…4759 (12×); it is the methodDescription's first string (distinct from the "PrepEngr" id-string)
Base class GraphicGaugeBackground (GaugeBase→…→localView, no rate/Execute) ctor calls base FUN_004440d4 (part_014.c:1213); FUN_004440d4 = GraphicGaugeBackground ctor (mode,renderer,ownerID,port,idstr) → localView(GraphicsViewRecord) at +0x24 / index 9 (part_006.c @004440d4), identical to BackgroundBitmap (part_009.c @00471d00)
ctor @004c7bf0 (FUN_004c7bf0) part_014.c:1204
dtor @004c7d14 (FUN_004c7d14) part_014.c:1246
BecameActive (the paint) @004c7e48 (FUN_004c7e48) part_014.c:1288
Make (config factory) @004c7b30 (FUN_004c7b30) part_014.c:1172
methodDescription in .rdata (not exported by the fn-only decompiler) — reconstruct from the CFG call shape
vtable PTR_FUN_0051a06c part_014.c:1214,1252
sizeof 0x90 (= FUN_00402298(0x90) in Make) part_014.c:1189
GUID / classID none (GraphicGaugeBackground carries no distinct classID; it's not roster-registered)

Vtable-slot proof (reference/decomp/vtables.tsv, row 0051a040): … 4c7d14 4173b8 417938 4c7e48 … — the exact same shape as BackgroundBitmap (row 004fb918): … 471d7c 4173b8 417938 471dec …. i.e. [dtor][inherited][inherited][BecameActive]. Only dtor + BecameActive are overridden; everything else is inherited (444xxx base slots). TestInstance is non-virtual (GAUGE.h:46) → not a vtable override.


2. What it displays & data binding

prepEngr = "PREPARE the engineering screen": a static per-screen label overlay for one of the 12 MFD engineering screens (ModeMFD{1,2,3}Eng{1..4} → screen numbers 1..12; CFG:4595-4769). It is not the live bars/dials — those come from vehicleSubSystems/SubsystemCluster. PrepEngrScreen paints, once each time its screen becomes active, the labels appropriate to the one subsystem assigned to that screen.

BecameActive (@004c7e48) walks the mech's subsystem roster, finds the first subsystem whose auxScreenNumber == this->screenNumber, and paints:

Element Source Where drawn Live now?
screen-number numeric (2 digits) this->screenNumber (own member) (0xE9,0x176) LIVE (own field)
linked heat-sink numeric (1 digit) ResolveLink(AttributePointerOf(sub,"HeatSink")) + 0x1D4 (0x15E,5) DEFERRED — raw offset on the resolved sink (databinding risk; guard NULL)
subsystem label bitmap sub + 0x224 (embedded char[] = a .pcc name) (0x125,0x172) DEFERRED — raw subsystem offset, not a byte-exact field; use the BTGetSubsystemAuxScreen label bridge instead
type-specific label cells this->statusImage[1..6] dispatched by sub->GetClassID() fixed cells via DrawStatusCells LIVE (own members + classID accessor)

ClassID → label dispatch (switch(sub+4), part_014.c:1330-1357; images are this[0x1D..0x23], byte 0x74..0x8C):

ClassID Subsystem DrawStatusCells(topBox, A, B, C) +extra
0xBC3 Sensor (1, , , ) draw statusImage[6]=btesrnge.pcc @(0xB8,0x8C) — part_014.c:1332-1334
0xBC6 Myomers (0, , img5=espeed, img3=bteslev) part_014.c:1339
0xBC8 / 0xBD4 Emitter / PPC (0, img1=escnd, img2=edmg, img3=bteslev) part_014.c:1344
0xBCD / 0xBD0 ProjectileWeapon / MissileLauncher (1, , , img4=bteunjm) part_014.c:1349
0xBCE GaussRifle warn "…Gauss rifle not yet supported" + (1, , , img3=bteslev) part_014.c:1353-1354
default nothing (return) part_014.c:1336

Databinding-safe roster access (the trap: reconstructed Mech is 0x638 vs binary 0x854, so raw mech+0x124/+0x128 read garbage). Use the same accessors the sibling VehicleSubSystems::Make uses (btl4gau2.cpp:1621-1636): entity->GetSubsystemCount(), entity->GetSubsystem(i), and BTGetSubsystemAuxScreen(sub,&auxScreen,&placement,label64) (declared btl4gau2.cpp:151) — the bridge both applies the FUN_0041a1a4(**(sub+0xc),0x50f4bc) PoweredSubsystem type filter (part_014.c:1308) and returns auxScreenNumber (sub+0x1DC, part_014.c:1309), replacing the two raw reads.

Content (from all 12 CFG calls, identical param set, CFG:4595-4605): font helv42.pcc; labels escnd.pcc(sensor) edmg.pcc(damage) bteslev.pcc(seek/energy level) bteunjm.pcc(unjam) espeed.pcc(speed) btesrnge.pcc(range).


3. Class layout (byte-exact) + locks

Binary layout (from ctor FUN_004c7bf0 int-index writes = byte N×4, and the FUN_00402298(0x90) alloc):

GraphicGaugeBackground base .......... 0x00 .. 0x23   (GaugeBase fields incl. renderer@0x1C)
  localView (GraphicsView) ........... 0x24 .. 0x6B   (GraphicsViewRecord, init'd by FUN_0044ad78)
  screenNumber   int ................. 0x6C   this[0x1B]   (param_7; part_014.c:1216)  ← NOT mech
  mech           Entity* ............. 0x70   this[0x1C]   (param_6; part_014.c:1215)  ← NOT screenNumber
  statusImage[0] char* (font helv42) . 0x74   this[0x1D]   (part_014.c:1218)
  statusImage[1] char* (escnd) ....... 0x78   this[0x1E]   (:1220)
  statusImage[2] char* (edmg) ........ 0x7C   this[0x1F]   (:1222)
  statusImage[3] char* (bteslev) ..... 0x80   this[0x20]   (:1224)
  statusImage[4] char* (bteunjm) ..... 0x84   this[0x21]   (:1226)
  statusImage[5] char* (espeed) ...... 0x88   this[0x22]   (:1228)
  statusImage[6] char* (btesrnge) .... 0x8C   this[0x23]   (:1230)
sizeof = 0x90

⚠ The current btl4gau2.hpp:318-320 stub has mech@0x6C / screenNumber@0x70 swapped and base Gauge. Both must change.

Because the reconstruction's GraphicGaugeBackground/GraphicsView are not byte-exact to the 1995 layout, do not emit offsetof locks against the binary offsets for the own fields (they'd fail like Sensor/heat-leaf). The only load-bearing size fact is the Make alloc; assert only that the compiled object fits the binary alloc:

static_assert(sizeof(PrepEngrScreen) <= 0x90, "PrepEngrScreen exceeds binary alloc 0x90");

(If you new PrepEngrScreen normally rather than operator new(0x90), even this is optional — no external code reads PrepEngrScreen at raw offsets.)


4. Full bodies to write

4a. Header (replace the stub at btl4gau2.hpp:304-322)

	//#######################################################################
	// PrepEngrScreen -- "prepEngr": the per-engineering-screen STATIC label
	// overlay.  @004c7b30 Make / @004c7bf0 ctor / @004c7d14 dtor /
	// @004c7e48 BecameActive.  vtable PTR_FUN_0051a06c.
	//
	// A GraphicGaugeBackground (paint-on-activation, NOT an Execute gauge --
	// same base/shape as the engine's BackgroundBitmap, FUN_00471d00).  Interns
	// 7 status .pcc's (font + 6 labels) and, when its MFD-Eng screen activates,
	// paints the labels for the ONE subsystem whose auxScreenNumber == this
	// screen (1..12), dispatched by the subsystem's ClassID.
	//#######################################################################
	class PrepEngrScreen :
		public GraphicGaugeBackground
	{
	public:
		static MethodDescription methodDescription;
		static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *);	// @004c7b30
		PrepEngrScreen(							// @004c7bf0
			ModeMask, L4GaugeRenderer *, unsigned int owner_ID,
			int graphics_port_number, Entity *mech, int screen_number,
			const char *img0/*font*/, const char *img1, const char *img2,
			const char *img3, const char *img4, const char *img5,
			const char *img6, const char *identification_string = "PrepEngr");
		~PrepEngrScreen();						// @004c7d14
		void	BecameActive();					// @004c7e48  (the paint slot -- NOT Execute)
	protected:
		int		screenNumber;					// @0x6C  this[0x1B]
		Entity	*mech;							// @0x70  this[0x1C]
		char	*statusImage[7];				// @0x74  this[0x1D..0x23]  (interned .pcc names)
	};

4b. Implementation (add to btl4gau2.cpp, replacing the prose block at 819-851)

//###########################################################################
//   PrepEngrScreen  --  "prepEngr"  @004c7b30 Make / @004c7bf0 ctor /
//   @004c7d14 dtor / @004c7e48 BecameActive.  A GraphicGaugeBackground.
//###########################################################################

// ---- FUN_004c79c8 : draw the 3 status-label cells (+ optional top erase box).
// Each cell either blits its label .pcc or blanks the cell.  Coords are the
// binary's exact absolute cell rectangles (part_014.c:1127-1166).
static void
	DrawStatusCells(GraphicsView *view, L4Warehouse *warehouse,
					int topBox, const char *A, const char *B, const char *C)
{
	if (topBox)											// part_014.c:1131-1135
	{
		view->SetColor(0);
		view->MoveToAbsolute(0x97, 0x80);
		view->DrawFilledRectangleToAbsolute(0x17d, 0x13b);
	}
	if (A == NULL) { view->SetColor(0); view->MoveToAbsolute(0x15a,0x145);	// :1136-1140
		view->DrawFilledRectangleToAbsolute(0x17f,0x159); }
	else { view->SetColor(0xff); DrawPortBackground(view,warehouse,0x15a,0x145,A); }	// FUN_004c2ec4
	if (B == NULL) { view->SetColor(0); view->MoveToAbsolute(0x85,0x58);		// :1145-1149
		view->DrawFilledRectangleToAbsolute(0x17f,0x7c); }
	else { view->SetColor(0xff); DrawPortBackground(view,warehouse,0x85,0x58,B); }
	if (C == NULL) { view->SetColor(0); view->MoveToAbsolute(0x2a,0x34);		// :1154-1160
		// NB: raw uses GraphicsView vtbl+0x4c(99,10) then MoveToAbsolute(10,0)
		// then DrawFilledRectangleToAbsolute(0x9f,0x2d) -- a compound blank.
		// vtbl+0x4c is an unresolved GraphicsView slot; a plain fill is close:
		view->DrawFilledRectangleToAbsolute(0x9f,0x2d); }
	else { view->SetColor(0xff); DrawPortBackground(view,warehouse,0x2a,0x34,C); }
}

// CFG shape (L4GAUGE.CFG:4595): mode, int screen(1..12), then 7 .pcc names
// (font + 6 labels).  9 params.
MethodDescription
	PrepEngrScreen::methodDescription =
	{
		"prepEngr",
		PrepEngrScreen::Make,
		{
			{ ParameterDescription::typeModeMask, NULL },	// p[0] mode  (ModeMFD*Eng*)
			{ ParameterDescription::typeInteger,  NULL },	// p[1] screen number 1..12
			{ ParameterDescription::typeString,   NULL },	// p[2] font   helv42.pcc  -> statusImage[0]
			{ ParameterDescription::typeString,   NULL },	// p[3] escnd.pcc          -> statusImage[1]
			{ ParameterDescription::typeString,   NULL },	// p[4] edmg.pcc           -> statusImage[2]
			{ ParameterDescription::typeString,   NULL },	// p[5] bteslev.pcc        -> statusImage[3]
			{ ParameterDescription::typeString,   NULL },	// p[6] bteunjm.pcc        -> statusImage[4]
			{ ParameterDescription::typeString,   NULL },	// p[7] espeed.pcc         -> statusImage[5]
			{ ParameterDescription::typeString,   NULL },	// p[8] btesrnge.pcc       -> statusImage[6]
			PARAMETER_DESCRIPTION_END
		}
	};

//
// @004c7b30 -- Make.  Validate the screen number (p[1], must be 1..12) then
// construct.  The GraphicGaugeBackground base ctor self-registers with the
// renderer (GAUGE.cpp GaugeBase::GaugeBase -> renderer->Add(this)), so the
// gauge's BecameActive fires whenever its Eng screen is selected.
//
Logical
	PrepEngrScreen::Make(
		int				display_port_index,
		Vector2DOf<int>	/*position -- ignored; PrepEngr draws at absolute coords*/,
		Entity			*entity,
		GaugeRenderer	*gauge_renderer
	)
{
	ParameterDescription *p = methodDescription.parameterList;

	int screen = p[1].data.integer;
	if (screen < 1 || screen > 12)						// part_014.c:1182
	{
		DebugStream << "PrepEngr: screen number out of range " << screen << "\n";	// :1183-1185
		return False;									// raw returns 0
	}

	// operator new(0x90) + placement-new to mirror FUN_00402298(0x90) (:1189).
	PrepEngrScreen *g = (PrepEngrScreen *)operator new(0x90);
	if (g != NULL)
		new (g) PrepEngrScreen(
			p[0].data.modeMask,							// mode (ModeMFD*Eng*)
			(L4GaugeRenderer *)gauge_renderer,
			0,											// owner_ID (raw hard-wires 0)
			display_port_index,							// graphics_port_number
			entity,										// mech (Make param_4)
			screen,										// screen number
			p[2].data.string, p[3].data.string, p[4].data.string,
			p[5].data.string, p[6].data.string, p[7].data.string,
			p[8].data.string,
			"PrepEngr");
	return True;										// raw returns 1
}

//
// @004c7bf0 -- ctor.  GraphicGaugeBackground base (mode/renderer/0/port/"PrepEngr");
// store screen + mech; nameCopy the 7 images and pre-load (AddRef) each from the
// bitmap cache.  (No SetOrigin -- localView keeps its default origin.)
//
PrepEngrScreen::PrepEngrScreen(
	ModeMask mode_mask, L4GaugeRenderer *renderer_in, unsigned int owner_ID,
	int graphics_port_number, Entity *mech_in, int screen_number,
	const char *img0, const char *img1, const char *img2, const char *img3,
	const char *img4, const char *img5, const char *img6,
	const char *identification_string
):
	GraphicGaugeBackground(mode_mask, renderer_in, owner_ID,		// FUN_004440d4
		graphics_port_number, identification_string)
{
	screenNumber = screen_number;					// @0x6C  (param_7, :1216)
	mech         = mech_in;							// @0x70  (param_6, :1215)

	const char *src[7] = { img0,img1,img2,img3,img4,img5,img6 };
	L4Warehouse *warehouse = (L4Warehouse *)renderer_in->warehousePointer;	// renderer+0x4c
	for (int i = 0; i < 7; i++)
	{
		statusImage[i] = nameCopy(src[i]);			// FUN_004700ac (:1217-1230)
		warehouse->bitMapBin.Get(statusImage[i]);	// FUN_00442aec pre-load/AddRef (:1232-1238)
	}
}

//
// @004c7d14 -- dtor.  Release the 7 pre-loaded images + free their name copies.
// (The localView + base dtor run implicitly via the C++ epilogue -- do NOT emit
// explicit FUN_0044ae0c/FUN_00443f7c calls; they are compiler glue, per the
// reconstruction destructor rule.)
//
PrepEngrScreen::~PrepEngrScreen()
{
	L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer;
	for (int i = 0; i < 7; i++)
	{
		warehouse->bitMapBin.Release(statusImage[i]);	// FUN_00442c12 (:1254-1260)
		delete[] statusImage[i];						// FUN_004022e8 (:1261-1274)
		statusImage[i] = NULL;
	}
}

//
// @004c7e48 -- BecameActive.  Find the subsystem on this screen and paint its
// labels.  (Roster/aux-screen read via the databinding-safe accessors + the
// PoweredSubsystem bridge, exactly like VehicleSubSystems::Make.)
//
void
	PrepEngrScreen::BecameActive()
{
	if (mech == NULL)  return;
	L4Warehouse *warehouse = (L4Warehouse *)renderer->warehousePointer;	// this[0x1C]->+0x4c
	const char  *font      = statusImage[0];							// helv42.pcc

	int count = mech->GetSubsystemCount();				// mech+0x124
	for (int i = 1; i < count; i++)						// skip slot 0 (the controls mapper)
	{
		Subsystem *sub = mech->GetSubsystem(i);			// mech+0x128[i]
		if (sub == NULL)  continue;

		int  auxScreen = 0, placement = -1;  char label64[64];
		if (!BTGetSubsystemAuxScreen(sub, &auxScreen, &placement, label64))	// FUN_0041a1a4 filter + sub+0x1dc
			continue;								// not a PoweredSubsystem-derived weapon
		if (auxScreen != screenNumber)				// part_014.c:1309
			continue;

		// ---- numeric #1 : the screen number, 2 digits @(0xE9,0x176)  (:1310-1313)
		{
			NumericDisplay num(warehouse, 0xe9, 0x176, font, 2,
				NumericDisplay::unsignedFormat, 0, 0xff);		// FUN_004700bc
			num.Draw(&localView, (Scalar)screenNumber);			// FUN_00470430
		}													// ~NumericDisplay = FUN_0047018c

		// ---- numeric #2 : linked heat-sink number, 1 digit @(0x15E,5)  (:1315-1321)
		int hsNumber = 0;
		void *hsLink = AttributePointerOf(sub, "HeatSink");		// FUN_0041bfc0
		Subsystem *hs = (Subsystem *)ResolveLink(hsLink);		// FUN_00417ab4
		if (hs != NULL)
			hsNumber = *(int *)((char *)hs + 0x1d4);			// BEST-EFFORT raw (see §6)
		{
			NumericDisplay num(warehouse, 0x15e, 5, font, 1,
				NumericDisplay::unsignedFormat, 0, 0xff);
			num.Draw(&localView, (Scalar)hsNumber);
		}

		// ---- subsystem label bitmap @(0x125,0x172)  (:1322-1329)
		// Raw draws the .pcc name at sub+0x224; use the aux-screen label bridge
		// (label64) for a databinding-safe equivalent.  (BEST-EFFORT; see §6.)
		localView.SetColor(0xff);
		if (label64[0] != '\0')
			DrawPortBackground(&localView, warehouse, 0x125, 0x172, label64);

		// ---- type-specific label cells  (switch on ClassID, :1330-1357)
		switch (sub->GetClassID())							// sub+4
		{
		case 0xBC3:		// Sensor
			DrawStatusCells(&localView, warehouse, 1, NULL, NULL, NULL);
			localView.SetColor(0xff);
			DrawPortBackground(&localView, warehouse, 0xb8, 0x8c, statusImage[6]); // btesrnge
			return;
		case 0xBC6:		// Myomers
			DrawStatusCells(&localView, warehouse, 0, NULL, statusImage[5], statusImage[3]);
			return;
		case 0xBC8:		// Emitter
		case 0xBD4:		// PPC
			DrawStatusCells(&localView, warehouse, 0, statusImage[1], statusImage[2], statusImage[3]);
			return;
		case 0xBCD:		// ProjectileWeapon
		case 0xBD0:		// MissileLauncher
			DrawStatusCells(&localView, warehouse, 1, NULL, NULL, statusImage[4]);
			return;
		case 0xBCE:		// GaussRifle -- not yet supported
			DebugStream << "PrepEngr: Gauss rifle not yet supported\n";	// :1353
			DrawStatusCells(&localView, warehouse, 1, NULL, NULL, statusImage[3]);
			return;
		default:
			return;
		}
	}
}

DrawPortBackground(view, warehouse, x, y, tile) (btl4gau2.cpp:923) is FUN_004c2ec4; nameCopy, AttributePointerOf, ResolveLink, BTGetSubsystemAuxScreen, NumericDisplay, L4Warehouse are already available in this TU. DrawPortBackground currently takes (GraphicsView*, L4Warehouse*, int, int, const char*) — matches the calls above.

4c. Registration (btl4grnd.cpp, in BTL4MethodDescription[], before &BTL4ChainToPrevious)

	&GeneratorCluster::methodDescription,		// (existing, line 149)
	&PrepEngrScreen::methodDescription,			// "prepEngr" -- per-Eng-screen static label overlay
	&BTL4ChainToPrevious

(#include <btl4gau2.hpp> is already present, btl4grnd.cpp:69.)


5. Systemic-check verdicts

  • Container-Execute override needed? NO. PrepEngrScreen is a GraphicGaugeBackground, which has no Execute virtual (Execute first appears on Gauge, GAUGE.h:366). The Gauge::Execute → Fail→abort hazard does not apply. The overridden slot is BecameActive() (confirmed vtable-identical to BackgroundBitmap). The override body is a real paint (does not chain the inactivating base) — exactly like BackgroundBitmap::BecameActive (L4GAUGE.cpp:2510), so the "default BecameActive inactivates" hazard is also handled.
  • Shadow fields? None. Own fields (screenNumber/mech/statusImage) are new; the base GraphicGaugeBackground owns renderer/localView, which are used (not re-declared). Do NOT re-declare localView or renderer.
  • Alias fields? None.
  • Phantom fields? None — all own fields are inside the 0x90 object; nothing past sizeof.
  • The stub's two bugs to fix: base GaugeGraphicGaugeBackground; screenNumber/mech offsets swapped; Execute()BecameActive().
  • Databinding NULL / every-mech crash risk:
    • mech==NULL → guarded (early return).
    • roster via GetSubsystemCount/GetSubsystem (safe accessors) + slot-0 skip → safe.
    • ResolveLink("HeatSink") may be NULL → guarded before the +0x1D4 read.
    • sub+0x1D4 and sub+0x224 are raw subsystem offsets on not-byte-exact objects → fail-soft (wrong digit / bitMapBin.Get returns NULL → draws nothing), not a crash. §6 gives the safe substitutes (label bridge; a "HeatSinkNumber" attribute if one is published).
    • NumericDisplay/DrawStatusCells/DrawPortBackground operate on the gauge's own localView + warehouse (both valid post-ctor) → safe. No GuardedExecute needed (background paints aren't SEH-wrapped, but nothing here dereferences unresolved game state without a guard).
  • Registration / lifetime: GaugeBase::GaugeBase self-registers (renderer->Add(this), GAUGE.cpp), so Make needs no explicit Register_Object (that macro is only debug memory-tracking, MEMREG.h:24). Unlike BackgroundBitmap, prepEngr is never ModeAlwaysActive (always ModeMFD*Eng*), so there is no run-once-then-delete branch — the gauge persists and repaints on each activation. Correct.

6. Confidence & unknowns

Confidence: HIGH for identity, base class, the BecameActive slot, the Make/ctor/dtor bodies, the methodDescription shape, the layout, and the ClassID→label dispatch. The base class, vtable slot, and lifetime are triple-confirmed (base-ctor FUN_004440d4 signature match + BackgroundBitmap structural twin + vtables.tsv row 0051a040). The CFG call shape (9 params) and image→slot mapping are pinned to the exact ctor stores and the switch.

Unknowns / follow-ups (all cosmetic, none block registration):

  1. sub+0x224 (subsystem label .pcc name), part_014.c:1322 — a raw embedded char[] used as a bitmap name. It is not Subsystem::subsystemName (GetName(), at a much lower offset) and not the aux-screen label (sub+0x1E4, which BTGetSubsystemAuxScreen already returns). Spec substitutes the bridge's label64; confirming/bridging the true +0x224 field (or verifying it equals the aux label) needs a disas2.py/field-map pass on the subsystem ctor. Low value (one label bitmap).
  2. resolvedHeatSink+0x1D4, part_014.c:1317 — a 1-digit readout (the linked sink's bank/index). Byte-exact HeatSink is only 0x1D0, so the resolved object must be a larger subclass for this to be in-bounds; raw read is best-effort. If a HeatSinkNumber/BankNumber attribute exists, prefer AttributePointerOf; otherwise keep the guarded raw read.
  3. DrawStatusCells empty-cell C-placeholder (part_014.c:1156-1159) uses GraphicsView vtbl+0x4c(99,10) — an unresolved GraphicsView slot (between DrawFilledRectangleToAbsolute@0x48 and DrawBitMap@0x54; likely a relative-size rectangle). The spec draws a plain fill at the same coords; resolving the exact call needs a GraphicsView vtable decode. Only affects the blanked-cell appearance when a label is NULL.
  4. The FUN_0041a1a4(**(sub+0xc),0x50f4bc) filter (part_014.c:1308) is folded into BTGetSubsystemAuxScreen (same treatment as VehicleSubSystems); if that bridge's filter ever diverges from the exact ClassDerivations resolution it would change which subsystems qualify — but the ClassID switch is the effective filter anyway, so this is faithful.

Net: registering &PrepEngrScreen::methodDescription + the bodies above stops the 12 prepEngr(...) lines from parse-skipping and paints the engineering-screen labels; the two raw subsystem reads (#1,#2) are guarded fail-soft best-efforts flagged for a later attribute/bridge pass.