game.gd 6.7 KB

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