HUD reticle + weapon pips LIVE: dpl2d 2D display-list port (task #35)

- dpl2d API fully recovered from the binary recorders (@487f34-488630):
  opcode model (points/lines/polyline/circle/color/width/matrix/push-pop),
  CallList = INLINE include (state persists to caller), centered coordinate
  frame (unit = half viewport height). game/reconstructed/dpl2d.cpp rework.
- BTReticleRenderable ctor @004cc40c transcribed with the authentic
  calibration (originX .35, originY .25, scaleY .5, 0..1200m right range
  ladder, bottom heading tape, FUN_004cd938 tick ladders, lock rings,
  turn arrows); range caret slides from the live target range fed by the
  mech4 targeting step (BTSetHudTargetRange).
- Weapon pips: the binary gate is IsDerivedFrom(0x511830 =
  MechWeapon::ClassDerivations) [T1: part_014.c:5386 hard-aborts on missing
  weapon attrs; part_012 counts + roster ORs capabilityFlags@+0x334] so ALL
  7 BLH weapons register (3 lasers + 2 PPCs + 2 MissileLaunchers). Pip A
  (lit, authored PipColor) on TargetWithinRange, else dark ring B.
- AddWeapon @004cdac0 store map corrected to the verified order
  (part_014.c:4827-4837); both state attrs are literally named
  "SimulationState" (strings @51d526/51d577) -> weapon simulationState.
- Mech roster this[0x1ef] renamed poweredSubsystems -> weaponRoster
  (0x511830 is MechWeapon, not PoweredSubsystem=0x50f4bc); derivation-tag
  table added to context/decomp-reference.md.
- Draw hook BTDrawReticle after the 3D scene, cockpit view only. Binary
  Execute @004cdcf0 is an un-exported gap -> Draw dynamics [T3], tracked
  in context/open-questions.md with the blx_cop canopy + PNAME pip meshes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
arcattack
2026-07-08 20:05:44 -05:00
co-authored by Claude Fable 5
parent 1cd8ca1a80
commit 48b17750e5
15 changed files with 593 additions and 109 deletions
+12
View File
@@ -77,6 +77,18 @@ Identify a class at runtime with `sub->GetClassID()` (== `sub+4`). [T1]
- **Heat leaf:** `PoweredSubsystem : HeatSink : HeatableSubsystem : MechSubsystem` (Emitter/PPC/Sensor/Myomers/weapons chain here). [T1]
- **Watcher branch:** `Torso/Gyroscope/Searchlight/ThermalSight/HUD : PowerWatcher : HeatWatcher : MechSubsystem`; `AmmoBin : HeatWatcher`. Uses a 0xC connection + 0x54 alarm (NOT the 4/8-byte heat-leaf types). [T1]
### Derivation-tag addresses (`FUN_0041a1a4(obj, tag)` = IsDerivedFrom)
| Tag | Class | Evidence |
|---|---|---|
| **0x511830** | **MechWeapon**::ClassDerivations | The reticle AddWeapon loop (part_014.c:5386) hard-aborts on missing WeaponRange/PipPosition/… attrs for every member; part_012.c:9344 counts ready weapons; the Mech ctor roster at this[0x1ef] (`weaponRoster`, ex-mislabel "poweredSubsystems") ORs weapon `capabilityFlags`@+0x334. [T1] |
| 0x50f4bc | PoweredSubsystem | btl4gau2 gauge wave. [T1] |
| 0x50e3ec | HeatableSubsystem | btl4gaug widget gate. [T1] |
| 0x50e604 | HeatSink | btl4gaug widget gate. [T1] |
| 0x51155c | roster at Mech this[0x1eb] (`heatableSubsystems` label) | tag ≠ 0x50e3ec — the label is UNVERIFIED [T4]; arbitrate before relying on it. |
| 0x50e4fc | roster at Mech this[499] (`damageableSubsystems` label) | [T3] |
| 0x50bdb4 | Mech | emitter.cpp destroyed-check. [T1] |
| 0x5121a8 | ProjectileWeapon-family (checked after 0x511830; reads ammo state @+0x364) | [T3] |
---
## 3. Mech struct offsets (`Mech*`, binary layout)
+18 -1
View File
@@ -84,7 +84,24 @@ see [[open-questions]] `mech+0x190`. The **MessageBoard** feed needs **StatusMes
stub) + the per-player status queue. `SeekVoltageGraph`'s 4 Seek* attrs are a cluster-child (not
config-called). [T2]
## Cockpit HUD reticle (main screen, inside view) — LIVE
`BTReticleRenderable` (0x358 bytes, ctor @004cc40c) draws over the finished 3D frame in cockpit
view only, via the recovered **dpl2d** 2D display-list API (recorders @0x487f34-0x488630; opcode
map + coordinate model in `phases/phase-02-dpl2d-reticle.md`; port: `game/reconstructed/dpl2d.cpp`).
Geometry is the ctor's hardcoded calibration (originX 0.35, originY 0.25, scaleY 0.5, right range
ladder 0..1200 m, bottom heading tape, center cross + dot; tick ladders via FUN_004cd938). The
range caret binds to the live target range (`BTSetHudTargetRange`, fed by mech4's targeting step).
**Weapon pips:** the build loop (part_014.c:5386) registers EVERY subsystem
`IsDerivedFrom(0x511830 = MechWeapon)` — lasers, PPCs AND missile launchers (BLH = 7 pips) — via
`AddWeapon` @004cdac0 (verified store map in btl4vid.hpp), reading WeaponRange/PipPosition/
PipColor/PipExtendedRange/TargetWithinRange/SimulationState(attrs 1+0x1c)/RearFiring. Pip A (lit,
authored PipColor) when TargetWithinRange, else the dark ring B. [T2 geometry+wiring]
The binary's per-frame `Execute` @004cdcf0 sits in an UN-EXPORTED decomp gap — the Draw dynamics
(caret slide, pip lit/dark; lock rings/turn arrows built but static) are best-effort [T3].
Deferred: PNAME1-8.bgf 3D pip meshes + the 3D marker chain; the `blx_cop` canopy shell renders
black and is hidden by name filter (`BT_INSIDE_COCKPIT=1` shows it) — see [[open-questions]].
## Key Relationships
- Full history: `docs/GAUGE_COMPOSITE.md`.
- Full history: `docs/GAUGE_COMPOSITE.md`; reticle recovery: `phases/phase-02-dpl2d-reticle.md`.
- Uses: [[attribute-pointer]] + [[reconstruction-gotchas]]; reads [[subsystems]] state.
- Renders on: [[pod-hardware]] MFD surfaces.
+9
View File
@@ -51,6 +51,15 @@ authentic path scoped.
these are MODE flags — in the basic test mission the inert Myomers / dormant valve is likely AUTHENTIC
(advanced damage off); wiring makes them RESPOND when a mission enables the mode, not necessarily change
the basic-mission behavior. The MessageBoard feed is separate (StatusMessagePool, below).
- **Cockpit HUD leftovers (task #35 residue, 2026-07-08)** — the reticle + 7 weapon pips are LIVE
(see [[gauges-hud]] + `phases/phase-02-dpl2d-reticle.md`), but three pieces remain: (a) the
**blx_cop canopy shell** renders BLACK (untextured/unlit in our inside view) so it's hidden by a
name filter — `BT_INSIDE_COCKPIT=1` shows it; the authentic look needs its material/lighting
path; (b) the **PNAME1-8.bgf 3D pip meshes** + the 3D target-designator marker chain (the ctor's
15-arg form binds 8 HUD-subsystem attrs we bypass); (c) the binary per-frame **Execute
@004cdcf0** is in an un-exported decomp gap — the Draw dynamics (lock rings, off-screen turn
arrows, blink states, the 3 cached "SimulationState" constants 2/3/1) are best-effort [T3];
a Ghidra re-export of the 0x4cdcf0 region would let us transcribe it properly.
- **StatusMessagePool (NULL stub, btstubs.cpp:62)** — the per-player status-message queue.
BTPlayer+0x1dc is never populated → MessageBoard is empty (authentic for bring-up). What
resolves it: wire the pool + decode `AddStatusMessage @0042e580` + the `Player__StatusMessage`