Files
BT412/scratchpad/wf_4_SectorDisplay_verify.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

71 lines
8.6 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 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:26662704): `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:226238, 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:27892794) 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 `@0x4ca0890x4ca0b9` 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:128129 "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:6971`) — the rewired Make reads `methodDescription.parameterList` (same as the PlayerStatus rewire, line 7273). 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 `@0x4ca0890x4ca0b9` 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`).