Add standoff sniper enemy (#45)

EnemyStandoffComponent holds a preferred distance from the nearest
player ship instead of ramming (advance beyond it, retreat inside
retreat_range_factor of it, drift laterally in the comfortable band
between) - never paired with a pursuit component. EnemyRangedWeaponComponent
mirrors VesselWeaponComponent for an enemy: fires an EnemyProjectile
aimed at the target's CURRENT position rather than led, so a moving
ship can dodge it (projectile_speed 260 vs the interceptor's 460
max_speed). Registered in EnemyDefinitions so it's placeable from a
planet setup by enemy_id.

test_sniper_enemy.gd went through a few iterations to get its own
timing right: physics ticks can run ahead of a SceneTree test's own
_process() clock under this device's load, so the cooldown-violation
check reads the component's own fire_timer directly (a rising value
means it refired) instead of comparing projectile counts against a
wall-clock wait, and manually repositioned ships need their
move_target re-pinned or Ship's own steering silently drives them back
to the stale target.

Part of the #40 conquest-mechanic breakdown.
This commit is contained in:
Loïc Wisniewski 2026-08-15 21:23:01 +02:00
commit fc2b5ca74a
13 changed files with 455 additions and 1 deletions

View file

@ -0,0 +1,17 @@
[gd_resource type="Resource" script_class="EnemyDefinition" load_steps=4 format=3]
[ext_resource type="Script" path="res://EnemyDefinition.gd" id="1"]
[ext_resource type="PackedScene" path="res://EnemyStandoffComponent.tscn" id="2"]
[ext_resource type="PackedScene" path="res://EnemyRangedWeaponComponent.tscn" id="3"]
[resource]
script = ExtResource("1")
enemy_id = "sniper"
display_name = "Sniper"
max_hp = 4
speed = 90.0
acceleration = 180.0
rotation_speed = 5.0
hull_points = PackedVector2Array(0, -28, 7, -6, 7, 22, -7, 22, -7, -6)
glow_color = Color(0.42, 0.72, 1.0, 1)
component_scenes = Array[PackedScene]([ExtResource("2"), ExtResource("3")])