Propagate the verified finding (0xBD3 = damage/explosion hub @0x434, NOT the valve/message gate; the valve/Myomers gates read the owning BTPlayer @mech+0x190) into the topic files that still carried the old claim: decomp-reference (ClassID row + both offset rows), gauges-hud, subsystems, open-questions (Myomers coupling), + frontmatter. Graph validates clean. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
91 lines
6.0 KiB
Markdown
91 lines
6.0 KiB
Markdown
---
|
||
id: gauges-hud
|
||
title: "Cockpit Gauges / MFD HUD system"
|
||
status: established
|
||
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"
|
||
---
|
||
|
||
# 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]
|
||
|
||
## Key Relationships
|
||
- Full history: `docs/GAUGE_COMPOSITE.md`.
|
||
- Uses: [[attribute-pointer]] + [[reconstruction-gotchas]]; reads [[subsystems]] state.
|
||
- Renders on: [[pod-hardware]] MFD surfaces.
|