extends Node ## HUD visibility group manager (D-170). ## ## Nodes register into hierarchical groups. Groups control show/hide as a unit. ## ## Hierarchy: ## "gameplay" — stance, minimap, health, prompts, cursor, inventory ## "implant/map" — star map ## "implant/wiki" — GTTR reader ## "implant/journal" — knowledge journal ## "implant/travel" — travel planner ## "implant/station" — station profile ## "implant/cargo" — cargo manifest ## "modal" — settings, bug report, loading (independent layer) ## "debug" — debug overlay, gauntlet HUD (independent layer) ## ## Rules: ## - "gameplay" and any "implant/*" are mutually exclusive. ## Opening an implant app hides gameplay. ## - "implant/*" apps are mutually exclusive with each other. ## Opening implant/map hides implant/wiki. ## - "modal" and "debug" are independent — overlay on anything. ## ## Usage: ## HudGroups.register(self, "gameplay") ## HudGroups.register(self, "implant/map") ## HudGroups.open_app("implant/map") # hides gameplay + other implant apps ## HudGroups.close_app() # returns to gameplay ## HudGroups.toggle_app("implant/map") # open if closed, close if open var _groups: Dictionary = {} # group_name -> Array[Control] var _active_app: String = "" # currently open implant/* app ("" = none) func register(node: Control, group: String) -> void: if not _groups.has(group): _groups[group] = [] if node not in _groups[group]: _groups[group].append(node) # Apply current visibility if group == "gameplay": node.visible = _active_app.is_empty() elif group.begins_with("implant/"): node.visible = (group == _active_app) func unregister(node: Control, group: String) -> void: if _groups.has(group): _groups[group].erase(node) ## Open an implant app. Hides gameplay and any other implant app. func open_app(app: String) -> void: if not app.begins_with("implant/"): push_warning("HudGroups.open_app: expected implant/* group, got: " + app) return # Hide previous app if different if not _active_app.is_empty() and _active_app != app: _set_group_visible(_active_app, false) _active_app = app _set_group_visible("gameplay", false) _set_group_visible(app, true) ## Close the current implant app. Returns to gameplay. func close_app() -> void: if not _active_app.is_empty(): _set_group_visible(_active_app, false) _active_app = "" _set_group_visible("gameplay", true) ## Toggle an implant app. If it's open, close it. If another is open, switch. func toggle_app(app: String) -> void: if _active_app == app: close_app() else: open_app(app) ## Check if a specific app is currently open. func is_app_active(app: String) -> bool: return _active_app == app ## Check if any implant app is open. func is_implant_active() -> bool: return not _active_app.is_empty() ## Get the currently active app name, or "" if none. func get_active_app() -> String: return _active_app ## Show/hide an independent group (modal, debug). Does not affect gameplay/implant. func show_group(group: String, vis: bool = true) -> void: _set_group_visible(group, vis) func _set_group_visible(group: String, vis: bool) -> void: if not _groups.has(group): return for node: Control in _groups[group]: if is_instance_valid(node): node.visible = vis