2026-08-15 21:23:43 +02:00
|
|
|
class_name EnemyArtilleryComponent
|
|
|
|
|
extends Node
|
|
|
|
|
|
|
|
|
|
# Stationary siege piece: drifts slowly toward the fleet (deliberately no
|
|
|
|
|
# pursuit component - closing distance is incidental, not its purpose) and
|
|
|
|
|
# fires a slow, heavily telegraphed AOE shell on a long cooldown via a
|
|
|
|
|
# standalone ArtilleryShell, so an already-launched shot survives this
|
|
|
|
|
# enemy dying mid-flight, same as EnemyProjectile/Projectile already do.
|
|
|
|
|
|
|
|
|
|
var capability_id: String = "artillery"
|
|
|
|
|
|
|
|
|
|
@export var fire_cooldown: float = 6.0
|
|
|
|
|
@export var fire_range: float = 900.0
|
|
|
|
|
@export var telegraph_time: float = 1.8
|
|
|
|
|
@export var shell_speed: float = 180.0
|
|
|
|
|
@export var aoe_radius: float = 220.0
|
|
|
|
|
@export var damage: int = 3
|
|
|
|
|
@export var drift_speed: float = 20.0
|
|
|
|
|
@export var color: Color = Color(1.0, 0.5, 0.2)
|
|
|
|
|
|
|
|
|
|
var cooldown_left: float = 0.0
|
|
|
|
|
var shell_scene: PackedScene = preload("res://ArtilleryShell.tscn")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func tick(delta: float) -> void:
|
|
|
|
|
var enemy: Node2D = get_parent()
|
|
|
|
|
_drift(enemy, delta)
|
|
|
|
|
|
|
|
|
|
cooldown_left -= delta
|
|
|
|
|
if cooldown_left > 0.0:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
var fleet: Node2D = get_tree().get_first_node_in_group("player_fleet")
|
|
|
|
|
if fleet == null or fleet.ships.is_empty():
|
|
|
|
|
return
|
|
|
|
|
var centroid: Vector2 = fleet.get_centroid()
|
|
|
|
|
if enemy.global_position.distance_to(centroid) > fire_range:
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
var shell: Node2D = shell_scene.instantiate()
|
|
|
|
|
shell.telegraph_time = telegraph_time
|
|
|
|
|
shell.shell_speed = shell_speed
|
|
|
|
|
shell.aoe_radius = aoe_radius
|
|
|
|
|
shell.damage = damage
|
|
|
|
|
shell.color = color
|
|
|
|
|
enemy.get_tree().root.add_child(shell)
|
|
|
|
|
shell.launch(enemy.global_position, centroid)
|
|
|
|
|
cooldown_left = fire_cooldown
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func _drift(enemy: Node2D, delta: float) -> void:
|
|
|
|
|
# Local position throughout, same convention as EnemyPursuitComponent/
|
|
|
|
|
# EnemyStandoffComponent: valid as long as the enemy's container and
|
|
|
|
|
# Fleet share a common origin, which every scene in this project does.
|
|
|
|
|
var fleet: Node2D = get_tree().get_first_node_in_group("player_fleet")
|
|
|
|
|
if fleet == null or fleet.ships.is_empty():
|
|
|
|
|
return
|
|
|
|
|
var to_fleet: Vector2 = fleet.get_centroid() - enemy.position
|
2026-08-17 19:47:37 +02:00
|
|
|
# #69: gated by the same fire_range it already shells within, rather
|
|
|
|
|
# than a second tunable that could drift out of sync - outside its own
|
|
|
|
|
# firing envelope it has nothing to be drifting toward yet.
|
|
|
|
|
if to_fleet.length() > fire_range:
|
|
|
|
|
return
|
2026-08-15 21:23:43 +02:00
|
|
|
if to_fleet.length() < 1.0:
|
|
|
|
|
return
|
|
|
|
|
enemy.position += to_fleet.normalized() * drift_speed * delta
|