## GameLoop.gd ## Orchestrates the phase state machine and wires up the lane + UI for solo play. extends Node const PLAYER_ID = 0 const STARTING_MINERALS = 200 const STARTING_WORKERS = 3 @onready var race_select: Control = $RaceSelect @onready var hud: CanvasLayer = $HUD @onready var build_panel: PanelContainer = $BuildPanel @onready var lane: Node2D = $Lane @onready var security_system: Node2D = $SecuritySystem @onready var game_over: Control = $GameOver func _ready() -> void: hud.hide() build_panel.hide() race_select.race_selected.connect(_on_race_selected) EventBus.phase_changed.connect(_on_phase_changed) # Wire slot clicks to build panel EventBus.connect("slot_clicked_in_lane", _on_slot_clicked) EventBus.connect("next_wave_requested", _on_next_wave_requested) func _on_race_selected(race: String) -> void: GameState.register_player(PLAYER_ID, race, lane) Economy.init_player(PLAYER_ID, STARTING_MINERALS, STARTING_WORKERS) race_select.hide() hud.show() GameState.set_phase(GameState.Phase.BUILD) func _on_phase_changed(new_phase: GameState.Phase) -> void: pass # HUD and other nodes react via their own connections func _on_slot_clicked(player_id: int, slot: Node) -> void: if GameState.current_phase != GameState.Phase.BUILD: return if slot.is_empty(): build_panel.open_for_slot(slot, player_id) elif slot.get_tower().can_upgrade(): _try_upgrade(slot, player_id) func _try_upgrade(slot: Node, player_id: int) -> void: var tower = slot.get_tower() var upgrade_id = tower.get_upgrade_id() var race = GameState.get_player_race(player_id) var defs = DataLoader.load_towers(race) for d in defs: if d.get("id") == upgrade_id: var cost = d.get("cost_minerals", 0) + d.get("cost_gas", 0) if Economy.spend_minerals(player_id, d.get("cost_minerals", 0)) and \ Economy.spend_gas(player_id, d.get("cost_gas", 0)): slot.upgrade_tower(d) return func _on_next_wave_requested() -> void: if GameState.current_phase != GameState.Phase.BUILD: return var next = GameState.wave_number + 1 if next > 31: return WaveManager.start_wave(next, lane)