class_name EnemyTargets extends RefCounted # #101 (#97c): who a wave enemy is coming for. # # Before this, every enemy component asked the same question - "which player # SHIP is nearest?" - and a structure was scenery they flew straight past. # #97 makes waves go after what the player has built, so the question # becomes "which player thing is nearest", asked in one place so pursuit, # standoff, the lancer's lunge and the ranged weapon cannot drift into # disagreeing about it. # # There is one thumb on the scale. A ship inside SHIP_PRIORITY_RANGE always # wins, even if a building is nearer: an enemy that ignored the vessels # shooting it in order to reach a depot two hundred pixels closer would read # as broken, and would make the fleet unable to defend anything by # interposing itself. const SHIP_PRIORITY_RANGE: float = 520.0 # The GROUP, not Fleet.ships. #105 puts vessels at outposts that are not in # the fleet at all, and an enemy that ignored the guns actually shooting at # it - because they were not in the player's formation - would let a # garrison hold a position without ever being fought back. static func nearest_ship(node: Node, from: Vector2) -> Node2D: var nearest: Node2D = null var best: float = INF for ship in node.get_tree().get_nodes_in_group("player_ships"): if not is_instance_valid(ship) or ship.is_queued_for_deletion(): continue var d: float = from.distance_to((ship as Node2D).global_position) if d < best: best = d nearest = ship return nearest static func nearest_building(node: Node, from: Vector2) -> Node2D: var nearest: Node2D = null var best: float = INF for building in node.get_tree().get_nodes_in_group("buildings"): if not is_instance_valid(building) or building.is_queued_for_deletion(): continue var d: float = from.distance_to(building.global_position) if d < best: best = d nearest = building return nearest static func nearest_target(node: Node, from: Vector2) -> Node2D: var ship: Node2D = nearest_ship(node, from) if ship != null and from.distance_to(ship.global_position) <= SHIP_PRIORITY_RANGE: return ship var building: Node2D = nearest_building(node, from) if building == null: return ship if ship == null: return building return ship if from.distance_to(ship.global_position) \ <= from.distance_to(building.global_position) else building static func is_building(target: Node) -> bool: return target != null and target.is_in_group("buildings")