extends SceneTree # Forgejo #179: an Energy Propulser in the fleet grants a hold-aim-release # dash. Covers visibility, aimed movement, energy cost, formation integrity, # and one cooldown per Propulser. const DASH_COST: int = 15 const DASH_DISTANCE: float = 520.0 const DASH_SETTLE_TIME: float = 0.3 var state: Node var main: Node var fleet: Node var dash: Node var stage: int = 0 var elapsed: float = 0.0 var first_origin: Vector2 var second_origin: Vector2 var offsets_before: Array = [] var first_component: Node func _initialize() -> void: state = root.get_node("GameState") state.reset_new_game() state.intro_active = false state.reset_quests() state.vessel_levels["unlock_distorder"] = 1 state.fleet_inventory.total_capacity = -1 state.deposit_fleet_resource(GameState.RESOURCE_ENERGY, DASH_COST * 3) main = load("res://world/Main.tscn").instantiate() root.add_child(main) current_scene = main fleet = main.get_node("Fleet") dash = main.get_node("DashController") func _process(delta: float) -> bool: elapsed += delta match stage: 0: if elapsed < 0.3: return false main.get_node("EnemySpawner").set_process(false) main.get_node("AsteroidField").set_process(false) if main.get_node("UI/DashButton").visible: return _fail("dash button appeared without an Energy Propulser") # The carrier keeps enough hold capacity for both dashes. Two # Propulsers prove that cooldown belongs to a vessel, not the fleet. fleet.spawn_ships(3, Vector2.ZERO, PackedStringArray([ GameState.VESSEL_CARRIER, GameState.VESSEL_DISTORDER, GameState.VESSEL_DISTORDER, ])) dash._process(0.0) if not main.get_node("UI/DashButton").visible: return _fail("an Energy Propulser did not reveal the dash button") first_component = dash._next_ready_ship().get_component("distorder") first_origin = fleet.get_centroid() for ship in fleet.ships: offsets_before.append(ship.position - first_origin) _aim_and_release(Vector2.RIGHT, 11) if not fleet.is_dashing(): return _fail("releasing a rightward aim did not begin a dash") if state.fleet_resource(GameState.RESOURCE_ENERGY) != DASH_COST * 2: return _fail("first dash did not consume %d energy" % DASH_COST) if first_component.is_ready(): return _fail("the Propulser that dashed did not enter cooldown") dash._process(0.0) if not main.get_node("UI/DashButton").enabled: return _fail("one cooling Propulser disabled a second ready one") stage = 1 elapsed = 0.0 return false 1: if elapsed < DASH_SETTLE_TIME: return false var moved: Vector2 = fleet.get_centroid() - first_origin if absf(moved.x - DASH_DISTANCE) > 8.0 or absf(moved.y) > 8.0: return _fail("rightward aim moved the fleet by %s" % moved) for i in range(fleet.ships.size()): var offset: Vector2 = fleet.ships[i].position - fleet.get_centroid() if offset.distance_to(offsets_before[i]) > 1.0: return _fail("dash distorted formation slot %d by %.2f" \ % [i, offset.distance_to(offsets_before[i])]) second_origin = fleet.get_centroid() _aim_and_release(Vector2.UP, 12) if state.fleet_resource(GameState.RESOURCE_ENERGY) != DASH_COST: return _fail("second Propulser did not pay for its own dash") dash._process(0.0) if main.get_node("UI/DashButton").enabled: return _fail("dash remained enabled after both Propulsers fired") stage = 2 elapsed = 0.0 return false 2: if elapsed < DASH_SETTLE_TIME: return false var moved: Vector2 = fleet.get_centroid() - second_origin if absf(moved.y + DASH_DISTANCE) > 8.0 or absf(moved.x) > 8.0: return _fail("upward aim moved the fleet by %s" % moved) first_component.tick(first_component.DASH_COOLDOWN) dash._process(0.0) if not main.get_node("UI/DashButton").enabled: return _fail("button did not re-enable when one Propulser recharged") var surface: Node = load("res://surface/PlanetSurface.tscn").instantiate() if not surface.has_node("DashController") or not surface.has_node("UI/DashButton"): return _fail("planet surface does not carry the dash ability") if surface.has_node("UI/SpeedFader"): return _fail("planet surface still carries the sustained speed multiplier") surface.free() print("two aimed dashes moved %.0f units, preserved formation, and cooled down per Propulser" \ % DASH_DISTANCE) print("TEST_ENERGY_PROPULSER_DASH: PASS") quit(0) return true return false func _aim_and_release(direction: Vector2, touch_index: int) -> void: var button: Control = main.get_node("UI/DashButton") var press := InputEventScreenTouch.new() press.index = touch_index press.pressed = true press.position = button.global_position + button.size * 0.5 main._handle_touch(press) var drag := InputEventScreenDrag.new() drag.index = touch_index drag.position = press.position + direction * 240.0 main._handle_drag(drag) var release := InputEventScreenTouch.new() release.index = touch_index release.pressed = false release.position = drag.position main._handle_touch(release) func _fail(message: String) -> bool: print("TEST_ENERGY_PROPULSER_DASH: FAIL (%s)" % message) quit(1) return true