diff --git a/game/threatzones.py b/game/threatzones.py index 571e7082..475517d6 100644 --- a/game/threatzones.py +++ b/game/threatzones.py @@ -1,7 +1,7 @@ from __future__ import annotations from functools import singledispatchmethod -from typing import Optional, TYPE_CHECKING, Union +from typing import Optional, TYPE_CHECKING, Union, Iterable from dcs.mapping import Point as DcsPoint from shapely.geometry import ( @@ -16,7 +16,7 @@ from shapely.ops import nearest_points, unary_union from game.theater import ControlPoint from game.utils import Distance, meters, nautical_miles from gen.flights.closestairfields import ObjectiveDistanceCache -from gen.flights.flight import Flight +from gen.flights.flight import Flight, FlightWaypoint if TYPE_CHECKING: from game import Game @@ -71,6 +71,13 @@ class ThreatZones: LineString((self.dcs_to_shapely_point(p.position) for p in flight.points)) ) + def waypoints_threatened_by_aircraft( + self, waypoints: Iterable[FlightWaypoint] + ) -> bool: + return self.threatened_by_aircraft( + LineString((self.dcs_to_shapely_point(p.position) for p in waypoints)) + ) + @singledispatchmethod def threatened_by_air_defense(self, target) -> bool: raise NotImplementedError @@ -99,6 +106,13 @@ class ThreatZones: LineString((self.dcs_to_shapely_point(p.position) for p in flight.points)) ) + def waypoints_threatened_by_radar_sam( + self, waypoints: Iterable[FlightWaypoint] + ) -> bool: + return self.threatened_by_radar_sam( + LineString((self.dcs_to_shapely_point(p.position) for p in waypoints)) + ) + @classmethod def closest_enemy_airbase( cls, location: ControlPoint, max_distance: Distance diff --git a/gen/flights/ai_flight_planner.py b/gen/flights/ai_flight_planner.py index 3b06481c..027230ed 100644 --- a/gen/flights/ai_flight_planner.py +++ b/gen/flights/ai_flight_planner.py @@ -831,9 +831,13 @@ class CoalitionMissionPlanner: def check_needed_escorts(self, builder: PackageBuilder) -> Dict[EscortType, bool]: threats = defaultdict(bool) for flight in builder.package.flights: - if self.threat_zones.threatened_by_aircraft(flight): + if self.threat_zones.waypoints_threatened_by_aircraft( + flight.flight_plan.escorted_waypoints() + ): threats[EscortType.AirToAir] = True - if self.threat_zones.threatened_by_radar_sam(flight): + if self.threat_zones.waypoints_threatened_by_radar_sam( + list(flight.flight_plan.escorted_waypoints()) + ): threats[EscortType.Sead] = True return threats diff --git a/gen/flights/flightplan.py b/gen/flights/flightplan.py index 5e6bc886..c2779e3f 100644 --- a/gen/flights/flightplan.py +++ b/gen/flights/flightplan.py @@ -198,6 +198,20 @@ class FlightPlan: def dismiss_escort_at(self) -> Optional[FlightWaypoint]: return None + def escorted_waypoints(self) -> Iterator[FlightWaypoint]: + begin = self.request_escort_at() + end = self.dismiss_escort_at() + if begin is None or end is None: + return + escorting = False + for waypoint in self.waypoints: + if waypoint == begin: + escorting = True + if escorting: + yield waypoint + if waypoint == end: + return + def takeoff_time(self) -> Optional[timedelta]: tot_waypoint = self.tot_waypoint if tot_waypoint is None: @@ -600,10 +614,6 @@ class StrikeFlightPlan(FormationFlightPlan): ) return total - @property - def mission_speed(self) -> Speed: - return GroundSpeed.for_flight(self.flight, self.ingress.alt) - @property def join_time(self) -> timedelta: travel_time = self.travel_time_between_waypoints(self.join, self.ingress)