From 09617adc5681844fbe32e23b8df26cc46b6c1d18 Mon Sep 17 00:00:00 2001 From: Raffson Date: Thu, 1 May 2025 19:52:52 +0200 Subject: [PATCH] Passive defense for non-air-to-air flights in package with jammer --- .../aircraft/aircraftgenerator.py | 40 ++++++++++++- .../aircraft/waypoints/joinpoint.py | 5 +- .../waypoints/pydcswaypointbuilder.py | 10 +--- .../aircraft/waypoints/splitpoint.py | 5 +- game/missiongenerator/missiongenerator.py | 57 ++++++++++++------- 5 files changed, 77 insertions(+), 40 deletions(-) diff --git a/game/missiongenerator/aircraft/aircraftgenerator.py b/game/missiongenerator/aircraft/aircraftgenerator.py index 4ae61076..06b625cd 100644 --- a/game/missiongenerator/aircraft/aircraftgenerator.py +++ b/game/missiongenerator/aircraft/aircraftgenerator.py @@ -13,6 +13,7 @@ from dcs.datalinks.datalink import DataLinkType from dcs.datalinks.datalinkbase import DataLinkSettingsWithFlightLead from dcs.datalinks.link16 import Link16Network, ViperLink16NetworkMemberLink from dcs.mission import Mission +from dcs.task import RunScript from dcs.terrain.terrain import NoParkingSlotError from dcs.triggers import TriggerOnce, Event from dcs.unit import Skill @@ -341,16 +342,49 @@ class AircraftGenerator: def _track_ewrj_flight(self, flight: Flight, group: FlyingGroup[Any]) -> None: if not self.ewrj_package_dict.get(id(flight.package)): self.ewrj_package_dict[id(flight.package)] = [] + added = False if ( - flight.package.primary_flight - and flight is flight.package.primary_flight - or flight.client_count + not flight.flight_type.is_air_to_air + and any( + [ + wpt + for wpt in group.points + if wpt.name in ["JOIN", "SPLIT", "RACETRACK START", "RACETRACK END"] + and any( + [ + t + for t in wpt.tasks + if isinstance(t, RunScript) + and ( + "Djamming" in t.params["action"]["params"]["command"] + or "EWjamm" in t.params["action"]["params"]["command"] + ) + ] + ) + ] + ) and ( not self.need_ecm or flight.any_member_has_weapon_of_type(WeaponType.JAMMER) + or flight.squadron.aircraft.has_built_in_ecm ) ): self.ewrj_package_dict[id(flight.package)].append(group) + added = True + if ( + added + or not flight.flight_type.is_air_to_air + and self.ewrj_package_dict[id(flight.package)] + ): + for f in flight.package.flights: + if f is flight or f.group_id == 0 or f.flight_type.is_air_to_air: + continue + g = self.mission.find_group_by_id(f.group_id) + if ( + isinstance(g, FlyingGroup) + and g not in self.ewrj_package_dict[id(flight.package)] + ): + self.ewrj_package_dict[id(flight.package)].append(g) def _reserve_frequencies_and_tacan(self, ato: AirTaskingOrder) -> None: for package in ato.packages: diff --git a/game/missiongenerator/aircraft/waypoints/joinpoint.py b/game/missiongenerator/aircraft/waypoints/joinpoint.py index 7dfb8d00..c52c7086 100644 --- a/game/missiongenerator/aircraft/waypoints/joinpoint.py +++ b/game/missiongenerator/aircraft/waypoints/joinpoint.py @@ -9,7 +9,6 @@ from dcs.task import ( OptFormation, Targets, SetUnlimitedFuelCommand, - OptReactOnThreat, ) from game.ato import FlightType @@ -66,9 +65,7 @@ class JoinPointBuilder(PydcsWaypointBuilder): ai_jammer = settings.plugin_option("ewrj.ai_jammer_enabled") if settings.plugins.get("ewrj") and ai_jammer: self.offensive_jamming(waypoint, "start") - if self.defensive_jamming(waypoint, "start"): - reaction = OptReactOnThreat(OptReactOnThreat.Values.PassiveDefense) - waypoint.tasks.append(reaction) + self.defensive_jamming(waypoint, "start") if self.flight.flight_type == FlightType.SEAD_ESCORT: self.handle_sead_escort(doctrine, waypoint) diff --git a/game/missiongenerator/aircraft/waypoints/pydcswaypointbuilder.py b/game/missiongenerator/aircraft/waypoints/pydcswaypointbuilder.py index 16b2909c..9daeaaeb 100644 --- a/game/missiongenerator/aircraft/waypoints/pydcswaypointbuilder.py +++ b/game/missiongenerator/aircraft/waypoints/pydcswaypointbuilder.py @@ -159,11 +159,10 @@ class PydcsWaypointBuilder: ): self.group.add_nav_target_point(self.waypoint.position, "IP") - def defensive_jamming(self, waypoint: MovingPoint, action: str) -> bool: + def defensive_jamming(self, waypoint: MovingPoint, action: str) -> None: # Explodes incoming missiles within the jamming bubble through the EW-Jamming script settings = self.flight.coalition.game.settings ecm_required = settings.plugin_option("ewrj.ecm_required") - has_jammers = False for unit, member in zip(self.group.units, self.flight.iter_members()): has_jammer = member.loadout.has_weapon_of_type(WeaponType.JAMMER) built_in_jammer = self.flight.squadron.aircraft.has_built_in_ecm @@ -173,14 +172,11 @@ class PydcsWaypointBuilder: script_content = f'{action}Djamming("{unit.name}")' jamming_script = RunScript(script_content) waypoint.tasks.append(jamming_script) - has_jammers = True - return has_jammers - def offensive_jamming(self, waypoint: MovingPoint, action: str) -> bool: + def offensive_jamming(self, waypoint: MovingPoint, action: str) -> None: # Silences enemy radars through the EW-Jamming script settings = self.flight.coalition.game.settings ecm_required = settings.plugin_option("ewrj.ecm_required") - has_jammers = False for unit, member in zip(self.group.units, self.flight.iter_members()): has_jammer = member.loadout.has_weapon_of_type(WeaponType.JAMMER) built_in_jammer = self.flight.squadron.aircraft.has_built_in_ecm @@ -190,5 +186,3 @@ class PydcsWaypointBuilder: script_content = f'{action}EWjamm("{unit.name}")' stop_jamming_script = RunScript(script_content) waypoint.tasks.append(stop_jamming_script) - has_jammers = True - return has_jammers diff --git a/game/missiongenerator/aircraft/waypoints/splitpoint.py b/game/missiongenerator/aircraft/waypoints/splitpoint.py index cfa14059..a14fa896 100644 --- a/game/missiongenerator/aircraft/waypoints/splitpoint.py +++ b/game/missiongenerator/aircraft/waypoints/splitpoint.py @@ -5,7 +5,6 @@ from dcs.task import ( SetUnlimitedFuelCommand, SwitchWaypoint, RunScript, - OptReactOnThreat, ) from game.ato import FlightType @@ -58,6 +57,4 @@ class SplitPointBuilder(PydcsWaypointBuilder): ai_jammer = settings.plugin_option("ewrj.ai_jammer_enabled") if settings.plugins.get("ewrj") and ai_jammer: self.offensive_jamming(waypoint, "stop") - if self.defensive_jamming(waypoint, "stop"): - reaction = OptReactOnThreat(OptReactOnThreat.Values.EvadeFire) - waypoint.tasks.append(reaction) + self.defensive_jamming(waypoint, "stop") diff --git a/game/missiongenerator/missiongenerator.py b/game/missiongenerator/missiongenerator.py index 3957641a..f9782118 100644 --- a/game/missiongenerator/missiongenerator.py +++ b/game/missiongenerator/missiongenerator.py @@ -9,6 +9,7 @@ import dcs.lua from dcs import Mission, Point from dcs.coalition import Coalition from dcs.countries import country_dict +from dcs.point import MovingPoint from dcs.task import OptReactOnThreat from dcs.terrain import Airport from dcs.unit import Static @@ -131,28 +132,42 @@ class MissionGenerator: return self.unit_map @staticmethod - def _configure_ewrj(gen: AircraftGenerator) -> None: + def _configure_react_to_threat_for_ew_jamming_packages( + gen: AircraftGenerator, + ) -> None: for groups in gen.ewrj_package_dict.values(): - optrot = [ - task - for task in groups[0].points[0].tasks - if isinstance(task, OptReactOnThreat) - ][0] - assert isinstance(optrot, OptReactOnThreat) - if ( - len(groups) == 1 - and optrot.value != OptReactOnThreat.Values.PassiveDefense - ): - # primary flight with no EWR-Jamming capability - continue for group in groups: - tasks = group.points[0].tasks - for i in range(len(tasks)): - if isinstance(tasks[i], OptReactOnThreat): - tasks[i] = OptReactOnThreat( - OptReactOnThreat.Values.PassiveDefense - ) - break + start_point = [ + p for p in group.points if p.name in ["JOIN", "RACETRACK START"] + ] + if not start_point: + sp = group.points[0] + else: + sp = start_point[0] + MissionGenerator.set_react_to_threat( + OptReactOnThreat.Values.PassiveDefense, sp + ) + stop_point = [ + p for p in group.points if p.name in ["SPLIT", "RACETRACK END"] + ] + if not stop_point: + sp = group.points[0] + else: + sp = stop_point[0] + MissionGenerator.set_react_to_threat( + OptReactOnThreat.Values.EvadeFire, sp + ) + + @staticmethod + def set_react_to_threat( + optrot: OptReactOnThreat.Values, start_point: MovingPoint + ) -> None: + tasks = start_point.tasks + for i in range(len(tasks)): + if isinstance(tasks[i], OptReactOnThreat): + tasks[i] = OptReactOnThreat(optrot) + return + tasks.append(OptReactOnThreat(optrot)) def setup_mission_coalitions(self) -> None: self.mission.coalition["blue"] = Coalition( @@ -291,7 +306,7 @@ class MissionGenerator: flight.aircraft_type.assign_channels_for_flight(flight, self.mission_data) if self.game.settings.plugins.get("ewrj"): - self._configure_ewrj(aircraft_generator) + self._configure_react_to_threat_for_ew_jamming_packages(aircraft_generator) def generate_destroyed_units(self) -> None: """Add destroyed units to the Mission"""