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

390 lines
24 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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:
```cpp
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`)
```cpp
//#######################################################################
// 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)
```cpp
//###########################################################################
// 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`)
```cpp
&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 `Gauge``GraphicGaugeBackground`; `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.