extends Node const ENEMY_SCENE: PackedScene = preload("res://scenes/entities/enemy/enemy.tscn") const PORTAL_SCENE: PackedScene = preload("res://scenes/entities/portal/portal.tscn") const GATE_SCENE: PackedScene = preload("res://scenes/entities/gate/gate.tscn") func _enemy_root() -> Node3D: var n: Node = get_node_or_null("/root/World/EntityRoot/Enemies") if n == null: n = get_node_or_null("/root/Dungeon/EntityRoot/Enemies") return n func _portal_root() -> Node3D: var n: Node = get_node_or_null("/root/World/EntityRoot/Portals") if n == null: n = get_node_or_null("/root/Dungeon/EntityRoot/Portals") return n func _gate_root() -> Node3D: var n: Node = get_node_or_null("/root/World/EntityRoot/Gates") if n == null: n = get_node_or_null("/root/Dungeon/EntityRoot/Gates") return n func spawn_enemy_at(pos: Vector3, strong: bool = false, mult: float = 1.0) -> Node: if not multiplayer.is_server() and multiplayer.multiplayer_peer != null: return null var root := _enemy_root() if root == null: return null var e: CharacterBody3D = ENEMY_SCENE.instantiate() var stats := EnemyStats.new() var s: float = mult * (3.0 if strong else 1.0) stats.max_health = 30.0 * s stats.attack_damage = 5.0 * s stats.attack_range = 2.0 stats.attack_cooldown = 1.5 stats.speed = 3.0 stats.aggro_radius = 12.0 stats.xp_value = 5.0 * s e.stats_resource = stats e.name = "Enemy_%d" % (Time.get_ticks_msec() + randi() % 1000) root.add_child(e, true) e.global_position = pos return e func spawn_boss_at(pos: Vector3, mult: float = 1.0) -> Node: if not multiplayer.is_server() and multiplayer.multiplayer_peer != null: return null var root := _enemy_root() if root == null: return null var b: CharacterBody3D = ENEMY_SCENE.instantiate() b.is_boss = true var stats := BossStats.new() stats.max_health = 250.0 * mult stats.attack_damage = 12.0 * mult stats.attack_range = 3.0 stats.attack_cooldown = 1.6 stats.speed = 3.5 stats.xp_value = 100.0 * mult b.stats_resource = stats b.name = "Boss_%d" % Time.get_ticks_msec() root.add_child(b, true) b.global_position = pos return b func spawn_portal_at(pos: Vector3, is_red: bool) -> Node: if not multiplayer.is_server() and multiplayer.multiplayer_peer != null: return null var root := _portal_root() if root == null: return null var p: StaticBody3D = PORTAL_SCENE.instantiate() p.is_red = is_red p.name = "Portal_%d" % Time.get_ticks_msec() root.add_child(p, true) p.global_position = pos EventBus.portal_spawned.emit(p) return p func spawn_gate_at(pos: Vector3, is_red: bool) -> Node: if not multiplayer.is_server() and multiplayer.multiplayer_peer != null: return null var root := _gate_root() if root == null: return null var g: StaticBody3D = GATE_SCENE.instantiate() g.is_red = is_red g.name = "Gate_%s_%d" % ["red" if is_red else "n", Time.get_ticks_msec() + randi() % 1000] root.add_child(g, true) g.global_position = pos return g