extends Node const NORMAL_GATES: int = 3 const TIMER_SECONDS: float = 600.0 @onready var spawn_system: Node = get_node("../SpawnSystem") var timer_remaining: float = TIMER_SECONDS var red_gate: Node = null var red_portal_done: bool = false var active: bool = false func _ready() -> void: EventBus.gate_destroyed.connect(_on_gate_destroyed) EventBus.boss_defeated.connect(_on_boss_defeated) EventBus.invasion_ended.connect(_on_invasion_ended) func start_wave(n: int) -> void: if not (multiplayer.is_server() or multiplayer.multiplayer_peer == null): return GameState.current_wave = n red_portal_done = false red_gate = null timer_remaining = TIMER_SECONDS active = true EventBus.wave_started.emit(n) _spawn_initial_gates() func _spawn_initial_gates() -> void: for i in range(NORMAL_GATES): var pos := _random_outer_position(20.0, 40.0) spawn_system.spawn_gate_at(pos, false) red_gate = spawn_system.spawn_gate_at(_random_outer_position(30.0, 45.0), true) func _random_outer_position(min_d: float, max_d: float) -> Vector3: var angle: float = randf() * TAU var d: float = randf_range(min_d, max_d) return Vector3(cos(angle) * d, 0.5, sin(angle) * d) func _physics_process(delta: float) -> void: if not active: return if not (multiplayer.is_server() or multiplayer.multiplayer_peer == null): return timer_remaining = max(0.0, timer_remaining - delta) EventBus.wave_timer_tick.emit(timer_remaining) if timer_remaining <= 0.0 and not red_portal_done: active = false EventBus.invasion_started.emit() var inv: Node = get_node_or_null("../InvasionSystem") if inv and inv.has_method("start"): inv.start(GameState.current_wave) func _on_gate_destroyed(gate: Node) -> void: if not (multiplayer.is_server() or multiplayer.multiplayer_peer == null): return if not gate.is_in_group("red_gate"): var pos := _random_outer_position(20.0, 40.0) spawn_system.spawn_gate_at(pos, false) func _on_boss_defeated(_boss: Node) -> void: if not (multiplayer.is_server() or multiplayer.multiplayer_peer == null): return if GameState.dungeon_red and not red_portal_done: red_portal_done = true active = false EventBus.wave_ended.emit(GameState.current_wave, true) var t := get_tree().create_timer(2.0) t.timeout.connect(func(): start_wave(GameState.current_wave + 1)) func _on_invasion_ended(success: bool) -> void: if not (multiplayer.is_server() or multiplayer.multiplayer_peer == null): return if success: EventBus.wave_ended.emit(GameState.current_wave, true) var t := get_tree().create_timer(2.0) t.timeout.connect(func(): start_wave(GameState.current_wave + 1))