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>
71 lines
8.6 KiB
Markdown
71 lines
8.6 KiB
Markdown
I now have everything verified against the raw decomp, the engine headers, the CFG, and the sibling reconstructions. Here is the adversarial verdict.
|
||
|
||
---
|
||
|
||
# ADVERSARIAL VERIFY — SectorDisplay: verdict **APPROVE WITH CORRECTIONS**
|
||
|
||
The spec is structurally sound and its layout corrections over the current (buggy) `btl4gau3.hpp` are **right**. I confirmed sizeof, every ctor offset, the base chain, the Make idiom, the methodDescription row set (against the live CFG), the dtor/BecameActive/Execute structure, and all five systemic-check verdicts. **One substantive error** (a wrong rounding claim with a fabricated justification) and **two confidence downgrades** (disassembly-only claims) must be fixed before implementing.
|
||
|
||
## What I verified as CORRECT (keep as-is)
|
||
|
||
- **Base = `GraphicGauge`, base ctor `FUN_00444818`, sizeof `0xC4`** — Make allocs `FUN_00402298(0xc4)` (part_014.c:2632). ✓
|
||
- **Every ctor offset** vs the raw `param_1[N]` writes (part_014.c:2666–2704): `gridImage@0x94`, `cellWidth@0x98=width/14`, `gridLeft@0x9C=cw*12`, `gridRight@0xA0=cw*13-1`, `gridHeight@0xA4`, `numericColor@0xA8`, `gridColor@0xAC`, both `500`s @0xB0/@0xB4, `numericA@0xBC (x=0)`, `numericB@0xC0 (x=cw*4)`. ✓
|
||
- **The header-layout fixes are real bugs in the current header** — it omits `@0xA8` and `@0xB8`, mislabels `@0x90` as `enabled` and `@0xB0/@0xB4` as `baseLine/dirty`, and wrongly gives the ctor **two** image strings (the raw has ONE, `param_9`, used for both grid + font). Spec fixes all of these. ✓
|
||
- **`@0x90` = `subject` Entity\* set by `LinkToEntity` (slot 9), NOT `enabled`/`SetEnable`** — well-founded: `FUN_004ca068` is a bare `this[0x24]=param` setter, base slot9 is the empty `LinkToEntity`, and Execute gates on `+0x90 != 0` and reads a *position* from it. This is the correct reinterpretation of the current header. ✓
|
||
- **methodDescription 5-row set** (`typeRate, typeModeMask, typeString, typeColor, typeColor`) — matches the Make's DAT_ reads AND the live CFG (`content/GAUGE/L4GAUGE.CFG:5146`): `sectorDisplay(K, ModeAlwaysActive, helv15.pcc, 0, 3)` with `offset=(125,579)` supplied separately. ✓
|
||
- **Make/ctor base-chain idiom** — identical to the registered sibling `PilotList` (`btl4gau3.cpp:226–238, 253`): `ParameterDescription *p = methodDescription.parameterList; … GraphicGauge(rate,mode,renderer,0,port,id)`. ✓
|
||
- **dtor** (implicit base, release grid, free name, delete numerics), **BecameActive** (dirty=1, ForceUpdate B-then-A, non-inactivating), **Execute** grid blit (`MoveToAbsolute(cw*3,0)`+`SetColor(gridColor@0xAC)`+`DrawBitMap(0,grid,gridLeft,0,gridRight,gridHeight)`) — all match the raw byte-for-byte. ✓
|
||
- **Systemic checks all correct**: Execute (slot16) + non-inactivating BecameActive (slot3) both overridden → no `Gauge::Execute` `Fail`→`abort`; the two NumericDisplays are private members drawn directly, not registered children → no child-`GuardedExecute` recursion; no shadow/alias/phantom fields; `subject`-NULL guarded with the viewpoint fallback; single cockpit gauge, not per-mech. ✓
|
||
- **`renderer->warehousePointer` is reachable in member methods/dtor** — confirmed by `PlayerStatus::Execute` (`btl4gau3.cpp:673`). Registration line goes before `&BTL4ChainToPrevious` (`btl4grnd.cpp:150`). ✓
|
||
|
||
## CHANGES I made (what was wrong)
|
||
|
||
**① CRITICAL — `FUN_004dcd94` is `ROUND`, not truncate.** Confirmed at its definition (`part_015.c:3769`): `local_10 = (undefined4)(longlong)ROUND(in_ST0);` — round-to-nearest (x87 `frndint`, half-to-even). The codebase's own map agrees (`btl4gau3.cpp:36` "FUN_004dcd94 Round"; CLAUDE.md). The spec asserts the **opposite** ("truncate toward zero … RC=chop `or 0xc`, `fistp` … `(long)` not round-to-nearest") — that justification is **fabricated**; there is no `or 0xc`/`fistp` in the function. Fix: the two numerics must **round**, not C-truncate. Use `lrintf` (default FE_TONEAREST == `frndint`) or the engine `Round`, never `(int)(x)`.
|
||
|
||
**② Downgrade the position data-binding to disassembly-sourced / MEDIUM confidence.** The pseudocode Execute (`FUN_004ca07c`, part_014.c:2789–2794) shows **only** `iVar2 = FUN_004dcd94(); iVar3 = FUN_004dcd94();` — the decompiler dropped the x87 operand loads. So the *entire* mapping (that `iVar2 = -Z·0.01`, `iVar3 = +X·0.01`, the `fchs`, and the `0.01` scale) is the reviewer's disassembly, which was **provably wrong on `FUN_004dcd94`**. The `subject != 0` gate + the two `+500` offsets + drawing two numerics are pseudocode-solid; the **which-axis / sign / scale** are not. Keep the mapping as the best structural reconstruction but mark it, and re-disassemble `@0x4ca089–0x4ca0b9` to lock the axis/sign/scale before claiming fidelity. (The read itself — `subject->localOrigin.linearPosition` via the engine `Entity` type — is confirmed as the established radar pattern: `btl4rdr.cpp:150` reads `entity->localOrigin.linearPosition`; `ENTITY.h:140 Origin localOrigin`; entity+0x100 == that per `btl4rdr.cpp:622`.)
|
||
|
||
**③ Unify the `FUN_00442aec` naming to `GetIfAlreadyExists`** (the codebase's established name, `btl4gau3.cpp:128–129 "peek, no AddRef"`). The spec inconsistently modeled the identical call as `bitMapBin.Get` (held) in the ctor but `GetIfAlreadyExists` (peek) in Make/Execute. Use `GetIfAlreadyExists` in all three; keep the dtor `Release` (`FUN_00442c12`, part_014.c:2717) balancing the ctor's held reference and the Make existence-check Release (part_014.c:2640) — that is binary-faithful.
|
||
|
||
**④ Minor:** remove the now-unused static `DAT_0051a2bc/0300/0344` placeholders (`btl4gau3.cpp:69–71`) — the rewired Make reads `methodDescription.parameterList` (same as the PlayerStatus rewire, line 72–73). Drop the redundant `(L4Warehouse*)` cast in Make (`warehousePointer` is already typed, per line 128). Confirm `NumericDisplay::unsignedFormat == 0` (raw format arg is literal `0`); if unsure use `(NumericDisplay::Format)0`. The `offsetX/offsetY` names are misleading (both `500`; A feeds the Z-numeric, B the X-numeric) — rename `sectorBaseA/sectorBaseB` or just comment "both = 500".
|
||
|
||
## Corrected Execute (the only body that changes)
|
||
|
||
```cpp
|
||
// @0x4ca07c -- Execute (slot 16). RAW: iVar2/iVar3 = FUN_004dcd94() = ROUND(ST0)
|
||
// (part_015.c:3769); the x87 operand loads were dropped by the decompiler, so the
|
||
// -Z / +X axis assignment, the fchs and the 0.01 scale are DISASSEMBLY-sourced
|
||
// (@0x4ca089-0x4ca0b9) and MEDIUM-confidence -- re-verify before claiming fidelity.
|
||
void SectorDisplay::Execute()
|
||
{
|
||
Entity *s = subject; // this+0x90
|
||
if (s == NULL && application != NULL) // PORT: LinkToEntity broadcast
|
||
s = (Entity *)application->GetViewpointEntity(); // may be unwired -> fall back
|
||
if (s == NULL)
|
||
return; // binary gates purely on subject!=0
|
||
|
||
const Point3D &pos = s->localOrigin.linearPosition; // engine type (NOT raw +0x100)
|
||
int vA = (int)lrintf(-pos.z * 0.01f) + sectorBaseA; // ROUND, not (int) truncate
|
||
int vB = (int)lrintf( pos.x * 0.01f) + sectorBaseB;
|
||
numericA->Draw(&localView, (Scalar)vA); // FUN_00470430
|
||
numericB->Draw(&localView, (Scalar)vB);
|
||
|
||
if (dirty) { // this+0xB8
|
||
dirty = 0;
|
||
BitMap *grid = ((L4Warehouse *)renderer->warehousePointer)
|
||
->bitMapBin.GetIfAlreadyExists(gridImage); // FUN_00442aec
|
||
if (grid != NULL) {
|
||
localView.MoveToAbsolute(cellWidth * 3, 0); // vtbl+0x24
|
||
localView.SetColor(gridColor); // vtbl+0x18 (this+0xAC)
|
||
localView.DrawBitMap(0, grid, gridLeft, 0, gridRight, gridHeight); // vtbl+0x54
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
Everything else in the spec (identity table, the `0xC4` overflow-lock, the methodDescription literal, the registration line, ctor/dtor/Make/BecameActive/TestInstance bodies) is **correct as written** — apply only ①–④.
|
||
|
||
## FINAL CONFIDENCE
|
||
|
||
**HIGH** on structure, layout, registration, and all systemic-check verdicts (pseudocode-verified). **MEDIUM** on the numeric data-binding specifics: the value is a *rounded* `±position·0.01 + 500`, but the exact axis→numeric assignment and the sign of Z are disassembly-only and the reviewer's disassembly was demonstrably unreliable (it inverted the rounding mode). Re-disassemble `@0x4ca089–0x4ca0b9` to lock the axis/sign/scale; nothing else blocks implementation.
|
||
|
||
**Remaining UNKNOWNS (non-blocking):** exact axis/sign/scale of the position read (②); whether `GaugeRenderer::LinkToEntity` is broadcast in the port (the viewpoint fallback makes it LIVE either way); `NumericDisplay::unsignedFormat`'s enum value (raw = `0`). |