MapDisplay (the radar/threat-map gauge, btl4rdr.cpp) was fully reconstructed
(ctor + Execute + DrawViewWedge/DrawStatic/DrawMoving/DrawNames) but never
registered and its data attributes never published. Wire it up end-to-end:
DATA (the attributes the map binds):
* Mech table extended to the full 0x15..0x38 (was the 0x21 prefix): add
RadarRange@0x2f -> radarRange, RadarLinearPosition@0x30 -> radarLinearPosition
(Point3D* -> &localOrigin.linearPosition), RadarAngularPosition@0x31 ->
radarAngularPosition (Quaternion* -> &localOrigin.angularPosition), DuckState
@0x37 -> duckState; the rest bind the shared attrPad (kept dense so Find can't
strcmp a gap). New members set in the Mech ctor; radarRange defaults to 500
(SetTargetRange is still stubbed) so nearby contacts are on-scale. The map's
position/angle attributes resolve to Point3D**/Quaternion** (AttributePointer
is int Simulation::*, so the ATTRIBUTE_ENTRY reinterpret binds pointer members
fine -- verified live: posPtr/anglePtr resolve).
* Sensor (named "Avionics") publishes RadarPercent/SelfTest/BadVoltage: define
Sensor::AttributePointers[] + build the previously-empty Sensor::AttributeIndex
chained to PoweredSubsystem::GetAttributeIndex() (= HeatSink's dense index).
WIDGET (the registration glue -- NOT in the assert-anchored decomp, so
reconstructed from the config + ctor):
* MapDisplay::methodDescription (config "map") + MapDisplay::Make. The
offset_position keyword "center"/"bottom" is typed as a STRING and converted
in Make, avoiding a ModeManager named-constant registration. Registered in
BTL4MethodDescription[] (btl4grnd.cpp now includes btl4rdr.hpp).
Three crash fixes exposed once the map ran (each a pre-existing stub the map is
the first consumer of):
* Sensor radarPercent went hugely negative (RadarBaseline - HeatMasterEnergy(),
where the inherited heatEnergy is un-normalized in the not-byte-exact heat-leaf
branch) -> the radar reported non-operational. Guard: treat an out-of-[0,1]
heat term as no penalty (marked bring-up; real overheat penalty needs the heat
normalization).
* ResolveOperatorEntity was a stub returning NULL -> EntityPosition(NULL) crashed
CalculateBounds. Fixed to the renderer linked-entity + application viewpoint
fallback (same as HeadingPointer).
* MapName::ExtractFromEntity didn't guard a NULL entity (the binary's Verify(False)
iterator-mismatch path compiles out at DEBUG_LEVEL 0) -> EntityPosition(NULL).
Guarded.
Verified live (BT_DEV_GAUGES): the radar now draws the view wedge (the mech's
180-deg FOV cone) and completes the full wedge/static/moving/names cycle with
operating=1, cap=1, scale=500, position/angle resolved, 0 crashes. Combat un-
regressed (TARGET DESTROYED after 8 hits), heap-clean under BT_HEAPCHECK.
Permanent gated diagnostic: BT_MAP_LOG traces the phase/draw pipeline. Contacts
show 0 (the spatial-query entity classification is a follow-up); DuckState now
resolves for the duck button too.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>