xanarch-td/scripts/autoload/WaveManager.gd
2026-06-03 21:53:16 -04:00

68 lines
2.2 KiB
GDScript

## WaveManager.gd
## Loads wave definitions and orchestrates creep spawning along the lane path.
extends Node
const WAVE_DATA_PATH := "res://data/waves.json"
const TOTAL_WAVES := 31
var _waves: Array = []
var _active_creeps: int = 0
func _ready() -> void:
_load_waves()
EventBus.creep_died.connect(_on_creep_removed)
EventBus.creep_reached_exit.connect(_on_creep_removed)
func _load_waves() -> void:
_waves = DataLoader.load_waves()
if _waves.is_empty():
push_error("WaveManager: waves.json failed to load or is empty")
func start_wave(wave_number: int, lane: Node) -> void:
if wave_number < 1 or wave_number > _waves.size():
push_error("WaveManager: invalid wave number %d" % wave_number)
return
var wave_data: Dictionary = _waves[wave_number - 1]
GameState.advance_wave()
GameState.set_phase(GameState.Phase.COMBAT)
EventBus.wave_started.emit(wave_number)
var count: int = wave_data.get("creep_count", 1)
_active_creeps += count
var path_pts: PackedVector2Array = lane.get_path_points() if lane.has_method("get_path_points") else PackedVector2Array()
# Spawn creeps spaced 0.5 s apart
for i in range(count):
await get_tree().create_timer(0.5 * i).timeout
_spawn_creep(wave_data, lane, path_pts)
func _spawn_creep(wave_data: Dictionary, lane: Node, path_pts: PackedVector2Array) -> void:
var creep_scene := load("res://scenes/gameplay/Creep.tscn") as PackedScene
if not creep_scene:
push_error("WaveManager: Creep.tscn not found")
_active_creeps -= 1
return
var creep: Node = creep_scene.instantiate()
lane.add_child(creep)
creep.setup(wave_data)
if path_pts.size() > 0:
# Convert lane-local path to global coords for the creep
var global_pts := PackedVector2Array()
for pt in path_pts:
global_pts.append(lane.to_global(pt))
creep.assign_path(global_pts)
func _on_creep_removed(_creep: Node, _value) -> void:
_active_creeps = max(0, _active_creeps - 1)
if _active_creeps == 0:
_wave_complete()
func _wave_complete() -> void:
var wn := GameState.wave_number
EventBus.wave_completed.emit(wn)
Economy.process_income_phase()
if wn < TOTAL_WAVES:
GameState.set_phase(GameState.Phase.BUILD)
# If wave 31, GameOver.gd listens to wave_completed and handles victory