feat(ui): introduce ImplantApp pattern — base class, registry, atlas + economics refactor (#844, #824, #836)
Establishes the ImplantApp faux-mobile-OS architecture (D-191):
Foundation:
- ImplantAppManifest (Resource): @export vars for app_path, scene_path, default_key, default_mode, preserves_state
- ImplantNavStack (Node): push/pop/replace/reset_to_default, synchronous screen_changed signal
- ImplantApp (Control base class): absorbs HudGroups boilerplate; on_install/on_open/on_close/on_insert_deactivated lifecycle hooks
- ImplantRegistry (autoload): lazy-scans res://ui/implant/apps/*/app.tres; avoids autoload parse-order trap
Atlas app (replaces atlas_panel + atlas_reach_map + atlas_system_map + atlas_planet_map + root viewer files):
- apps/atlas/app.tres — manifest (implant/map, FULLSCREEN, key=M)
- apps/atlas/atlas_app.gd — coordinator; 4-screen nav via ImplantNavStack
- apps/atlas/screens/{reach,system,planet,regional}_screen.gd — enter/leave interface
- apps/atlas/{atlas_viewer,atlas_marker_overlay,atlas_overlay_bar}.gd — moved from root
Economics app (replaces economics_panel):
- apps/economics/app.tres — manifest (implant/economics, INSERT, key=N)
- apps/economics/economics_app.gd — thin shell delegating to OverviewScreen
- apps/economics/screens/overview_screen.gd — full panel logic, enter/leave interface
Wiring:
- project.godot: add ImplantRegistry autoload after HudGroups
- main.gd: registry-driven key toggle loop; rename atlas_panel→atlas_app, economics_panel→economics_app
- hud.tscn: swap to new scene paths; remove legacy StarMap node
- snapshot_consumers.gd: on_insert_deactivated() uniformly; rename vars
- hud_groups.gd: remove stale starchart compat comment
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -12,7 +12,6 @@ extends Node
|
||||
## Groups use hierarchical paths:
|
||||
## "gameplay" — HUD status, minimap, prompts, stance
|
||||
## "implant/map" — unified atlas (reach map → system → planet → regional, D-191)
|
||||
## "implant/map/starchart" — legacy hop-ring view (registered by StarMapRenderer, kept for compat)
|
||||
## "implant/wiki/gttr" — Drifter's Guide reader
|
||||
## "implant/journal" — knowledge journal
|
||||
## "implant/economics" — economics monitor (D-181, #824)
|
||||
|
||||
+26
-30
@@ -32,9 +32,8 @@ var _dialogue: DialogueCoordinator # #775: dialogue consumers + signal handlers
|
||||
@onready var loading_screen = $ModalLayer/LoadingScreen # #257: blocking overlay during load
|
||||
@onready var debug_console = $ModalLayer/DebugConsole # #581: tilde debug console
|
||||
@onready var news_ticker = $UILayer/NewsTicker # #592: scrolling headline bar (D-049 z-7)
|
||||
@onready var star_map = $InsertOverlay/HUD/StarMap # #674: star map insert module (hop-ring view)
|
||||
@onready var economics_panel = $InsertOverlay/HUD/EconomicsPanel # #824: economics monitor (D-170)
|
||||
@onready var atlas_panel = $InsertOverlay/HUD/AtlasPanel # #834: atlas implant — system → orbital → body (D-191)
|
||||
@onready var economics_app = $InsertOverlay/HUD/EconomicsApp # #824: economics monitor (D-170)
|
||||
@onready var atlas_app = $InsertOverlay/HUD/AtlasApp # #844: atlas implant — reach → system → planet → regional (D-191)
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
@@ -92,9 +91,8 @@ func _ready() -> void:
|
||||
"interaction_list": interaction_list,
|
||||
"interaction_prompt": interaction_prompt,
|
||||
"minimap": minimap,
|
||||
"star_map": star_map,
|
||||
"economics_panel": economics_panel,
|
||||
"atlas_panel": atlas_panel,
|
||||
"economics_app": economics_app,
|
||||
"atlas_app": atlas_app,
|
||||
},
|
||||
_screen_flash
|
||||
)
|
||||
@@ -171,38 +169,36 @@ func _ready() -> void:
|
||||
# #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)
|
||||
if atlas_app and economics_app:
|
||||
atlas_app.economics_link_requested.connect(_on_atlas_economics_link)
|
||||
|
||||
|
||||
func _unhandled_key_input(event: InputEvent) -> void:
|
||||
if event.is_pressed() and not event.is_echo():
|
||||
if event is InputEventKey and event.keycode == KEY_M:
|
||||
# #844: M — unified atlas (implant/map). Reach map → system → planet → regional.
|
||||
if atlas_panel:
|
||||
atlas_panel.toggle_visible()
|
||||
elif event is InputEventKey and event.keycode == KEY_N:
|
||||
# #824: N — toggle Economics Monitor implant panel (E is bound to interact).
|
||||
# Gated on the atlas being inactive so the viewer's N → city-economics
|
||||
# cross-link isn't shadowed by this global toggle (review #6).
|
||||
if economics_panel and not HudGroups.is_app_active("implant/map"):
|
||||
economics_panel.toggle_visible()
|
||||
elif event is InputEventKey and event.keycode == KEY_BRACKETLEFT:
|
||||
# #824: [ — cycle economics panel system selector backward
|
||||
if economics_panel and HudGroups.is_app_active("implant/economics"):
|
||||
economics_panel.navigate(-1)
|
||||
elif event is InputEventKey and event.keycode == KEY_BRACKETRIGHT:
|
||||
# #824: ] — cycle economics panel system selector forward
|
||||
if economics_panel and HudGroups.is_app_active("implant/economics"):
|
||||
economics_panel.navigate(1)
|
||||
if not (event is InputEventKey) or not event.is_pressed() or event.is_echo():
|
||||
return
|
||||
var key_event := event as InputEventKey
|
||||
# Registry-driven toggle: each manifest declares its own default_key.
|
||||
for manifest: Variant in ImplantRegistry.get_manifests():
|
||||
if manifest.get("default_key") == key_event.keycode:
|
||||
HudGroups.toggle_app(
|
||||
manifest.get("app_path"), manifest.get("default_mode", HudGroups.Mode.FULLSCREEN)
|
||||
)
|
||||
return
|
||||
# [ / ] — cycle economics system selector (app-specific, not generic enough for manifest).
|
||||
if key_event.keycode == KEY_BRACKETLEFT:
|
||||
if economics_app and HudGroups.is_app_active("implant/economics"):
|
||||
economics_app.navigate(-1)
|
||||
elif key_event.keycode == KEY_BRACKETRIGHT:
|
||||
if economics_app and HudGroups.is_app_active("implant/economics"):
|
||||
economics_app.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:
|
||||
# the panel open. AtlasApp closes itself before emitting this signal.
|
||||
if economics_app == null:
|
||||
return
|
||||
economics_panel.select_system(system_id)
|
||||
economics_app.select_system(system_id)
|
||||
HudGroups.open_app("implant/economics", HudGroups.Mode.INSERT)
|
||||
|
||||
|
||||
|
||||
@@ -16,9 +16,8 @@ var cursor_renderer: Node = null
|
||||
var interaction_list: Node = null
|
||||
var interaction_prompt: Node = null
|
||||
var minimap: Node = null
|
||||
var star_map: Node = null
|
||||
var economics_panel: Node = null # #824: economics monitor (D-181)
|
||||
var atlas_panel: Node = null # #834: atlas implant panel (D-191)
|
||||
var economics_app: Node = null # #824: economics monitor (D-181)
|
||||
var atlas_app: Node = null # #844: atlas implant app (D-191)
|
||||
|
||||
var _screen_flash_fn: Callable # Callable(color: Color, duration: float)
|
||||
|
||||
@@ -38,9 +37,8 @@ func init(refs: Dictionary, screen_flash: Callable) -> SnapshotConsumers:
|
||||
interaction_list = refs.get("interaction_list")
|
||||
interaction_prompt = refs.get("interaction_prompt")
|
||||
minimap = refs.get("minimap")
|
||||
star_map = refs.get("star_map")
|
||||
economics_panel = refs.get("economics_panel")
|
||||
atlas_panel = refs.get("atlas_panel")
|
||||
economics_app = refs.get("economics_app")
|
||||
atlas_app = refs.get("atlas_app")
|
||||
_screen_flash_fn = screen_flash
|
||||
return self
|
||||
|
||||
@@ -56,12 +54,11 @@ func propagate_insert_state() -> void:
|
||||
interaction_prompt.set_insert_active(insert_state)
|
||||
if minimap:
|
||||
minimap.set_insert_active(insert_state)
|
||||
if star_map:
|
||||
star_map.set_insert_active(insert_state)
|
||||
if economics_panel:
|
||||
economics_panel.set_insert_active(insert_state)
|
||||
if atlas_panel:
|
||||
atlas_panel.set_insert_active(insert_state)
|
||||
if not insert_state:
|
||||
if economics_app and economics_app.has_method("on_insert_deactivated"):
|
||||
economics_app.on_insert_deactivated()
|
||||
if atlas_app and atlas_app.has_method("on_insert_deactivated"):
|
||||
atlas_app.on_insert_deactivated()
|
||||
|
||||
|
||||
# D-057: Update interaction list from game state.
|
||||
@@ -181,12 +178,12 @@ func consume_debug_response() -> void:
|
||||
GameState.debug_response = null
|
||||
|
||||
|
||||
# #824: Forward economy_snapshot from server to the economics panel (D-181).
|
||||
# #824: Forward economy_snapshot from server to the economics app (D-181).
|
||||
func consume_economy_snapshot() -> void:
|
||||
if GameState.economy_snapshot == null or not economics_panel:
|
||||
if GameState.economy_snapshot == null or not economics_app:
|
||||
return
|
||||
if economics_panel.has_method("receive_economy_data"):
|
||||
economics_panel.receive_economy_data(GameState.economy_snapshot)
|
||||
if economics_app.has_method("receive_economy_data"):
|
||||
economics_app.receive_economy_data(GameState.economy_snapshot)
|
||||
GameState.economy_snapshot = null
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user