feat(ui): atlas heightmap viewer — pan/zoom, marker overlay, city data panel (#835)

Adds Level.HEIGHTMAP_VIEWER to AtlasPanel. The viewer loads a body's
terrain_reference heightmap PNG, pairs it with markers.json (roads, rail, POIs,
cities, rivers/oceans/mountains), and renders markers in texture-space via an
AtlasMarkerOverlay Node2D child of a transformed canvas — pan = offset,
zoom = scale.

Pan/zoom is cursor-centred (wheel zooms under the mouse, drag pans), with a
fit-to-view reset on R. Empty markers.json state renders a bare heightmap;
missing terrain_reference shows a themed "terrain data pending (#839)" notice
instead of crashing.

City data sidebar rebuilds from the selected city: name, pop tier, function,
currency zone, Commission presence, shadow zone, gate distance. Pressing N on
a selected city emits economics_link_requested(system_id) — main.gd bridges
this to EconomicsPanel.select_system() + HudGroups.open_app("implant/economics")
as an insert overlay, satisfying the D-191 Phase 2/3 cross-panel integration.

The overlay renders all nine D-191 overlay layers off of per-overlay visibility
flags in AtlasViewer. Overlay toggling for the regional view (#836) plugs into
set_overlay_visible(); the five always-on layers (terrain, infrastructure,
named features, gate markers, political zones) draw by default, the four
toggleable layers draw from placeholder data, and the two locked layers
(stockpile_weeks, production_vs_baseline) remain off until unlocked.

Per D-191 criteria 1, 4, 5.
This commit is contained in:
2026-04-15 08:22:01 +02:00
parent 760953aeba
commit c33ac8921f
4 changed files with 870 additions and 8 deletions
+15
View File
@@ -168,6 +168,12 @@ func _ready() -> void:
debug_console.pause_requested.connect(_dialogue.on_dialogue_pause_requested)
debug_console.unpause_requested.connect(_dialogue.on_dialogue_unpause_requested)
# #835 D-191: Atlas → Economics Monitor cross-link. The atlas city data panel
# emits economics_link_requested(system_id); we pre-filter the monitor and
# open it as an insert panel on top.
if atlas_panel and economics_panel:
atlas_panel.economics_link_requested.connect(_on_atlas_economics_link)
func _unhandled_key_input(event: InputEvent) -> void:
if event.is_pressed() and not event.is_echo():
@@ -192,6 +198,15 @@ func _unhandled_key_input(event: InputEvent) -> void:
economics_panel.navigate(1)
func _on_atlas_economics_link(system_id: String) -> void:
# #835 D-191: Pre-filter the economics monitor to the city's system and pop
# the panel open. AtlasPanel closes itself before emitting this signal.
if economics_panel == null:
return
economics_panel.select_system(system_id)
HudGroups.open_app("implant/economics", HudGroups.Mode.INSERT)
func _process(delta: float) -> void:
# Main game loop: poll snapshot, apply state, flush input
var snapshot: Variant = SimBridge.poll_snapshot()