def configure_escort_tasks(waypoint: MovingPoint, target_types: List[Type[TargetType]]) -> None: # Ideally we would use the escort mission type and escort task to have # the AI automatically but the AI only escorts AI flights while they are # traveling between waypoints. When an AI flight performs an attack # (such as attacking the mission target), AI escorts wander aimlessly # until the escorted group resumes its flight plan. # # As such, we instead use the Search Then Engage task, which is an # enroute task that causes the AI to follow their flight plan and engage # enemies of the set type within a certain distance. The downside to # this approach is that AI escorts are no longer related to the group # they are escorting, aside from the fact that they fly a similar flight # plan at the same time. With Escort, the escorts will follow the # escorted group out of the area. The strike element may or may not fly # directly over the target, and they may or may not require multiple # attack runs. For the escort flight we must just assume a flight plan # for the escort to fly. If the strike flight doesn't need to overfly # the target, the escorts are needlessly going in harms way. If the # strike flight needs multiple passes, the escorts may leave before the # escorted aircraft do. # # Another possible option would be to use Search Then Engage for join -> # ingress and egress -> split, but use a Search Then Engage in Zone task # for the target area that is set to end on a flag flip that occurs when # the strike aircraft finish their attack task. # # https://forums.eagle.ru/topic/251798-options-for-alternate-ai-escort-behavior waypoint.add_task( ControlledTask( EngageTargets( # TODO: From doctrine. max_distance=int(nautical_miles(30).meters), targets=target_types, )))
def add_tasks(self, waypoint: MovingPoint) -> None: if isinstance(self.flight.flight_plan, CasFlightPlan): waypoint.add_task( EngageTargetsInZone( position=self.flight.flight_plan.layout.target.position, radius=int( self.flight.flight_plan.engagement_distance.meters), targets=[ Targets.All.GroundUnits.GroundVehicles, Targets.All.GroundUnits.AirDefence.AAA, Targets.All.GroundUnits.Infantry, ], )) else: logging.error( "No CAS waypoint found. Falling back to search and engage") waypoint.add_task( EngageTargets( max_distance=int(nautical_miles(10).meters), targets=[ Targets.All.GroundUnits.GroundVehicles, Targets.All.GroundUnits.AirDefence.AAA, Targets.All.GroundUnits.Infantry, ], ))
def add_tasks(self, waypoint: MovingPoint) -> None: loiter = ControlledTask( OrbitAction(altitude=waypoint.alt, pattern=OrbitAction.OrbitPattern.Circle) ) if not isinstance(self.flight.flight_plan, LoiterFlightPlan): flight_plan_type = self.flight.flight_plan.__class__.__name__ logging.error( f"Cannot configure hold for for {self.flight} because " f"{flight_plan_type} does not define a push time. AI will push " "immediately and may flight unsuitable speeds." ) return push_time = self.flight.flight_plan.push_time self.waypoint.departure_time = push_time loiter.stop_after_time( int((push_time - self.elapsed_mission_time).total_seconds()) ) waypoint.add_task(loiter) waypoint.add_task(OptFormation.finger_four_close())
def configure_refueling_actions(self, waypoint: MovingPoint) -> None: waypoint.add_task(Tanker()) if self.flight.unit_type.dcs_unit_type.tacan: tanker_info = self.air_support.tankers[-1] tacan = tanker_info.tacan tacan_callsign = { "Texaco": "TEX", "Arco": "ARC", "Shell": "SHL", }.get(tanker_info.callsign) waypoint.add_task( ActivateBeaconCommand( tacan.number, tacan.band.value, tacan_callsign, bearing=True, unit_id=self.group.units[0].id, aa=True, ))
def add_tasks(self, waypoint: MovingPoint) -> None: 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.") return # NB: It's important that the engage task comes before the orbit task. # Though they're on the same waypoint, if the orbit task comes first it # is their first priority and they will not engage any targets because # they're fully focused on orbiting. If the STE task is first, they will # engage targets if available and orbit if they find nothing to shoot. if self.flight.flight_type is FlightType.REFUELING: self.configure_refueling_actions(waypoint) # TODO: Move the properties of this task into the flight plan? # CAP is the only current user of this so it's not a big deal, but might # be good to make this usable for things like BAI when we add that # 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=engagement_distance, targets=[Targets.All.Air])) orbit = OrbitAction( altitude=waypoint.alt, pattern=OrbitAction.OrbitPattern.RaceTrack, speed=int(flight_plan.patrol_speed.kph), ) racetrack = ControlledTask(orbit) self.set_waypoint_tot(waypoint, flight_plan.patrol_start_time) loiter_duration = flight_plan.patrol_end_time - self.elapsed_mission_time racetrack.stop_after_time(int(loiter_duration.total_seconds())) waypoint.add_task(racetrack)
def add_tasks(self, waypoint: MovingPoint) -> None: waypoint.add_task(RefuelingTaskAction()) return super().add_tasks(waypoint)