Files
BT411/docs/RADAR_MAP_AUDIT.md
T

6.4 KiB
Raw Blame History

Radar/Map Display Drift Audit — binary vs port vs content (2026-08-14)

What this is: the AI-facing ledger of the radar/map subsystem audit (3-agent, full reports preserved at scratchpad/night17/radar_audit_{bin,port,content}.txt; ~800k tokens of reads). Trigger: #49 (arena walls missing from radar) + the field report "many map items aren't showing on radar, like map boundaries." Companion fix: the static world feed, commit c2193e2 (#49 CLOSED, operator-verified).

The architecture, as the machine built it [T1 unless noted]

  • ONE radar picture for every map/mech: the 480×640 portrait BTSEC1.PCX + BTSEC1OV.PCX baked art (tick ring + crosshair — no range rings exist), with the live map( widget in the (366,367) scope rect at (58,229). There is no per-map radar art and no map page — the ModeMapping bit is the weapon-button CONFIG session, not cartography (aliased ModeNonConfig [T0]).
  • Entity membership (@004cbfa0, the interest feed): an entity reaches the scope iff (a) a type-0x12 GaugeImageStream pip exists for its resourceID AND (b) Mover-derived → moving list, else Terrain-GRAPH-derived → static list. The derivation graph parents UnscalableTerrain (0x2A), CulturalIcon (0x5E) and Landmark (0x56) onto Terrain [T0 TERRAIN.cpp:183, CULTURAL.cpp:27] even though their C++ bases differ.
  • Draw order (@004c22c4): wedge → static pips → moving pips → name labels, inside a stroke recorder (erase = replay last frame in bg color).
  • DrawStatic (@004c25b4): each in-capability static's pip drawn with the entity's FULL transform — walls/buttes/hills/ridges/buildings/trees rendered as world-rotated, metre-scaled staticColor(3) outlines. 110 authored GIMs ship (wall1-3, aw01-05, ab*/ar*/bld*, buttea-e, hillg/dhillg 652-byte contours, sr1e/n/s/w polar rails, tree, dish, …).
  • DrawMoving (@004c2788): every mover except the operator, color 7, target boxed (+4px, hotbox color 1). NO self-blip; NO pipless fallback (every shipped mech has a pip).
  • DrawNames (@004c28c4): ≤16 callsign labels (64×16 egg rasters via playerBitmapIndex); the target's label BLINKS at frame rate.
  • Zoom: 6-step exponential, RadarRange = 250·2^level (250…8000 m scope width), SLEWED smoothly; SCALE numeric shows it live. Capability radius = RadarPercent × 4000 m — radar damage shrinks detection (#105/#121 pending).
  • Wedge: hardcoded π/8 half-angle (45° total); the config's "180" param only sizes the DEAD shadow table. (Manual says "60° field of vision" — print-vs-code drift, the code wins for 4.10 [T1 vs manual].)

Authenticity verdicts the port must respect

  1. The pure map boundary was INVISIBLE on the shipped machine. Every outdoor map places one wall10k (collision solids only, ±4100 m ring — no pip, no video model). Players saw a "boundary" only where visible wall/ridge ENTITIES formed the perimeter (arena aw*, polar sr1* rails, rav buttes). Do NOT invent a boundary rectangle. (ExistanceBox type-26 extents: arena ±700, rav ±1000, others ±7000 — available if a design call ever wants one.)
  2. BuildRadarShadow (@004c228c) compiled EMPTY — radar occlusion shading was cut before ship. The port's empty body is faithful.
  3. Authored pip omissions are design: floors/sky, wall10k, overhead butte tops (butteeu), walkways/banners, snow banks have NO pips on purpose. Never force-draw them.
  4. Missile pips are authored dead content: lrm/srm/strk/nrk GIMs ship, but Projectile/Missile are Entity-derived in the graph — they fail both class tests and never listed on the machine either.
  5. Landmark labels + DropZone blips: dormant/absent (zero Landmark instances; DropZones carry rid 1).

The #49 root cause + fix (2026-08-14, c2193e2)

The port dropped the engine's per-entity interest feed and replaced it with GaugeRenderer::RebuildEntityGrid — which iterated DYNAMIC masters/replicants only. The 1008 statically-registered UnscalableTerrain instances (every wall, butte, hill, ridge, big building) never entered the static grid; DrawStatic (fully transcribed and working) had nothing to draw. Dynamic-registering CulturalIcon props (e.g. grass's 313 trees) were the only statics that ever showed. Fix: a third RebuildEntityGrid pass files non-dynamic Terrain-graph entities from HostManager::AllEntityIterator; pipless ones no-op at the pip lookup exactly as on the machine. Receipts: [map-grid] worldStatics= census + capped per-static [map] static ent/cls/rid/pip/dsq dump (BT_MAP_LOG). Benched grass (hill cls=42 rid=2190 pip=1 drawing + trees) and arena1 (126 world statics, aw walls rid 1918/1915 drawing, unpipped props skipped); operator-verified visually on arena1.

Known port deviations (deliberate, inventoried)

  • Three visible-radius culls (DrawStatic/DrawMoving/DrawNames) drop contacts between scope radius and capability radius instead of the binary's draw-and-clip — justified by the shared gauge surface (out-of-port draws land on neighbors). Revisit only with a real GraphicsView clip.
  • Cross-blip fallback for pipless movers (dev content insurance; dead in the field — every shipped mech has a pip).
  • Dead-mover (state 2/9) radar drop: the wreck-blip removal. The binary's uninteresting-notification presumably did the same [T4 — unverified whether a pod wreck kept its blip].
  • Per-frame O(all-entities) rebuild vs the authentic event-driven feed — acceptable at shipped populations; restoring the notify feed retires it.

Stale notes corrected by this audit

  • mech.cpp "SetTargetRange is stubbed" — FALSE since the zoom work (btstubs.cpp body + the mapper slew); comment swept 2026-08-14.
  • btl4rdr.cpp header "Make has no exported caller" — stale; @004c1b4c IS in the 2026-08-06 re-export.
  • docs/GAUGE_COMPOSITE.md row 24 "cross-blip stand-in" — stale; pips are the live path since dd27238.

Open follow-ups

  • ERA QUESTION (for the group): what did the ARENA EDGE look like on the pod's scope — just the wall outlines, or anything more? (Guards against inventing a boundary ring; the code says wall outlines only.)
  • #105/#121: RadarPercent is pinned 1.0 until sensor damage lands — the capability-shrink lane is authored and waiting.
  • The 45°-wedge vs the manual's "60° field of vision" — flag to testers comparing against memory; the 4.10 code hardcodes π/8·2.
  • Overlay-plane compositing into the dev sec cell (SECTOR/SCALE readouts) — existing polish item, unchanged.