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>
294 lines
19 KiB
Markdown
294 lines
19 KiB
Markdown
I now have the complete picture, verified against disassembly, the PE method-description table, the CFG, and the sibling reconstructions. Here is the full implementation spec.
|
||
|
||
---
|
||
|
||
# SectorDisplay — Reconstruction Spec
|
||
|
||
Cockpit **radar SECTOR X/Z read-out** (the Secondary-overlay grid + two 3-digit coordinate numerics). Config keyword `sectorDisplay`, currently **prose-only** in `game/reconstructed/btl4gau3.cpp` (a placeholder `Make`, no ctor/`methodDescription`/registration) → the CFG line is **parse-skipped**. Everything below is decoded from `BTL4OPT.EXE` (Execute/ctor/vtable disassembled; methodDescription PE-parsed) and cross-checked against `part_014.c` and the already-reconstructed siblings.
|
||
|
||
---
|
||
|
||
## 1. Identity
|
||
|
||
| Field | Value | Evidence |
|
||
|---|---|---|
|
||
| Class | `SectorDisplay` | id string `s_SectorDisplay_0051bb34` `part_014.c:2635`; `"sectorDisplay"` keyword `@0x51bc82` |
|
||
| Base | `GraphicGauge` (→`GraphicGaugeBackground`→`GaugeBase`); base ctor `FUN_00444818`, base vtable `@0x4ee088` | ctor `@0x4c9e38` calls `0x444818`; `btl4gau3.hpp:97` |
|
||
| Config keyword | `sectorDisplay` (1 use, `L4GAUGE.CFG:5146`) | methodDescription name ptr `@0x51a2b0` → `@0x51bc82` |
|
||
| **Make** | `@0x4c9d44` (returns `Logical`; alloc `operator new(0xc4)`) | `part_014.c:2625`; disasm |
|
||
| ctor | `@0x4c9e10` (sets vtable `0x51beec`, sizeof `0xc4`) | `part_014.c:2654`; disasm |
|
||
| dtor | `@0x4c9f94` (slot 0) | `part_014.c:2712` |
|
||
| BecameActive | `@0x4ca038` (slot 3, +0x0c) | vtdump `0x51beec` |
|
||
| **LinkToEntity(Entity\*)** | `@0x4ca068` (slot 9, +0x24) — *the subject setter* | vtdump; base slot9 `0x444088` = empty `LinkToEntity` (`GAUGE.h:62`) |
|
||
| Execute | `@0x4ca07c` (slot 16, +0x40) | vtdump |
|
||
| TestInstance | `@0x4ca020` → `FUN_004448ac`→`FUN_004443a4` (base test); `@0x4ca030` = empty no-op (`TestClass`/dead) | `part_014.c:2736,2747` |
|
||
| **methodDescription** | `@0x51a2b0` → keyword `@0x51bc82`, Make `0x4c9d44`, 5 param rows | PE dump |
|
||
| vtable | `PTR_FUN_0051beec` (17 slots; overrides 0/3/9/16) | vtdump |
|
||
| sizeof | **0xC4** (== Make alloc `FUN_00402298(0xc4)`, `@0x4c9d54`) | disasm |
|
||
| GUID / RTTI | none | vtable has no RTTI slot |
|
||
|
||
**Overridden vtable slots** (vs base `0x4ee088`): slot0 dtor `0x4c9f94`; slot3 `BecameActive` `0x4ca038`; **slot9 `LinkToEntity` `0x4ca068`** (base `0x444088` is an empty `ret`); slot16 `Execute` `0x4ca07c`. All others inherited.
|
||
|
||
---
|
||
|
||
## 2. What it displays & the data binding — **DATA-LIVE**
|
||
|
||
Two `NumericDisplay`s show the linked mech's **world sector coordinates**, plus a one-shot grid-cell background blit.
|
||
|
||
The subject is an **`Entity*`** cached at `+0x90` by the overridden **`LinkToEntity(Entity*)`** (slot 9). The engine `GaugeRenderer::LinkToEntity` (`GAUGREND.cpp:3008`, == binary broadcast `FUN_00447b70` `part_006.c:5295` which calls slot9 on all three gauge lists) pushes the viewpoint entity to every gauge each frame.
|
||
|
||
Execute reads the subject's position (disasm `@0x4ca096`–`@0x4ca0b9`):
|
||
|
||
```
|
||
numericA value = (int)(-subject->localOrigin.linearPosition.z * 0.01f) + 500 // -Z/100 + 500
|
||
numericB value = (int)( subject->localOrigin.linearPosition.x * 0.01f) + 500 // X/100 + 500
|
||
```
|
||
|
||
- Scale const `@0x4ca194` is the **80-bit extended `0.01`** (= ÷100 → 100-unit sectors); decoded exact.
|
||
- `-Z` uses `fchs` `@0x4ca09c`; both truncate toward zero (`FUN_004dcd94` sets FPU RC=chop `or 0xc`, `fistp` — it is `(long)`, **not** round-to-nearest).
|
||
- `entity+0x100` == `Entity::localOrigin.linearPosition` is **already established** by the reconstructed radar (`btl4rdr.cpp:150,622` `FUN_00408440(this+0x310, owner+0x100)`); `.x@+0x100, .z@+0x108`. `Origin localOrigin` is a base-`Entity` member (`ENTITY.h:140`, `ORIGIN.h:15`), read via the **engine type** (compiled-consistent) — **not** a raw offset, so no databinding-trap garbage.
|
||
- Heading is **not** read (the task's "heading" hint is inaccurate — only X/Z position feed the two numerics).
|
||
|
||
**LIVE now**, with one caveat: the radar notes the renderer's linked-entity socket "may be unwired on WinTesla" (`btl4rdr.cpp:1029`). Mitigation (faithful to intent, same as `ResolveOperatorEntity`/`HeadingPointer::Execute`): when `subject==NULL`, fall back to `application->GetViewpointEntity()`. The grid background blits once (dirty-gated) from cell 12 of the `helv15.pcc` strip; if that image isn't cached the blit is skipped and Make warns `"SectorDisplay: Missing image …"` (`@0x4c9e91` peek).
|
||
|
||
---
|
||
|
||
## 3. Class layout (byte-exact) + locks
|
||
|
||
⚠ The **current `btl4gau3.hpp` layout is wrong** (mislabels `+0x90` as `enabled`, omits `+0xA8` and the `+0xB8` dirty flag, mislabels the two `500` offsets as `baseLine/dirty`). Corrected from ctor/Execute disasm:
|
||
|
||
```cpp
|
||
class SectorDisplay : public GraphicGauge
|
||
{
|
||
public:
|
||
static MethodDescription methodDescription; // register "sectorDisplay"
|
||
static Logical Make(int, Vector2DOf<int>, Entity *, GaugeRenderer *); // @0x4c9d44
|
||
SectorDisplay(GaugeRate, ModeMask, L4GaugeRenderer *,
|
||
int graphics_port_number, int x, int y,
|
||
const char *image, int color, int ok_color,
|
||
const char *identification_string); // @0x4c9e10 (10 args; owner folded to 0)
|
||
~SectorDisplay(); // @0x4c9f94
|
||
Logical TestInstance() const; // @0x4ca020
|
||
void LinkToEntity(Entity *entity); // @0x4ca068 (slot 9 override)
|
||
void BecameActive(); // @0x4ca038 (slot 3)
|
||
void Execute(); // @0x4ca07c (slot 16)
|
||
protected:
|
||
Entity *subject; // @0x90 this[0x24] LinkToEntity target (linked mech); ctor=0
|
||
char *gridImage; // @0x94 this[0x25] interned image name (helv15.pcc)
|
||
int cellWidth; // @0x98 this[0x26] imageWidth / 14
|
||
int gridLeft; // @0x9C this[0x27] cellWidth*12
|
||
int gridRight; // @0xA0 this[0x28] cellWidth*13 - 1
|
||
int gridHeight; // @0xA4 this[0x29] imageHeight
|
||
int numericColor; // @0xA8 this[0x2A] param_10 (numeric color)
|
||
int gridColor; // @0xAC this[0x2B] param_11 (grid blit color + numeric okColor)
|
||
int offsetX; // @0xB0 this[0x2C] = 500 (added to numericA)
|
||
int offsetY; // @0xB4 this[0x2D] = 500 (added to numericB)
|
||
int dirty; // @0xB8 this[0x2E] redraw flag (BecameActive=1, Execute clears)
|
||
NumericDisplay *numericA; // @0xBC this[0x2F] -Z sector readout
|
||
NumericDisplay *numericB; // @0xC0 this[0x30] X sector readout
|
||
// sizeof == 0xC4
|
||
};
|
||
```
|
||
|
||
**Locks** — use the **overflow lock only** (matching the sibling widgets: the 2007 `GraphicGauge` base is not byte-identical to the 1995 base, so `subject@0x90`/`sizeof==0xC4` byte-exact asserts would fail; every read here is via named members / the engine `Entity` type, so byte-exactness is not required):
|
||
|
||
```cpp
|
||
// namespace scope (sizeof needs no friend); the class reads NO raw this-offsets, so this
|
||
// overflow lock against the Make alloc is the load-bearing guarantee (like Sensor/heat-leaf):
|
||
static_assert(sizeof(SectorDisplay) <= 0xC4, "SectorDisplay must fit its 0xC4 Make alloc");
|
||
```
|
||
|
||
(If a future reader wants the offset asserts anyway, they require a `friend struct SectorDisplayLayoutCheck` and will only pass if the engine `GraphicGauge` happens to end at 0x90 — do **not** gate the build on that.)
|
||
|
||
---
|
||
|
||
## 4. Full method bodies
|
||
|
||
```cpp
|
||
//======================= btl4gau3.cpp (replace the prose-only SectorDisplay block) =======================
|
||
|
||
// @0x51a2b0 -- registered so the interpreter builds "sectorDisplay(K,ModeAlwaysActive,helv15.pcc,0,3)".
|
||
// CFG shape (L4GAUGE.CFG:5146, port=overlay, offset=(125,579)):
|
||
// sectorDisplay( K, ModeAlwaysActive, helv15.pcc, 0, 3 )
|
||
// | | | | +-- p[4] color=3 -> gridColor / numeric okColor
|
||
// | | | +----- p[3] color=0 -> numericColor
|
||
// | | +----------------- p[2] string -> grid/font image
|
||
// | +----------------------------------- p[1] modeMask -> ModeAlwaysActive
|
||
// +-------------------------------------- p[0] rate -> 'K'
|
||
// (position (125,579) and the overlay port index arrive via Make's args, not config tokens.)
|
||
MethodDescription
|
||
SectorDisplay::methodDescription =
|
||
{
|
||
"sectorDisplay",
|
||
SectorDisplay::Make,
|
||
{
|
||
{ ParameterDescription::typeRate, NULL }, // p[0] rate [binary row0 type=1 @0x51a2b8]
|
||
{ ParameterDescription::typeModeMask, NULL }, // p[1] modeMask [row1 type=2 @0x51a2fc]
|
||
{ ParameterDescription::typeString, NULL }, // p[2] image [row2 type=9 @0x51a340]
|
||
{ ParameterDescription::typeColor, NULL }, // p[3] color [row3 type=4 @0x51a384]
|
||
{ ParameterDescription::typeColor, NULL }, // p[4] okColor [row4 type=4 @0x51a3c8]
|
||
PARAMETER_DESCRIPTION_END // [row5 type=0 @0x51a40c]
|
||
}
|
||
};
|
||
|
||
// @0x4c9d44 -- Make. Alloc 0xc4 + construct; then verify the grid image exists
|
||
// (warn "SectorDisplay: Missing image <name>"). Returns True iff the image is cached
|
||
// (binary-faithful: the object self-registers via the base ctor regardless of the return).
|
||
Logical
|
||
SectorDisplay::Make(
|
||
int display_port_index,
|
||
Vector2DOf<int> position,
|
||
Entity * /*entity -- unused*/,
|
||
GaugeRenderer *gauge_renderer)
|
||
{
|
||
ParameterDescription *p = methodDescription.parameterList;
|
||
|
||
SectorDisplay *gauge = (SectorDisplay *)operator new(0xc4); // FUN_00402298(0xc4)
|
||
if (gauge != NULL)
|
||
new (gauge) SectorDisplay(
|
||
p[0].data.rate, p[1].data.modeMask,
|
||
(L4GaugeRenderer *)gauge_renderer,
|
||
display_port_index, // graphics_port_number (FIX: was 0)
|
||
position.x, position.y, // SetOrigin (FIX: was 0,0)
|
||
p[2].data.string, // grid/font image (helv15.pcc)
|
||
p[3].data.color, // numericColor
|
||
p[4].data.color, // gridColor / numeric okColor
|
||
"SectorDisplay");
|
||
|
||
BitMap *grid = ((L4Warehouse *)gauge_renderer->warehousePointer) // renderer+0x4c
|
||
->bitMapBin.GetIfAlreadyExists(p[2].data.string); // FUN_00442aec (peek)
|
||
if (grid == NULL)
|
||
DebugStream << "SectorDisplay: Missing image " << p[2].data.string << "\n"; // FUN_004dbb24 x3
|
||
return (grid != NULL);
|
||
}
|
||
|
||
// @0x4c9e10 -- ctor (vtable 0x51beec). GraphicGauge base (owner=0); intern the image;
|
||
// cellWidth=imgW/14, gridLeft=cellWidth*12, gridRight=cellWidth*13-1, gridHeight=imgH;
|
||
// SetOrigin(x,y); build the two 3-digit NumericDisplays (unsignedFormat).
|
||
SectorDisplay::SectorDisplay(
|
||
GaugeRate rate, ModeMask mode_mask, L4GaugeRenderer *renderer_in,
|
||
int graphics_port_number, int x, int y,
|
||
const char *image, int color, int ok_color, const char *identification_string)
|
||
: GraphicGauge(rate, mode_mask, renderer_in, 0, // FUN_00444818, owner=0
|
||
graphics_port_number, identification_string)
|
||
{
|
||
gridImage = InternName(image); // FUN_004700ac (dtor FreeName's it)
|
||
numericColor = color; // this[0x2A] (param_10)
|
||
gridColor = ok_color; // this[0x2B] (param_11)
|
||
subject = NULL; // this[0x24]
|
||
offsetY = 500; // this[0x2D] (@0x4c9e6d 0x1f4)
|
||
offsetX = 500; // this[0x2C] (@0x4c9e77 0x1f4)
|
||
|
||
L4Warehouse *wh = (L4Warehouse *)renderer_in->warehousePointer; // renderer+0x4c
|
||
BitMap *img = wh->bitMapBin.Get(gridImage); // FUN_00442aec (held; dtor Releases)
|
||
if (img == NULL) {
|
||
cellWidth = gridLeft = gridRight = gridHeight = 0;
|
||
} else {
|
||
cellWidth = img->Data.Size.x / 14; // img+0xc = width (@0x4c9ec1)
|
||
gridLeft = cellWidth * 12; // @0x4c9ed4 (shl 2, *3)
|
||
gridRight = cellWidth * 12 + cellWidth - 1; // @0x4c9ee6
|
||
gridHeight = img->Data.Size.y; // img+0x10 = height (@0x4c9ef5)
|
||
}
|
||
localView.SetOrigin(x, y); // this+0x48 vtbl+0x10 (@0x4c9f0d)
|
||
|
||
// NumericDisplay(warehouse, x, y, font, fieldWidth=3, format=unsignedFormat(0), color, okColor)
|
||
numericA = new NumericDisplay(wh, 0, 0, image, 3,
|
||
NumericDisplay::unsignedFormat, color, ok_color); // this[0x2F]
|
||
numericB = new NumericDisplay(wh, cellWidth * 4, 0, image, 3, // @0x4c9f6f shl 2
|
||
NumericDisplay::unsignedFormat, color, ok_color); // this[0x30]
|
||
|
||
dirty = 1; // binary leaves this[0x2E] uninit (BecameActive sets it before Execute); init for safety
|
||
}
|
||
|
||
// @0x4c9f94 -- dtor. Release grid, free name, delete both numerics. The base
|
||
// GraphicGauge::~GraphicGauge (FUN_00444870) runs IMPLICITLY -- do NOT call it.
|
||
SectorDisplay::~SectorDisplay()
|
||
{
|
||
((L4Warehouse *)renderer->warehousePointer)->bitMapBin.Release(gridImage); // FUN_00442c12
|
||
FreeName(gridImage); gridImage = NULL; // FUN_004022e8
|
||
delete numericA; numericA = NULL; // FUN_0047018c
|
||
delete numericB; numericB = NULL;
|
||
}
|
||
|
||
// @0x4ca020 -- TestInstance: out-of-line forward to the base (so it isn't /FORCE-stubbed).
|
||
Logical
|
||
SectorDisplay::TestInstance() const { return GraphicGauge::TestInstance(); }
|
||
|
||
// @0x4ca068 -- LinkToEntity (slot 9): cache the renderer's linked entity as the subject.
|
||
void
|
||
SectorDisplay::LinkToEntity(Entity *entity) { subject = entity; }
|
||
|
||
// @0x4ca038 -- BecameActive (slot 3): mark dirty + reset both numerics. NON-inactivating
|
||
// (does NOT call the base) -> satisfies the container-Execute rule.
|
||
void
|
||
SectorDisplay::BecameActive()
|
||
{
|
||
dirty = 1; // this[0x2E]
|
||
numericB->ForceUpdate(); // FUN_004703f4 (order B then A, @0x4ca03e/0x4ca04f)
|
||
numericA->ForceUpdate();
|
||
}
|
||
|
||
// @0x4ca07c -- Execute (slot 16): draw the two sector numerics from the linked mech's
|
||
// world X/Z; on the first active frame blit the grid-cell background.
|
||
void
|
||
SectorDisplay::Execute()
|
||
{
|
||
Entity *s = subject;
|
||
// PORT accommodation (marked): the LinkToEntity broadcast may be unwired on WinTesla ->
|
||
// fall back to the viewpoint mech (same pattern as btl4rdr ResolveOperatorEntity).
|
||
// The binary gates purely on `subject != 0` (@0x4ca08e).
|
||
if (s == NULL && application != NULL)
|
||
s = (Entity *)application->GetViewpointEntity();
|
||
if (s == NULL)
|
||
return;
|
||
|
||
const Point3D &pos = s->localOrigin.linearPosition; // s+0x100 (x@+0x100, z@+0x108)
|
||
int vA = (int)(-pos.z * 0.01f) + offsetX; // @0x4ca096 ftol(chop)
|
||
int vB = (int)( pos.x * 0.01f) + offsetY; // @0x4ca0ad
|
||
numericA->Draw(&localView, (Scalar)vA); // FUN_00470430
|
||
numericB->Draw(&localView, (Scalar)vB);
|
||
|
||
if (dirty) { // @0x4ca10f
|
||
dirty = 0;
|
||
BitMap *grid = ((L4Warehouse *)renderer->warehousePointer)
|
||
->bitMapBin.GetIfAlreadyExists(gridImage); // FUN_00442aec
|
||
if (grid != NULL) {
|
||
localView.MoveToAbsolute(cellWidth * 3, 0); // vtbl+0x24 @0x4ca152
|
||
localView.SetColor(gridColor); // vtbl+0x18 @0x4ca163
|
||
localView.DrawBitMap(0 /*rotation*/, grid, // vtbl+0x54 @0x4ca187
|
||
gridLeft, 0, gridRight, gridHeight); // source rect
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**Registration** — `game/reconstructed/btl4grnd.cpp`, in `BTL4MethodDescription[]` immediately before `&BTL4ChainToPrevious` (`btl4grnd.cpp:149`):
|
||
|
||
```cpp
|
||
&SectorDisplay::methodDescription, // "sectorDisplay" -- radar SECTOR X/Z read-out (Secondary overlay)
|
||
```
|
||
|
||
`SectorDisplay` is already reachable there (`btl4grnd.cpp:71` includes `btl4gau3.hpp`).
|
||
|
||
---
|
||
|
||
## 5. Systemic-check verdicts
|
||
|
||
- **Container-Execute override:** ✅ satisfied. `Execute` (slot 16) and `BecameActive` (slot 3, non-inactivating) are both overridden, so the base `Gauge::Execute` `Fail`→`abort()` is never reached. The two `NumericDisplay`s are **private sub-objects drawn directly** (not registered gauges), so there's no child-`Execute`/`GuardedExecute` recursion.
|
||
- **Shadow fields:** none vs the engine base — `subject@0x90` is the first subclass field (base `GraphicGauge` ends before 0x90). The failures found were **internal layout bugs in the current header** (`enabled`↔`subject`, missing `+0xA8`/`+0xB8`, `baseLine/dirty`↔`offsetX/offsetY`), fixed in §3.
|
||
- **Alias / phantom:** none. `numericColor@0xA8` is a real stored field (consumed only by the child ctors, never re-read — faithful, not phantom); `offsetX/offsetY` are two independent `500`s; all members lie within `sizeof 0xC4`.
|
||
- **Databinding NULL risks:** all guarded — `subject==NULL` early-returns (+viewpoint fallback); missing grid image → `GetIfAlreadyExists` NULL → blit skipped + Make warns; `renderer->warehousePointer` always set by the base. Add a `numericA/numericB != NULL` guard before `Draw` if you keep the binary's `new`-can-fail branch (`@0x4c9f20`).
|
||
- **Every-mech crash risk:** ✅ none. This is a **single cockpit gauge** built once for the local pod; it reads the **linked/viewpoint** entity's `localOrigin.linearPosition` through the **engine `Entity` type** (compiled-consistent), never a raw `*(T*)(entity+0xNN)`. It does not iterate mechs and is not per-mech.
|
||
|
||
---
|
||
|
||
## 6. Confidence & unknowns
|
||
|
||
**Confidence: HIGH.** Full function set disassembled (Execute/ctor/dtor/BecameActive/LinkToEntity/vtable), `methodDescription` PE-parsed exact (keyword + 5 typed rows), the `0.01`/`÷100` const decoded, the CFG shape confirmed, and the position binding (`localOrigin.linearPosition`) is the exact mapping the reconstructed radar already uses.
|
||
|
||
**Unknowns / follow-ups (none blocking):**
|
||
1. Whether `GaugeRenderer::LinkToEntity` is broadcast with a real viewpoint in the port. The `application->GetViewpointEntity()` fallback makes the gauge LIVE either way; if you confirm the broadcast fires, the fallback is inert.
|
||
2. `InternName`/`FreeName` (`FUN_004700ac`/`FUN_004022e8`) exact engine symbols — if `NumericDisplay`'s ctor copies the font name internally (siblings pass `p[2].data.string` uncopied), you may store `p[2].data.string` directly and drop the intern/free pair. Cosmetic.
|
||
3. `bitMapBin.Get`(ctor, held) vs `GetIfAlreadyExists`(peek) ref-counting — both compile; the ctor `Get` is balanced by the dtor `Release` (binary-faithful). If `Get`/`Release` aren't symmetric on the WinTesla `L4Warehouse`, use `GetIfAlreadyExists` in the ctor and drop the dtor `Release`.
|
||
4. `FUN_004ca030` (empty `ret`) is an unreferenced `TestClass`/dead stub — not needed for function.
|
||
5. Visual semantics of the blitted cell-12 sub-rect of `helv15.pcc` (`gridLeft=cellWidth*12`) are replicated exactly but not eyeballed; verify against pod footage when the Secondary overlay is composited (`BT_DEV_GAUGES`). |