diff --git a/game/data/doctrine.py b/game/data/doctrine.py index 939b60cf..31b0a03b 100644 --- a/game/data/doctrine.py +++ b/game/data/doctrine.py @@ -25,12 +25,27 @@ class Doctrine: max_patrol_altitude: Distance pattern_altitude: Distance + #: The duration that CAP flights will remain on-station. cap_duration: timedelta + + #: The minimum length of the CAP race track. cap_min_track_length: Distance + + #: The maximum length of the CAP race track. cap_max_track_length: Distance + + #: The minimum distance between the defended position and the *end* of the + #: CAP race track. cap_min_distance_from_cp: Distance + + #: The maximum distance between the defended position and the *end* of the + #: CAP race track. cap_max_distance_from_cp: Distance + #: The engagement range of CAP flights. Any enemy aircraft within this range + #: of the CAP's current position will be engaged by the CAP. + cap_engagement_range: Distance + cas_duration: timedelta sweep_distance: Distance @@ -58,6 +73,7 @@ MODERN_DOCTRINE = Doctrine( cap_max_track_length=nautical_miles(40), cap_min_distance_from_cp=nautical_miles(10), cap_max_distance_from_cp=nautical_miles(40), + cap_engagement_range=nautical_miles(50), cas_duration=timedelta(minutes=30), sweep_distance=nautical_miles(60), ) @@ -84,6 +100,7 @@ COLDWAR_DOCTRINE = Doctrine( cap_max_track_length=nautical_miles(24), cap_min_distance_from_cp=nautical_miles(8), cap_max_distance_from_cp=nautical_miles(25), + cap_engagement_range=nautical_miles(35), cas_duration=timedelta(minutes=30), sweep_distance=nautical_miles(40), ) @@ -110,6 +127,7 @@ WWII_DOCTRINE = Doctrine( cap_max_track_length=nautical_miles(18), cap_min_distance_from_cp=nautical_miles(0), cap_max_distance_from_cp=nautical_miles(5), + cap_engagement_range=nautical_miles(20), cas_duration=timedelta(minutes=30), sweep_distance=nautical_miles(10), ) diff --git a/gen/aircraft.py b/gen/aircraft.py index cc807ebd..5e7cd879 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -1504,7 +1504,7 @@ class CasIngressBuilder(PydcsWaypointBuilder): if isinstance(self.flight.flight_plan, CasFlightPlan): waypoint.add_task(EngageTargetsInZone( position=self.flight.flight_plan.target, - radius=FRONTLINE_LENGTH / 2, + radius=int(self.flight.flight_plan.engagement_distance.meters), targets=[ Targets.All.GroundUnits.GroundVehicles, Targets.All.GroundUnits.AirDefence.AAA, @@ -1750,8 +1750,10 @@ class RaceTrackBuilder(PydcsWaypointBuilder): def build(self) -> MovingPoint: waypoint = super().build() - if not isinstance(self.flight.flight_plan, PatrollingFlightPlan): - flight_plan_type = self.flight.flight_plan.__class__.__name__ + flight_plan = self.flight.flight_plan + + if not isinstance(flight_plan, PatrollingFlightPlan): + flight_plan_type = flight_plan.__class__.__name__ logging.error( f"Cannot create race track for {self.flight} because " f"{flight_plan_type} does not define a patrol.") @@ -1769,18 +1771,18 @@ class RaceTrackBuilder(PydcsWaypointBuilder): # later. cap_types = {FlightType.BARCAP, FlightType.TARCAP} if self.flight.flight_type in cap_types: + engagement_distance = int(flight_plan.engagement_distance.meters) waypoint.tasks.append( - EngageTargets(max_distance=int(nautical_miles(50).meters), + EngageTargets(max_distance=engagement_distance, targets=[Targets.All.Air])) racetrack = ControlledTask(OrbitAction( altitude=waypoint.alt, pattern=OrbitAction.OrbitPattern.RaceTrack )) - self.set_waypoint_tot( - waypoint, self.flight.flight_plan.patrol_start_time) + self.set_waypoint_tot(waypoint, flight_plan.patrol_start_time) racetrack.stop_after_time( - int(self.flight.flight_plan.patrol_end_time.total_seconds())) + int(flight_plan.patrol_end_time.total_seconds())) waypoint.add_task(racetrack) return waypoint diff --git a/gen/flights/flightplan.py b/gen/flights/flightplan.py index a984fc76..f5656a32 100644 --- a/gen/flights/flightplan.py +++ b/gen/flights/flightplan.py @@ -33,7 +33,7 @@ from .closestairfields import ObjectiveDistanceCache from .flight import Flight, FlightType, FlightWaypoint, FlightWaypointType from .traveltime import GroundSpeed, TravelTime from .waypointbuilder import StrikeTarget, WaypointBuilder -from ..conflictgen import Conflict +from ..conflictgen import Conflict, FRONTLINE_LENGTH if TYPE_CHECKING: from game import Game @@ -365,6 +365,12 @@ class PatrollingFlightPlan(FlightPlan): #: Maximum time to remain on station. patrol_duration: timedelta + #: The engagement range of any Search Then Engage task, or the radius of a + #: Search Then Engage in Zone task. Any enemies of the appropriate type for + #: this mission within this range of the flight's current position (or the + #: center of the zone) will be engaged by the flight. + engagement_distance: Distance + @property def patrol_start_time(self) -> timedelta: return self.package.time_over_target @@ -877,6 +883,7 @@ class FlightPlanBuilder: package=self.package, flight=flight, patrol_duration=self.doctrine.cap_duration, + engagement_distance=self.doctrine.cap_engagement_range, takeoff=builder.takeoff(flight.departure), patrol_start=start, patrol_end=end, @@ -1010,6 +1017,7 @@ class FlightPlanBuilder: # requests an escort the CAP flight will remain on station for the # duration of the escorted mission, or until it is winchester/bingo. patrol_duration=self.doctrine.cap_duration, + engagement_distance=self.doctrine.cap_engagement_range, takeoff=builder.takeoff(flight.departure), patrol_start=start, patrol_end=end, @@ -1152,6 +1160,7 @@ class FlightPlanBuilder: takeoff=builder.takeoff(flight.departure), patrol_start=builder.ingress(FlightWaypointType.INGRESS_CAS, ingress, location), + engagement_distance=meters(FRONTLINE_LENGTH) / 2, target=builder.cas(center), patrol_end=builder.egress(egress, location), land=builder.land(flight.arrival),