diff --git a/gen/aircraft.py b/gen/aircraft.py index 25c4f65e..0fac70b0 100644 --- a/gen/aircraft.py +++ b/gen/aircraft.py @@ -1027,9 +1027,21 @@ class AircraftConflictGenerator: rtb_winchester=OptRTBOnOutOfAmmo.Values.Unguided, restrict_jettison=True) + def configure_dead(self, group: FlyingGroup, package: Package, + flight: Flight, + dynamic_runways: Dict[str, RunwayData]) -> None: + group.task = SEAD.name + self._setup_group(group, SEAD, package, flight, dynamic_runways) + self.configure_behavior( + group, + react_on_threat=OptReactOnThreat.Values.EvadeFire, + roe=OptROE.Values.OpenFire, + rtb_winchester=OptRTBOnOutOfAmmo.Values.ASM, + restrict_jettison=True) + def configure_sead(self, group: FlyingGroup, package: Package, - flight: Flight, - dynamic_runways: Dict[str, RunwayData]) -> None: + flight: Flight, + dynamic_runways: Dict[str, RunwayData]) -> None: group.task = SEAD.name self._setup_group(group, SEAD, package, flight, dynamic_runways) self.configure_behavior( @@ -1087,7 +1099,9 @@ class AircraftConflictGenerator: self.configure_cap(group, package, flight, dynamic_runways) elif flight_type in [FlightType.CAS, FlightType.BAI]: self.configure_cas(group, package, flight, dynamic_runways) - elif flight_type in [FlightType.SEAD, FlightType.DEAD]: + elif flight_type in [FlightType.DEAD, ]: + self.configure_dead(group, package, flight, dynamic_runways) + elif flight_type in [FlightType.SEAD, ]: self.configure_sead(group, package, flight, dynamic_runways) elif flight_type in [FlightType.STRIKE]: self.configure_strike(group, package, flight, dynamic_runways) @@ -1208,6 +1222,7 @@ class PydcsWaypointBuilder: mission: Mission) -> PydcsWaypointBuilder: builders = { FlightWaypointType.INGRESS_CAS: CasIngressBuilder, + FlightWaypointType.INGRESS_DEAD: DeadIngressBuilder, FlightWaypointType.INGRESS_SEAD: SeadIngressBuilder, FlightWaypointType.INGRESS_STRIKE: StrikeIngressBuilder, FlightWaypointType.JOIN: JoinPointBuilder, @@ -1273,14 +1288,14 @@ class CasIngressBuilder(PydcsWaypointBuilder): return waypoint -class SeadIngressBuilder(PydcsWaypointBuilder): +class DeadIngressBuilder(PydcsWaypointBuilder): def build(self) -> MovingPoint: waypoint = super().build() target_group = self.package.target if isinstance(target_group, TheaterGroundObject): - tgroup = self.mission.find_group(target_group.group_identifier) - if tgroup is not None: + tgroup = self.mission.find_group(target_group.group_identifier, search="match") # Match search is used due to TheaterGroundObject.name not matching + if tgroup is not None: # the Mission group name because of SkyNet prefixes. task = AttackGroup(tgroup.id) task.params["expend"] = "All" task.params["attackQtyLimit"] = False @@ -1289,6 +1304,36 @@ class SeadIngressBuilder(PydcsWaypointBuilder): task.params["weaponType"] = 268402702 # Guided Weapons task.params["groupAttack"] = True waypoint.tasks.append(task) + else: + logging.error(f"Could not find group for DEAD mission {target_group.group_identifier}") + + for i, t in enumerate(self.waypoint.targets): + if self.group.units[0].unit_type == JF_17 and i < 4: + self.group.add_nav_target_point(t.position, "PP" + str(i + 1)) + if self.group.units[0].unit_type == F_14B and i == 0: + self.group.add_nav_target_point(t.position, "ST") + if self.group.units[0].unit_type == AJS37 and i < 9: + self.group.add_nav_target_point(t.position, "M" + str(i + 1)) + return waypoint + + +class SeadIngressBuilder(PydcsWaypointBuilder): + def build(self) -> MovingPoint: + waypoint = super().build() + + target_group = self.package.target + if isinstance(target_group, TheaterGroundObject): + tgroup = self.mission.find_group(target_group.group_identifier, search="match") # Match search is used due to TheaterGroundObject.name not matching + if tgroup is not None: # the Mission group name because of SkyNet prefixes. + waypoint.add_task(EngageTargetsInZone( + position=tgroup.position, + radius=nm_to_meter(30), + targets=[ + Targets.All.GroundUnits.AirDefence, + ]) + ) + else: + logging.error(f"Could not find group for DEAD mission {target_group.group_identifier}") for i, t in enumerate(self.waypoint.targets): if self.group.units[0].unit_type == JF_17 and i < 4: diff --git a/gen/flights/flight.py b/gen/flights/flight.py index 48296635..d76347f3 100644 --- a/gen/flights/flight.py +++ b/gen/flights/flight.py @@ -60,6 +60,7 @@ class FlightWaypointType(Enum): SPLIT = 17 LOITER = 18 INGRESS_ESCORT = 19 + INGRESS_DEAD = 20 class FlightWaypoint: diff --git a/gen/flights/flightplan.py b/gen/flights/flightplan.py index 60fb32cf..8839b1af 100644 --- a/gen/flights/flightplan.py +++ b/gen/flights/flightplan.py @@ -36,6 +36,7 @@ INGRESS_TYPES = { FlightWaypointType.INGRESS_ESCORT, FlightWaypointType.INGRESS_SEAD, FlightWaypointType.INGRESS_STRIKE, + FlightWaypointType.INGRESS_DEAD, } @@ -545,7 +546,7 @@ class FlightPlanBuilder: elif task == FlightType.CAS: return self.generate_cas(flight) elif task == FlightType.DEAD: - return self.generate_sead(flight, custom_targets) + return self.generate_dead(flight, custom_targets) elif task == FlightType.ESCORT: return self.generate_escort(flight) elif task == FlightType.SEAD: @@ -734,9 +735,34 @@ class FlightPlanBuilder: land=land ) + def generate_dead(self, flight: Flight, + custom_targets: Optional[List[Unit]]) -> StrikeFlightPlan: + """Generate a DEAD flight at a given location. + + Args: + flight: The flight to generate the flight plan for. + custom_targets: Specific radar equipped units selected by the user. + """ + location = self.package.target + + if not isinstance(location, TheaterGroundObject): + logging.exception(f"Invalid Objective Location for DEAD flight {flight=} at {location=}") + raise InvalidObjectiveLocation(flight.flight_type, location) + + # TODO: Unify these. + # There doesn't seem to be any reason to treat the UI fragged missions + # different from the automatic missions. + targets: Optional[List[StrikeTarget]] = None + if custom_targets is not None: + targets = [] + for target in custom_targets: + targets.append(StrikeTarget(location.name, target)) + + return self.strike_flightplan(flight, location, targets) + def generate_sead(self, flight: Flight, custom_targets: Optional[List[Unit]]) -> StrikeFlightPlan: - """Generate a SEAD/DEAD flight at a given location. + """Generate a SEAD flight at a given location. Args: flight: The flight to generate the flight plan for. @@ -884,10 +910,14 @@ class FlightPlanBuilder: assert self.package.waypoints is not None builder = WaypointBuilder(self.game.conditions, flight, self.doctrine, targets) - sead_types = {FlightType.DEAD, FlightType.SEAD} - if flight.flight_type in sead_types: + # sead_types = {FlightType.DEAD, FlightType.SEAD} + if flight.flight_type is FlightType.SEAD: ingress = builder.ingress_sead(self.package.waypoints.ingress, location) + + elif flight.flight_type is FlightType.DEAD: + ingress = builder.ingress_dead(self.package.waypoints.ingress, + location) else: ingress = builder.ingress_strike(self.package.waypoints.ingress, location) diff --git a/gen/flights/waypointbuilder.py b/gen/flights/waypointbuilder.py index 1e081ee7..ddc76b5f 100644 --- a/gen/flights/waypointbuilder.py +++ b/gen/flights/waypointbuilder.py @@ -168,6 +168,11 @@ class WaypointBuilder: objective: MissionTarget) -> FlightWaypoint: return self._ingress(FlightWaypointType.INGRESS_ESCORT, position, objective) + + def ingress_dead(self, position:Point, + objective: MissionTarget) -> FlightWaypoint: + return self._ingress(FlightWaypointType.INGRESS_DEAD, position, + objective) def ingress_sead(self, position: Point, objective: MissionTarget) -> FlightWaypoint: