extends SceneTree # Headless gameplay test: run with # godot --headless -s res://tests/test_enemy_detection_range.gd # Forgejo #69: enemies used to beeline toward the fleet from anywhere on the # map the instant they spawned. Chasers (EnemyPursuitComponent) and snipers # (EnemyStandoffComponent) now sit idle until the fleet is within their own # detection_range; the enemy mothership deliberately keeps an (effectively) # unlimited range instead, since it is meant to read as a persistent, # unavoidable stalking threat rather than a local sentry. # # Covers: # A. a chaser beyond detection_range does not move at all # B. the same chaser, once the fleet is within range, closes in # C. a sniper beyond detection_range does not move either # D. the enemy mothership closes in even from far beyond a chaser's range var game_state: Node var main: Node var fleet: Node var chaser: Node var sniper: Node var mothership: Node var chaser_start: Vector2 var sniper_start: Vector2 var mothership_start: Vector2 var stage: int = 0 var elapsed: float = 0.0 func _initialize() -> void: game_state = root.get_node("GameState") game_state.buildings.clear() game_state.extractors.clear() game_state.transporters.clear() game_state.reset_progression() main = load("res://Main.tscn").instantiate() root.add_child(main) fleet = main.get_node("Fleet") func _process(delta: float) -> bool: elapsed += delta match stage: 0: if elapsed < 0.2: return false main.get_node("EnemySpawner").set_process(false) main.get_node("AsteroidField").set_process(false) for a in get_nodes_in_group("asteroids"): a.queue_free() fleet.spawn_ships(1, Vector2.ZERO) # --- A. beyond detection_range: no movement at all --------------- chaser = load("res://Enemy.tscn").instantiate() chaser.enemy_id = "chaser" var pursuit: Node = null main.add_child(chaser) pursuit = chaser.get_component("pursuit") chaser.position = fleet.get_centroid() + Vector2(pursuit.detection_range + 300.0, 0.0) chaser_start = chaser.position sniper = load("res://Enemy.tscn").instantiate() sniper.enemy_id = "sniper" main.add_child(sniper) var standoff: Node = sniper.get_component("standoff") sniper.position = fleet.get_centroid() + Vector2(0.0, standoff.detection_range + 300.0) sniper_start = sniper.position elapsed = 0.0 stage = 1 return false 1: if elapsed < 1.0: return false var chaser_moved: float = chaser.position.distance_to(chaser_start) var sniper_moved: float = sniper.position.distance_to(sniper_start) print("beyond range for 1.0s: chaser moved %.1f, sniper moved %.1f" % [chaser_moved, sniper_moved]) if chaser_moved > 1.0: return _fail("a chaser beyond detection_range moved %.1f - it should sit idle" % chaser_moved) if sniper_moved > 1.0: return _fail("a sniper beyond detection_range moved %.1f - it should sit idle" % sniper_moved) # --- B. bring the chaser within range, it should now close in ---- var pursuit: Node = chaser.get_component("pursuit") chaser.position = fleet.get_centroid() + Vector2(pursuit.detection_range * 0.5, 0.0) chaser_start = chaser.position elapsed = 0.0 stage = 2 return false 2: if elapsed < 1.0: return false var chaser_moved: float = chaser.position.distance_to(chaser_start) print("within range for 1.0s: chaser moved %.1f" % chaser_moved) if chaser_moved < 20.0: return _fail("a chaser within detection_range did not close in (moved %.1f)" % chaser_moved) print("chaser correctly idle beyond range, closes in once inside it") # --- D. the mothership closes in from far beyond a chaser's range - mothership = load("res://Enemy.tscn").instantiate() mothership.enemy_id = "enemy_mothership" main.add_child(mothership) var mother_pursuit: Node = mothership.get_component("pursuit") if mother_pursuit.detection_range < 50000.0: return _fail("the mothership's pursuit range is not effectively unlimited (%f)" \ % mother_pursuit.detection_range) mothership.position = fleet.get_centroid() + Vector2(5000.0, 0.0) mothership_start = mothership.position elapsed = 0.0 stage = 3 return false 3: if elapsed < 1.0: return false var mothership_moved: float = mothership.position.distance_to(mothership_start) print("mothership 5000 units out, 1.0s: moved %.1f" % mothership_moved) if mothership_moved < 5.0: return _fail("the mothership did not close in from far away (moved %.1f)" % mothership_moved) print("TEST_ENEMY_DETECTION_RANGE: PASS") quit(0) return true return false func _fail(message: String) -> bool: print("TEST_ENEMY_DETECTION_RANGE: FAIL (%s)" % message) quit(1) return true