Files
BT411/context/gauges-hud.md
T
arcattackandClaude Fable 5 48b17750e5 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>
2026-07-08 20:05:44 -05:00

7.5 KiB
Raw Blame History

id, title, status, source_sections, related_topics, key_terms, open_questions
id title status source_sections related_topics key_terms open_questions
gauges-hud Cockpit Gauges / MFD HUD system established docs/GAUGE_COMPOSITE.md (full map); CLAUDE.md §8
reconstruction-gotchas
decomp-reference
subsystems
pod-hardware
gauge
methodDescription
attribute-pointer
GaugeRenderer
MFD
PCC
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

Cockpit Gauges / MFD HUD

The pod's cockpit instruments: the secondary MFD (radar/heat/comm), the 5 mono MFDs, and the engineering screens. Full map + per-widget history in docs/GAUGE_COMPOSITE.md. The gauge system is COMPLETE at the registration+binding level: all 50 config attribute bindings resolve (0 NULL) and every config gauge primitive is registered + built (0 parse-skips). [T2]

Architecture (three layers)

  1. The config content/GAUGE/l4gauge.cfg — a text file the engine GaugeInterpreter parses (BuildConfigurationFile → Initialize → GetProcedureBody → ParsePrimitive). Each mech's gauge tree is built from the label GetGameModel()+"Init" (e.g. bhk1Init), which invokes shared blocks (MechInit, Secondary1) that configure the ports and call gauge primitives. [T1]
  2. Widgets — each keyword(...) in the config resolves to a MethodDescription in BTL4MethodDescription[] (btl4grnd.cpp). An UNREGISTERED keyword is parse-skipped (never built). Base primitives (numeric/digitalClock/rankAndScore/vertBar-base/segmentArc) are ENGINE (L4GAUGE.cpp); BT-specific ones (vertBar/map/pilotList/GeneratorCluster/ sectorDisplay/prepEngr/messageBoard/vehicleSubSystems/the ColorMapper family) are reconstructed + registered. [T2]
  3. Data binding — gauges bind to game state by NAME via the engine attribute-pointer system: the config's Subsystem/Attribute (e.g. HeatSink/CurrentTemperature) resolves through ParseAttribute → FindSubsystem (stricmp GetName()) → GetAttributePointer. A class PUBLISHES an attribute via a <Name>AttributeID enum + static AttributePointers[] (ATTRIBUTE_ENTRY) + GetAttributeIndex() chained to its parent. ⚠ DENSE-TABLE HAZARD (see reconstruction-gotchas §11). [T2]

Reconstructing a widget — the recipe

MethodDescription Class::methodDescription = { "keyword", Class::Make, { ParameterDescription rows } }; + a line in BTL4MethodDescription[] before &BTL4ChainToPrevious. The static Make(int port, Vector2DOf<int> pos, Entity*, GaugeRenderer*) reads methodDescription.parameterList[], allocs (operator new(binSize) or plain new), placement-news the ctor. Then ctor/dtor/ TestInstance/BecameActive/Execute. Gotchas that bite EVERY widget:

  • Container-Execute must override (§10 gotchas) — else Gauge::Execute aborts.
  • /FORCE trap — a prose-only slot AVs on first call.
  • Databinding trap — never raw-read owner offsets; use a bridge (BTGetSubsystemAuxScreen, …).
  • ReconStream no-op — use DEBUG_STREAM for logs, not DebugStream.
  • Lazy build — wait for the gauge window before concluding "not built" (BT_GAUGE_SKIP_LOG). [T2]

The completed widgets (this project's gauge wave)

  • Attributes published: HeatSink table (Degradation/Failure/NormalizedPressure/CoolantMassLeakRate/ ValveSetting/…), PoweredSubsystem (InputVoltage), MechWeapon (OutputVoltage), Mech (LinearSpeed, radar Position/Quaternion), Sensor (RadarPercent), AggregateHeatSink (AmbientTemperature=300 — the LAST NULL). [T2]
  • Widgets reconstructed + registered: ColorMapper family (cmHeat/cmCrit/cmArmor/multiArmor), headingPointer, vertBar (VertTwoPartBar), segmentArcRatio, oneOfSeveralPixInt, map (radar), PlayerStatus, vehicleSubSystems (the engineering cluster panels), LeakGauge, vertNormalSlider, pilotList (Comm KILLS/DEATHS), GeneratorCluster, SectorDisplay (radar SECTOR X/Z read-out — live), PrepEngrScreen (12 engineering-screen label overlays), MessageBoard (comm ticker — deferred-empty). [T2]
  • Condenser valve gauge: ValveSetting→coolantFlowScale reads the authentic 1/N (RecomputeCondenserValves, FUN_0049f788, was a no-op stub). [T2]

Dev composite (off-pod)

BT_DEV_GAUGES renders the 6 pod MFD surfaces in a separate 960×384 window (bit-plane masks over one shared SVGA16 pixelBuffer; SVGA16::DrawDevSurface). On the POD they come from SETENV.BAT/L4GAUGE on the real multi-adapter hardware (FindBestAdapterIndices/BuildWindows, intact). The overlay port (SectorDisplay lives there) shares the sec physical surface via a different bit-plane (0x00C0). [T2]

Authentically-static (do NOT "fix")

currentTemperature ~77 (huge thermalMass ~1.39e6 → a 3.5-heat shot rounds to zero); Degradation/Failure temps are fixed markers; AmbientTemperature 300; CoolantMassLeakRate 0 on a pristine mech (damage-gated); cmArmor/cmCrit all-green (undamaged solo player — BT is PvP-only); RANK 1 solo; MessageBoard empty (no status messages exist in bring-up). The Heat MFD is authentically NEAR-STATIC, not a live heat-accumulation display. [T2]

Remaining = DATA FEEDS, not widgets (deferred systems)

The condenser valve CONTROL gates on the owning BTPlayer's game-mode flag (mech+0x190, GetPlayerLink(), via MechSubsystem::IsDamaged/FUN_004ac9c8 reading player+0x274) — NOT the 0xBD3 messmgr (a common earlier misconception; 0xBD3 is a damage/explosion hub at Mech[0x10d]=0x434). In a basic mission the valve/mode flags are likely off, so the dormant valve is plausibly AUTHENTIC — see open-questions mech+0x190. The MessageBoard feed needs StatusMessagePool (a NULL 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