92 lines
2.4 KiB
GDScript
92 lines
2.4 KiB
GDScript
extends Node3D
|
|
|
|
signal matador_killed
|
|
signal all_defeated
|
|
|
|
const MATADOR := preload("res://Matador.tscn")
|
|
|
|
var _alive: int = 0
|
|
var _wave: int = 0
|
|
var _resolved: bool = false
|
|
var _spawn_points: Array[Node3D] = []
|
|
|
|
|
|
func _ready() -> void:
|
|
add_to_group(&"matador_spawn")
|
|
_spawn.call_deferred()
|
|
|
|
|
|
# Each spawner node is a spawn-point marker. The first in tree order (the one the HUD
|
|
# connects its all_defeated to) runs the wave logic and uses every marker — itself and
|
|
# its siblings — as an entry point; the rest stay passive so waves aren't run four times.
|
|
func _spawn() -> void:
|
|
var markers := get_tree().get_nodes_in_group(&"matador_spawn")
|
|
if markers.is_empty() or markers[0] != self:
|
|
return
|
|
for node: Node in markers:
|
|
if node is Node3D:
|
|
_spawn_points.append(node as Node3D)
|
|
_place_bull(randf() * TAU, DP.f("arena_spawn_radius"))
|
|
_start_next_wave()
|
|
|
|
|
|
# Wave 1 sends 1 matador, wave 2 sends 2, … up to the number of placed spawn points.
|
|
# Matadors are assigned to a random subset of spawn points each wave and enter staggered.
|
|
func _start_next_wave() -> void:
|
|
_wave += 1
|
|
|
|
# 8 waves total.
|
|
if _wave > DP.f("mat_wave_size"):
|
|
return
|
|
|
|
# Wave 1 = 1 matador, Wave 2 = 2, ... Wave 8 = 8.
|
|
var count := _wave
|
|
|
|
# Shuffle the spawn points so the spawn locations are random.
|
|
var points: Array[Node3D] = _spawn_points.duplicate()
|
|
points.shuffle()
|
|
|
|
for i in range(count):
|
|
# Reuse spawn points when we have more matadors than points.
|
|
var sp: Node3D = points[i % points.size()]
|
|
|
|
var m := _spawn_at(sp.global_position)
|
|
m.call_deferred(&"enter_spawn_roll", Vector3.ZERO)
|
|
|
|
if i < count - 1:
|
|
await get_tree().create_timer(
|
|
DP.f("mat_spawn_stagger")
|
|
).timeout
|
|
|
|
|
|
func _place_bull(angle: float, arena_r: float) -> void:
|
|
var bull := get_tree().get_first_node_in_group(&"player") as Node3D
|
|
if not bull:
|
|
return
|
|
bull.global_position = Vector3(
|
|
cos(angle) * arena_r, bull.global_position.y, sin(angle) * arena_r
|
|
)
|
|
|
|
|
|
func _spawn_at(pos: Vector3) -> Node3D:
|
|
var m: Node3D = MATADOR.instantiate()
|
|
m.position = pos
|
|
get_parent().add_child(m)
|
|
m.killed.connect(_on_matador_killed)
|
|
_alive += 1
|
|
return m
|
|
|
|
|
|
func _on_matador_killed() -> void:
|
|
matador_killed.emit()
|
|
_alive -= 1
|
|
if _alive > 0 or _resolved:
|
|
return
|
|
if _wave >= DP.f("mat_wave_size"):
|
|
DP.set_value("gate_unlocked_bear", true)
|
|
_resolved = true
|
|
all_defeated.emit()
|
|
else:
|
|
await get_tree().create_timer(DP.f("mat_wave_pause")).timeout
|
|
_start_next_wave()
|