class_name DashController extends "res://controllers/AimedFleetAbilityController.gd" # Energy Propulser active ability (#179): hold, aim a direction, release, and # the complete fleet surges along that heading. Cooldown belongs to the # particular Propulser selected by the shared ability controller, so adding a # second hull adds a second independently recharging dash. const DASH_COLOR := Color(0.85, 0.95, 0.15) # The unupgraded reach, and what the definition declares. #205 made it a # vessel stat; _aim_max_range() below is the distance actually in force. const DASH_DISTANCE: float = 520.0 const ENERGY_PER_DASH: int = 15 const TRAIL_SECONDS: float = 0.45 var trail_from: Vector2 = Vector2.ZERO var trail_time: float = 0.0 func _button_path() -> NodePath: return "../UI/DashButton" func _status_path() -> NodePath: return "../UI/DashStatus" func _component_id() -> String: return "distorder" func _ammo_resource() -> String: return GameState.RESOURCE_ENERGY func _ammo_cost() -> int: return ENERGY_PER_DASH func _aim_padding() -> float: return 36.0 # Off the PROPULSER that will actually surge, falling back to the definition # when none is ready - the same shape LaserController._aim_max_range() uses, # and for the same reason: the guide must not promise reach the fleet has not # researched. func _aim_max_range() -> float: return GameState.vessel_stat(GameState.VESSEL_DISTORDER, "dash_distance") func _has_effect_visuals() -> bool: return trail_time > 0.0 or fleet.is_dashing() func _calculate_aim_target(drag: Vector2, origin: Vector2) -> Vector2: var direction: Vector2 = drag.normalized() if drag.length() > 0.001 else Vector2.UP return origin + direction * _aim_max_range() func _consume_shot(component: Node) -> bool: return component.consume_dash() func _perform_shot(_ship: Node2D, _component: Node) -> void: var direction: Vector2 = aim_target - _aim_origin() if direction.length() < 0.001: return trail_from = fleet.get_centroid() trail_time = TRAIL_SECONDS fleet.dash(direction, _aim_max_range()) func _advance_effects(delta: float) -> void: trail_time = maxf(trail_time - delta, 0.0) func _draw() -> void: if aiming: var origin: Vector2 = _aim_origin() NeonDraw.draw_glowing_line(self, origin, aim_target, DASH_COLOR, 0.65, 0.65) var direction: Vector2 = (aim_target - origin).normalized() var side: Vector2 = direction.orthogonal() * 18.0 NeonDraw.draw_glowing_path(self, PackedVector2Array([ aim_target - direction * 38.0 + side, aim_target, aim_target - direction * 38.0 - side, ]), DASH_COLOR, 0.9, 0.55) if trail_time > 0.0: var alpha: float = trail_time / TRAIL_SECONDS var now: Vector2 = fleet.get_centroid() for offset in [-20.0, 0.0, 20.0]: var across: Vector2 = (now - trail_from).normalized().orthogonal() * offset NeonDraw.draw_glowing_line(self, trail_from + across, now + across, DASH_COLOR, alpha * 0.6, 0.35)