Gauges: the CLOSEOUT wave -- radar pips, Myomers dedup, attribute parity, ledger sweep (tasks #14-#17)

TASK #17 -- AUTHENTIC RADAR SYMBOLOGY (the cross-blip stand-in retired).
The recon proved the 'missing pip raster set' never existed as BT game code:
pips are the ENGINE's L4GaugeImage vector-stroke system (T0 source in tree,
L4GAUIMA.cpp == FUN_0046f0c0 line-for-line), the 'pip table' is L4Warehouse::
gaugeImageBin keyed by Entity::resourceID, and BTL4.RES ships 110 type-0x12
shapes (every mech/vehicle/building/tree).  The six btl4rdr stubs are wired
to the real facilities: contacts draw their authentic model silhouettes with
LOD selection, the target gets the binary's 4px-inflated box highlight, and
player-name labels resolve via Mission::GetSmallNameBitmap (the prebuilt
64x16 egg rasters keyed by the player's bitmapindex).  DECODED: the invented
'VideoObject' was Entity::owningPlayer all along (+0x190; nameID =
playerBitmapIndex@0x1E0, target = BTPlayer::objectiveMech@0x284 -- new
bridge BTPlayerObjectiveMechOf); the 'LabelledEntity' class is Landmark
(cultural.h; label path dormant -- no landmark content ships, no runtime
landmarkID writer).  The L4GREND BT_DEV_GAUGES warehouse guard is removed
(its AV had a different culprit, below); resource type 18 corrected to
GaugeImageStream in decomp-reference (was mislabeled 'ModelList').

TASK #14 -- the Myomers ODR duplicate ELIMINATED: the powersub.cpp/hpp
'Myomers' (classID 0xBC3 -- actually Sensor) is retired whole; it duplicated
?DefaultData@Myomers@@ against the real class (dumpbin-verified) and /FORCE
picked the winner by link order.  The real Myomers (0xBC6) now chains
PoweredSubsystem's handler set (ids 4-8) and publishes its SEVEN binary
attributes (@00511588: SpeedEffect/Current/Recommended/Min/MaxSeekVoltage-
Index/SeekVoltage/OutputVoltage) -- the old empty unchained index starved
the Myomer engineering panel of every resolve.

TASK #16 -- attribute parity: MechWeapon publishes the FULL binary table
@0x511890 (11 entries; ids renumbered to binary truth -- the port aliases
had squatted the binary's DistanceToTarget/TargetWithinRange ids; the
streamed TriggerState 0x13 binding unchanged).  Binary names resolved two
TODO members: pipState -> estimatedReadyTime (attr 0x1A), and the EXT-model
flag is the binary's RearFiring (0x1B).  ThermalSight LightState published.
HUD (offset conflicts) + missile-side tables (id encoding suspect)
documented for a re-dump instead of publishing blind.
  THE CRASH THIS EXPOSED [T2, cdb-verified]: gotcha #11's dense-table gap
is a LATENT AV, not a guaranteed one -- the old table's 0x0D..0x12 gap
(task #5) survived on heap luck; the renumber reshuffled allocations and
Find() AV'd on a garbage entryName in WeaponCluster's PercentDone resolve.
Fixed with five named PAD entries (the mech.cpp attrPad idiom) + a
static_assert locking the pad base to PoweredSubsystem::NextAttributeID.
Gotcha #11 amended with the proof.

TASK #15 -- stale-ledger sweep: GAUGE_COMPOSITE ('composite not yet built',
Reservoir shadow, PlayerStatus/vehicleSubSystems 'remaining', valve-dormant-
until-0xBD3, sensor guard, the superseded 'Heat MFD near-static' reframe --
all banner-corrected), gauges-hud frontmatter, L4VB16 + powersub comments.

Verified live: 50/50 config attribute bindings resolve, 0 NULLs, 0 parse
skips, mech spawns and simulates 31/31 subsystems, no cross-blip fallbacks,
the pip cache fills through entity registration without the old guard.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-12 00:57:45 -05:00
co-authored by Claude Fable 5
parent 80cadc98c7
commit dd27238ceb
16 changed files with 309 additions and 384 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ NOT `SearchList(clip_id, 16)` (which treats the arg as a LIST → walks garbage
|---|---|---|
| SkeletonStream | — | `.SKL` skeletons |
| DamageZoneStream | **0x14** | damage-zone records (Mech ctor reads count + array) |
| ModelList | **18** | model/mech names (`bhk1`, `madcat`, …) |
| GaugeImageStream | **18** (0x12) | radar PIP vector shapes (.GIM linelist; keyed by the entity model's resource id -- `bhk1`=1025, `madcat`=401, …; 110 ship in BTL4.RES). task #17 CORRECTION: the old "ModelList = model/mech names" label was wrong -- the names matched because pips are stored under their model's name/id. |
| AnimationResourceType | **16 (0x10)** | animation clips (lowercase: `blhrrl`=904, `blhrrr`=905, `blhwwli`=910, `blhrrli`=916) |
| damage-zone segment list | 0x14 | per-zone segment list |
| critical-subsystem segment | 0x1e | crit subsystem segments |
+1 -1
View File
@@ -6,8 +6,8 @@ source_sections: "docs/GAUGE_COMPOSITE.md (full map); CLAUDE.md §8"
related_topics: [reconstruction-gotchas, decomp-reference, subsystems, pod-hardware]
key_terms: [gauge, methodDescription, attribute-pointer, GaugeRenderer, MFD, PCC]
open_questions:
- "Condenser valve control gates on the owning BTPlayer game-mode flag (mech+0x190), likely off in basic missions"
- "Status-message queue (StatusMessagePool) is a NULL stub -> MessageBoard is empty"
- "HUD binary attr table @005110c0 offsets conflict with the port HUD layout on 3 slots (0x1D8/0x1EC/0x1F8) -- re-dump before publishing"
---
# Cockpit Gauges / MFD HUD
+10
View File
@@ -188,6 +188,16 @@ published attribute table MUST be a **dense prefix** from the parent's `NextAttr
AVs. Fill gaps with a shared read-only pad member. Same for a class's `<Name>AttributeID` enum.
[T2]
**PROVEN LIVE (task #16):** a gap does NOT necessarily crash immediately — the garbage slot's
`entryName` may happen to point at readable heap, so a gapped table can "work" for weeks (the
MechWeapon table's 0x0D..0x12 gap shipped in task #5 and survived on heap luck). ANY change
that reshuffles allocations (the task-#16 renumber did) can then fire the latent AV — observed
as `AttributeIndexSet::Find` crashing in `WeaponCluster::WeaponCluster("PercentDone")`. A
"passes the run" verification does NOT clear a gapped table; grep every pinned
`<Name>AttributeID = 0xNN` and check the parent chain actually reaches 0xNN-1, else pad
(mechweap.cpp now static_asserts its pad base against `PoweredSubsystem::NextAttributeID`).
[T2]
## 12. Frame-pacing trap — the binary assumes a LOCKED 60 fps (task #11)
The 1995 pod ran frame-locked; reconstructed per-frame logic can carry HIDDEN frame-rate