game.gd 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. extends Node2D
  2. class_name Game
  3. @onready var health_bar: HealthBar = $HealthBar
  4. @onready var overlay: CanvasLayer = $Overlay
  5. @onready var transition: Transition = $Overlay/Transition
  6. @onready var player_spawn: PlayerSpawnZone = $PlayerSpawnZone
  7. @onready var spawn_timer: Timer = $Timer
  8. @onready var ui_root: Control = $UI/Root
  9. @onready var wave_label: Label = $UI/Root/WaveLabel
  10. @onready var phase_label: Label = $UI/Root/PhaseLabel
  11. @onready var next_phase_button: Button = $UI/Root/NextPhaseButton
  12. @onready var combat_start_sound: AudioStreamPlayer = $Sounds/CombatStartSound
  13. @onready var main_menu: PackedScene = load("res://screens/main_menu.tscn")
  14. @onready var bot_scene: PackedScene = load("res://assets/scenes/bot.tscn")
  15. @onready var game_over_scene: PackedScene = load("res://assets/scenes/game_over.tscn")
  16. @onready var victory_scene: PackedScene = load("res://assets/scenes/victory.tscn")
  17. @onready var intro_scene: PackedScene = load("res://assets/scenes/intro.tscn")
  18. @onready var left_enemy_label: Label = $UI/Root/LeftEnemyLabel
  19. @onready var right_enemy_label: Label = $UI/Root/RightEnemyLabel
  20. @onready var top_enemy_label: Label = $UI/Root/TopEnemyLabel
  21. @onready var spawn_points: Array[Marker2D] = [
  22. $EnemySpawns/EnemySpawn_Left,
  23. $EnemySpawns/EnemySpawn_Right,
  24. $EnemySpawns/EnemySpawn_Top,
  25. ]
  26. @onready var enemy_labels: Array[Label] = [
  27. $UI/Root/LeftEnemyLabel,
  28. $UI/Root/RightEnemyLabel,
  29. $UI/Root/TopEnemyLabel,
  30. ]
  31. enum Phase {
  32. PHASE_SETUP,
  33. PHASE_COMBAT,
  34. PHASE_LOOT,
  35. }
  36. enum Loot {
  37. LOOT_SURVIVOR,
  38. LOOT_HEAL,
  39. LOOT_LOWER_COOLDOWN,
  40. }
  41. const RELOAD_TIME: float = 4.0
  42. static var reload_time: float = RELOAD_TIME # seconds
  43. static var max_ammo: int = 1 # shots
  44. static var base_accuracy: float = 0.33 # percent
  45. var phase: Phase = Phase.PHASE_SETUP:
  46. set(new_value):
  47. phase = new_value
  48. match new_value:
  49. Phase.PHASE_SETUP:
  50. phase_label.text = "PHASE: SETUP"
  51. Phase.PHASE_COMBAT:
  52. phase_label.text = "PHASE: COMBAT"
  53. Phase.PHASE_LOOT:
  54. phase_label.text = "PHASE: LOOT"
  55. var waves_completed: int = 0:
  56. set(new_value):
  57. waves_completed = new_value
  58. wave_label.text = "WAVE: %d" % (new_value + 1)
  59. func update_enemy_labels() -> void:
  60. for n in 3:
  61. var enemies = spawn_points[n].get_child_count()
  62. enemy_labels[n].text = str(enemies)
  63. func set_enemy_label_visible(value: bool) -> void:
  64. for label in enemy_labels:
  65. label.visible = value
  66. func _ready() -> void:
  67. Game.reload_time = RELOAD_TIME # seconds
  68. Game.max_ammo = 1 # shots
  69. Game.base_accuracy = 0.33 # percent
  70. waves_completed = 0
  71. phase = Phase.PHASE_SETUP
  72. overlay.visible = true
  73. start_setup()
  74. player_spawn.add_survivor()
  75. var intro: Intro = null
  76. if Config.show_tutorial:
  77. intro = intro_scene.instantiate()
  78. add_child(intro)
  79. ui_root.visible = false
  80. transition.slide_out()
  81. await transition.game_fully_visible
  82. if intro != null:
  83. intro.start()
  84. await intro.finished
  85. await transition.transition("WAVE 1", func ():
  86. ui_root.visible = true
  87. intro.queue_free()
  88. )
  89. func _process(_delta: float) -> void:
  90. var intro_visible: bool = get_tree().get_first_node_in_group("intro") != null
  91. if Input.is_action_pressed("ui_cancel") && not intro_visible:
  92. go_to_main_menu()
  93. if phase == Phase.PHASE_COMBAT:
  94. if get_foes().is_empty() and health_bar.health != 0:
  95. end_combat()
  96. func go_to_main_menu() -> void:
  97. var tree = get_tree()
  98. transition.text = ""
  99. tree.paused = true
  100. transition.slide_in()
  101. await transition.game_fully_hidden
  102. tree.change_scene_to_packed(main_menu)
  103. tree.paused = false
  104. func spawn_bot(spawn: Marker2D, index: int) -> void:
  105. var bot: Bot = bot_scene.instantiate()
  106. bot.name = "Bot #%d" % (index + 1)
  107. bot.speed += waves_completed
  108. bot.visible = false
  109. spawn.add_child(bot)
  110. bot.position = Vector2.ZERO
  111. func get_foes() -> Array[Area2D]:
  112. var foes: Array[Area2D] = []
  113. foes.assign(get_tree().get_nodes_in_group("foe"))
  114. return foes
  115. func get_survivors() -> Array[Area2D]:
  116. var survivors: Array[Area2D] = []
  117. survivors.assign(get_tree().get_nodes_in_group("survivor"))
  118. return survivors
  119. func get_waiting_foes() -> Array[Area2D]:
  120. return get_foes().filter(func (foe): return not foe.visible)
  121. func get_active_foes() -> Array[Area2D]:
  122. return get_foes().filter(func (foe): return foe.visible)
  123. func activate_foe() -> void:
  124. var foes = get_waiting_foes()
  125. if not foes.is_empty():
  126. foes.pick_random().visible = true
  127. func reset_survivors() -> void:
  128. var survivors = get_survivors()
  129. #for survivor in survivors:
  130. # survivor.reparent(self)
  131. for survivor in survivors:
  132. #player_spawn.drop(survivor)
  133. #survivor.position = Vector2.ZERO
  134. #survivor.rotation = 0.0
  135. survivor.ammo = Game.max_ammo
  136. func _on_timer_timeout() -> void:
  137. activate_foe()
  138. func base_hit() -> void:
  139. health_bar.health -= 1
  140. if health_bar.health == 0:
  141. await game_over()
  142. func game_over() -> void:
  143. spawn_timer.stop()
  144. var foes = get_tree().get_nodes_in_group("foe")
  145. for foe in foes:
  146. foe.queue_free()
  147. var gos: GameOver = game_over_scene.instantiate()
  148. gos.message = "YOU DIED AFTER\nCOMPLETING %d WAVES!" % waves_completed
  149. ui_root.add_child(gos)
  150. await gos.closed
  151. await go_to_main_menu()
  152. func _on_base_area_entered(area: Area2D) -> void:
  153. if area.is_in_group("foe") || area.is_in_group("foe_weapons"):
  154. base_hit()
  155. func start_setup() -> void:
  156. for n in (waves_completed + 1):
  157. var spawner = spawn_points.pick_random()
  158. spawn_bot(spawner, n)
  159. update_enemy_labels()
  160. set_enemy_label_visible(true)
  161. func start_combat() -> void:
  162. set_enemy_label_visible(false)
  163. GlobalInput.dragging_disabled = true
  164. spawn_timer.wait_time = lerpf(3.5, 0.5, minf(float(waves_completed)/20.0, 1.0))
  165. spawn_timer.start()
  166. combat_start_sound.play()
  167. activate_foe()
  168. const LOOT_SURVIVOR: String = "+1 SURVIVOR"
  169. const LOOT_HEALTH: String = "+3 HEALTH"
  170. const LOOT_AMMO: String = "BIGGER MAGAZINES"
  171. const LOOT_RELOAD_TIME: String = "FASTER RELOADING"
  172. const LOOT_ACCURACY: String = "HIGHER ACCURACY"
  173. const LOOTS: Array[String] = [LOOT_SURVIVOR, LOOT_HEALTH, LOOT_AMMO, LOOT_RELOAD_TIME, LOOT_ACCURACY]
  174. func end_combat() -> void:
  175. phase = Phase.PHASE_LOOT
  176. spawn_timer.stop()
  177. await get_tree().create_timer(1.5).timeout
  178. var vs: Victory = victory_scene.instantiate()
  179. ui_root.add_child(vs)
  180. var loots: Array[String] = []
  181. loots.assign(LOOTS)
  182. if get_survivors().size() >= 6: # this is, so the player has a reason to move survivors even later
  183. loots.erase(LOOT_SURVIVOR)
  184. loots.shuffle()
  185. vs.set_loot_options(loots[0], loots[1], loots[2])
  186. await vs.loot_selected
  187. var loot: String = loots[vs.selection]
  188. print("selected loot: " + str(loot))
  189. var next_wave = waves_completed + 2
  190. await transition.transition("WAVE %d" % next_wave, func ():
  191. self.waves_completed += 1
  192. self.phase = Phase.PHASE_SETUP
  193. self.next_phase_button.disabled = false
  194. match loot:
  195. LOOT_SURVIVOR:
  196. self.player_spawn.add_survivor()
  197. LOOT_HEALTH:
  198. self.health_bar.health += 3
  199. LOOT_RELOAD_TIME:
  200. Game.reload_time *= 0.9
  201. LOOT_AMMO:
  202. Game.max_ammo += 1
  203. LOOT_ACCURACY:
  204. Game.base_accuracy += 0.1
  205. self.reset_survivors()
  206. self.start_setup()
  207. )
  208. GlobalInput.dragging_disabled = false
  209. func _on_next_phase_button_pressed() -> void:
  210. match phase:
  211. Phase.PHASE_SETUP:
  212. phase = Phase.PHASE_COMBAT
  213. next_phase_button.disabled = true
  214. start_combat()
  215. Phase.PHASE_COMBAT:
  216. pass # this should not happen
  217. Phase.PHASE_LOOT:
  218. pass # this should not happen