extends Node2D class_name Game @onready var health_bar: HealthBar = $HealthBar @onready var overlay: CanvasLayer = $Overlay @onready var transition: Transition = $Overlay/Transition @onready var player_spawn: PlayerSpawnZone = $PlayerSpawnZone @onready var spawn_timer: Timer = $Timer @onready var ui_root: Control = $UI/Root @onready var wave_label: Label = $UI/Root/WaveLabel @onready var phase_label: Label = $UI/Root/PhaseLabel @onready var next_phase_button: Button = $UI/Root/NextPhaseButton @onready var combat_start_sound: AudioStreamPlayer = $Sounds/CombatStartSound @onready var main_menu: PackedScene = load("res://screens/main_menu.tscn") @onready var bot_scene: PackedScene = load("res://assets/scenes/bot.tscn") @onready var game_over_scene: PackedScene = load("res://assets/scenes/game_over.tscn") @onready var victory_scene: PackedScene = load("res://assets/scenes/victory.tscn") @onready var intro_scene: PackedScene = load("res://assets/scenes/intro.tscn") @onready var left_enemy_label: Label = $UI/Root/LeftEnemyLabel @onready var right_enemy_label: Label = $UI/Root/RightEnemyLabel @onready var top_enemy_label: Label = $UI/Root/TopEnemyLabel @onready var spawn_points: Array[Marker2D] = [ $EnemySpawns/EnemySpawn_Left, $EnemySpawns/EnemySpawn_Right, $EnemySpawns/EnemySpawn_Top, ] @onready var enemy_labels: Array[Label] = [ $UI/Root/LeftEnemyLabel, $UI/Root/RightEnemyLabel, $UI/Root/TopEnemyLabel, ] enum Phase { PHASE_SETUP, PHASE_COMBAT, PHASE_LOOT, } enum Loot { LOOT_SURVIVOR, LOOT_HEAL, LOOT_LOWER_COOLDOWN, } const RELOAD_TIME: float = 4.0 static var reload_time: float = RELOAD_TIME # seconds static var max_ammo: int = 1 # shots static var base_accuracy: float = 0.33 # percent var phase: Phase = Phase.PHASE_SETUP: set(new_value): phase = new_value match new_value: Phase.PHASE_SETUP: phase_label.text = "PHASE: SETUP" Phase.PHASE_COMBAT: phase_label.text = "PHASE: COMBAT" Phase.PHASE_LOOT: phase_label.text = "PHASE: LOOT" var waves_completed: int = 0: set(new_value): waves_completed = new_value wave_label.text = "WAVE: %d" % (new_value + 1) func update_enemy_labels() -> void: for n in 3: var enemies = spawn_points[n].get_child_count() enemy_labels[n].text = str(enemies) func set_enemy_label_visible(value: bool) -> void: for label in enemy_labels: label.visible = value func _ready() -> void: Game.reload_time = RELOAD_TIME # seconds Game.max_ammo = 1 # shots Game.base_accuracy = 0.33 # percent waves_completed = 0 phase = Phase.PHASE_SETUP overlay.visible = true start_setup() player_spawn.add_survivor() var intro: Intro = null if Config.show_tutorial: intro = intro_scene.instantiate() add_child(intro) ui_root.visible = false transition.slide_out() await transition.game_fully_visible if intro != null: intro.start() await intro.finished await transition.transition("WAVE 1", func (): ui_root.visible = true intro.queue_free() ) func _process(_delta: float) -> void: if Input.is_action_pressed("ui_cancel"): go_to_main_menu() if phase == Phase.PHASE_COMBAT: if get_foes().is_empty() and health_bar.health != 0: end_combat() func go_to_main_menu() -> void: var tree = get_tree() transition.text = "" tree.paused = true transition.slide_in() await transition.game_fully_hidden tree.change_scene_to_packed(main_menu) tree.paused = false func spawn_bot(spawn: Marker2D, index: int) -> void: var bot: Bot = bot_scene.instantiate() bot.name = "Bot #%d" % (index + 1) bot.speed += waves_completed bot.visible = false spawn.add_child(bot) bot.position = Vector2.ZERO func get_foes() -> Array[Area2D]: var foes: Array[Area2D] = [] foes.assign(get_tree().get_nodes_in_group("foe")) return foes func get_survivors() -> Array[Area2D]: var survivors: Array[Area2D] = [] survivors.assign(get_tree().get_nodes_in_group("survivor")) return survivors func get_waiting_foes() -> Array[Area2D]: return get_foes().filter(func (foe): return not foe.visible) func get_active_foes() -> Array[Area2D]: return get_foes().filter(func (foe): return foe.visible) func activate_foe() -> void: var foes = get_waiting_foes() if not foes.is_empty(): foes.pick_random().visible = true func reset_survivors() -> void: var survivors = get_survivors() #for survivor in survivors: # survivor.reparent(self) for survivor in survivors: #player_spawn.drop(survivor) #survivor.position = Vector2.ZERO #survivor.rotation = 0.0 survivor.ammo = Game.max_ammo func _on_timer_timeout() -> void: activate_foe() func base_hit() -> void: health_bar.health -= 1 if health_bar.health == 0: await game_over() func game_over() -> void: spawn_timer.stop() var foes = get_tree().get_nodes_in_group("foe") for foe in foes: foe.queue_free() var gos: GameOver = game_over_scene.instantiate() gos.message = "YOU DIED AFTER\nCOMPLETING %d WAVES!" % waves_completed ui_root.add_child(gos) await gos.closed await go_to_main_menu() func _on_base_area_entered(area: Area2D) -> void: if area.is_in_group("foe") || area.is_in_group("foe_weapons"): base_hit() func start_setup() -> void: for n in (waves_completed + 1): var spawner = spawn_points.pick_random() spawn_bot(spawner, n) update_enemy_labels() set_enemy_label_visible(true) func start_combat() -> void: set_enemy_label_visible(false) GlobalInput.dragging_disabled = true spawn_timer.wait_time = lerpf(3.5, 0.5, minf(float(waves_completed)/20.0, 1.0)) spawn_timer.start() combat_start_sound.play() activate_foe() const LOOT_SURVIVOR: String = "+1 SURVIVOR" const LOOT_HEALTH: String = "+3 HEALTH" const LOOT_AMMO: String = "BIGGER MAGAZINES" const LOOT_RELOAD_TIME: String = "FASTER RELOADING" const LOOT_ACCURACY: String = "HIGHER ACCURACY" const LOOTS: Array[String] = [LOOT_SURVIVOR, LOOT_HEALTH, LOOT_AMMO, LOOT_RELOAD_TIME, LOOT_ACCURACY] func end_combat() -> void: phase = Phase.PHASE_LOOT spawn_timer.stop() await get_tree().create_timer(1.5).timeout var vs: Victory = victory_scene.instantiate() ui_root.add_child(vs) var loots: Array[String] = [] loots.assign(LOOTS) if get_survivors().size() >= 6: # this is, so the player has a reason to move survivors even later loots.erase(LOOT_SURVIVOR) loots.shuffle() vs.set_loot_options(loots[0], loots[1], loots[2]) await vs.loot_selected var loot: String = loots[vs.selection] print("selected loot: " + str(loot)) var next_wave = waves_completed + 2 await transition.transition("WAVE %d" % next_wave, func (): self.waves_completed += 1 self.phase = Phase.PHASE_SETUP self.next_phase_button.disabled = false match loot: LOOT_SURVIVOR: self.player_spawn.add_survivor() LOOT_HEALTH: self.health_bar.health += 3 LOOT_RELOAD_TIME: Game.reload_time *= 0.9 LOOT_AMMO: Game.max_ammo += 1 LOOT_ACCURACY: Game.base_accuracy += 0.1 self.reset_survivors() self.start_setup() ) GlobalInput.dragging_disabled = false func _on_next_phase_button_pressed() -> void: match phase: Phase.PHASE_SETUP: phase = Phase.PHASE_COMBAT next_phase_button.disabled = true start_combat() Phase.PHASE_COMBAT: pass # this should not happen Phase.PHASE_LOOT: pass # this should not happen