def preferred_patrol_altitude(self) -> Distance: if self.patrol_altitude is not None: return self.patrol_altitude else: # Estimate based on max speed. # Aircaft with max speed 600 kph will prefer patrol at 10 000 ft # Aircraft with max speed 2800 kph will prefer pratrol at 33 000 ft altitude_for_lowest_speed = feet(10 * 1000) altitude_for_highest_speed = feet(33 * 1000) lowest_speed = kph(600) highest_speed = kph(2800) factor = (self.max_speed - lowest_speed).kph / (highest_speed - lowest_speed).kph altitude = ( altitude_for_lowest_speed + (altitude_for_highest_speed - altitude_for_lowest_speed) * factor) logging.debug( f"Preferred patrol altitude for {self.dcs_unit_type.id}: {altitude.feet}" ) rounded_altitude = feet(round(1000 * round(altitude.feet / 1000))) return max( altitude_for_lowest_speed, min(altitude_for_highest_speed, rounded_altitude), )
def build(self) -> RtbLayout: if not isinstance(self.flight.state, InFlight): raise RuntimeError(f"Cannot abort {self} because it is not in flight") current_position = self.flight.state.estimate_position() current_altitude, altitude_reference = self.flight.state.estimate_altitude() altitude_is_agl = self.flight.unit_type.dcs_unit_type.helicopter altitude = ( feet(1500) if altitude_is_agl else self.flight.unit_type.preferred_patrol_altitude ) builder = WaypointBuilder(self.flight, self.flight.coalition) abort_point = builder.nav( current_position, current_altitude, altitude_reference == "RADIO" ) abort_point.name = "ABORT AND RTB" abort_point.pretty_name = "Abort and RTB" abort_point.description = "Abort mission and return to base" return RtbLayout( departure=builder.takeoff(self.flight.departure), abort_location=abort_point, nav_to_destination=builder.nav_path( current_position, self.flight.arrival.position, altitude, altitude_is_agl, ), arrival=builder.land(self.flight.arrival), divert=builder.divert(self.flight.divert), bullseye=builder.bullseye(), )
def build(self) -> PatrollingLayout: location = self.package.target if isinstance(location, FrontLine): raise InvalidObjectiveLocation(self.flight.flight_type, location) start_pos, end_pos = self.cap_racetrack_for_objective(location, barcap=True) preferred_alt = self.flight.unit_type.preferred_patrol_altitude randomized_alt = preferred_alt + feet(random.randint(-2, 1) * 1000) patrol_alt = max( self.doctrine.min_patrol_altitude, min(self.doctrine.max_patrol_altitude, randomized_alt), ) builder = WaypointBuilder(self.flight, self.coalition) start, end = builder.race_track(start_pos, end_pos, patrol_alt) return PatrollingLayout( departure=builder.takeoff(self.flight.departure), nav_to=builder.nav_path(self.flight.departure.position, start.position, patrol_alt), nav_from=builder.nav_path(end.position, self.flight.arrival.position, patrol_alt), patrol_start=start, patrol_end=end, arrival=builder.land(self.flight.arrival), divert=builder.divert(self.flight.divert), bullseye=builder.bullseye(), )
def build(self) -> TarCapLayout: location = self.package.target preferred_alt = self.flight.unit_type.preferred_patrol_altitude randomized_alt = preferred_alt + feet(random.randint(-2, 1) * 1000) patrol_alt = max( self.doctrine.min_patrol_altitude, min(self.doctrine.max_patrol_altitude, randomized_alt), ) builder = WaypointBuilder(self.flight, self.coalition) orbit0p, orbit1p = self.cap_racetrack_for_objective(location, barcap=False) start, end = builder.race_track(orbit0p, orbit1p, patrol_alt) refuel = None if self.package.waypoints is not None: refuel = builder.refuel(self.package.waypoints.refuel) return TarCapLayout( departure=builder.takeoff(self.flight.departure), nav_to=builder.nav_path( self.flight.departure.position, orbit0p, patrol_alt ), nav_from=builder.nav_path( orbit1p, self.flight.arrival.position, patrol_alt ), patrol_start=start, patrol_end=end, refuel=refuel, arrival=builder.land(self.flight.arrival), divert=builder.divert(self.flight.divert), bullseye=builder.bullseye(), )
def from_data(cls, data: dict[str, Any]) -> PatrolConfig: altitude = data.get("altitude", None) speed = data.get("speed", None) return PatrolConfig( feet(altitude) if altitude is not None else None, knots(speed) if speed is not None else None, )
def build(self) -> PatrollingLayout: racetrack_half_distance = nautical_miles(20).meters location = self.package.target closest_boundary = self.threat_zones.closest_boundary( location.position) heading_to_threat_boundary = Heading.from_degrees( location.position.heading_between_point(closest_boundary)) distance_to_threat = meters( location.position.distance_to_point(closest_boundary)) orbit_heading = heading_to_threat_boundary # Station 70nm outside the threat zone. threat_buffer = nautical_miles(70) if self.threat_zones.threatened(location.position): orbit_distance = distance_to_threat + threat_buffer else: orbit_distance = distance_to_threat - threat_buffer racetrack_center = location.position.point_from_heading( orbit_heading.degrees, orbit_distance.meters) racetrack_start = racetrack_center.point_from_heading( orbit_heading.right.degrees, racetrack_half_distance) racetrack_end = racetrack_center.point_from_heading( orbit_heading.left.degrees, racetrack_half_distance) builder = WaypointBuilder(self.flight, self.coalition) tanker_type = self.flight.unit_type if tanker_type.patrol_altitude is not None: altitude = tanker_type.patrol_altitude else: altitude = feet(21000) racetrack = builder.race_track(racetrack_start, racetrack_end, altitude) return PatrollingLayout( departure=builder.takeoff(self.flight.departure), nav_to=builder.nav_path(self.flight.departure.position, racetrack_start, altitude), nav_from=builder.nav_path(racetrack_end, self.flight.arrival.position, altitude), patrol_start=racetrack[0], patrol_end=racetrack[1], arrival=builder.land(self.flight.arrival), divert=builder.divert(self.flight.divert), bullseye=builder.bullseye(), )
def build(self) -> AirliftLayout: cargo = self.flight.cargo if cargo is None: raise PlanningError( "Cannot plan transport mission for flight with no cargo." ) altitude = feet(1500) altitude_is_agl = True builder = WaypointBuilder(self.flight, self.coalition) pickup = None nav_to_pickup = [] if cargo.origin != self.flight.departure: pickup = builder.pickup(cargo.origin) nav_to_pickup = builder.nav_path( self.flight.departure.position, cargo.origin.position, altitude, altitude_is_agl, ) return AirliftLayout( departure=builder.takeoff(self.flight.departure), nav_to_pickup=nav_to_pickup, pickup=pickup, nav_to_drop_off=builder.nav_path( cargo.origin.position, cargo.next_stop.position, altitude, altitude_is_agl, ), drop_off=builder.drop_off(cargo.next_stop), nav_to_home=builder.nav_path( cargo.origin.position, self.flight.arrival.position, altitude, altitude_is_agl, ), arrival=builder.land(self.flight.arrival), divert=builder.divert(self.flight.divert), bullseye=builder.bullseye(), )
def build(self) -> PatrollingLayout: package_waypoints = self.package.waypoints assert package_waypoints is not None racetrack_half_distance = Distance.from_nautical_miles(20).meters racetrack_center = package_waypoints.refuel split_heading = Heading.from_degrees( racetrack_center.heading_between_point(package_waypoints.split)) home_heading = split_heading.opposite racetrack_start = racetrack_center.point_from_heading( split_heading.degrees, racetrack_half_distance) racetrack_end = racetrack_center.point_from_heading( home_heading.degrees, racetrack_half_distance) builder = WaypointBuilder(self.flight, self.coalition) tanker_type = self.flight.unit_type if tanker_type.patrol_altitude is not None: altitude = tanker_type.patrol_altitude else: altitude = feet(21000) racetrack = builder.race_track(racetrack_start, racetrack_end, altitude) return PatrollingLayout( departure=builder.takeoff(self.flight.departure), nav_to=builder.nav_path(self.flight.departure.position, racetrack_start, altitude), nav_from=builder.nav_path(racetrack_end, self.flight.arrival.position, altitude), patrol_start=racetrack[0], patrol_end=racetrack[1], arrival=builder.land(self.flight.arrival), divert=builder.divert(self.flight.divert), bullseye=builder.bullseye(), )
def build(self) -> FerryLayout: if self.flight.departure == self.flight.arrival: raise PlanningError( f"Cannot plan ferry self.flight: departure and arrival are both " f"{self.flight.departure}") altitude_is_agl = self.flight.unit_type.dcs_unit_type.helicopter altitude = (feet(1500) if altitude_is_agl else self.flight.unit_type.preferred_patrol_altitude) builder = WaypointBuilder(self.flight, self.coalition) return FerryLayout( departure=builder.takeoff(self.flight.departure), nav_to_destination=builder.nav_path( self.flight.departure.position, self.flight.arrival.position, altitude, altitude_is_agl, ), arrival=builder.land(self.flight.arrival), divert=builder.divert(self.flight.divert), bullseye=builder.bullseye(), )
def generate_trigger_zone(self, scenery: SceneryGroundObject) -> TriggerZone: zone = scenery.zone # Align the trigger zones to the faction color on the DCS briefing/F10 map. if scenery.is_friendly(to_player=True): color = {1: 0.2, 2: 0.7, 3: 1, 4: 0.15} else: color = {1: 1, 2: 0.2, 3: 0.2, 4: 0.15} # Create the smallest valid size trigger zone (16 feet) so that risk of overlap is minimized. # As long as the triggerzone is over the scenery object, we're ok. smallest_valid_radius = feet(16).meters return self.m.triggers.add_triggerzone( zone.position, smallest_valid_radius, zone.hidden, zone.name, color, zone.properties, )
from game.ato.traveltime import GroundSpeed from game.naming import namegen from game.theater import Airfield, ControlPoint, Fob, NavalControlPoint, OffMapSpawn from game.utils import feet, meters WARM_START_HELI_ALT = meters(500) WARM_START_ALTITUDE = meters(3000) # In-flight spawns are MSL for the first waypoint (this can maybe be changed to AGL, but # AGL waypoints have different piloting behavior, so we need to check whether that's # safe to do first), so spawn them high enough that they're unlikely to be near (or # under) the ground, or any nearby obstacles. The highest airfield in DCS is Kerman in # PG at 5700ft. This could still be too low if there are tall obstacles near the # airfield, but the lowest we can push this the better to avoid spawning helicopters # well above the altitude for WP1. MINIMUM_MID_MISSION_SPAWN_ALTITUDE = feet(6000) RTB_ALTITUDE = meters(800) RTB_DISTANCE = 5000 HELI_ALT = 500 class FlightGroupSpawner: def __init__( self, flight: Flight, country: Country, mission: Mission, helipads: dict[ControlPoint, StaticGroup], ) -> None: self.flight = flight
cap_engagement_range: Distance cas_duration: timedelta sweep_distance: Distance ground_unit_procurement_ratios: GroundUnitProcurementRatios MODERN_DOCTRINE = Doctrine( cap=True, cas=True, sead=True, strike=True, antiship=True, rendezvous_altitude=feet(25000), hold_distance=nautical_miles(15), push_distance=nautical_miles(20), join_distance=nautical_miles(20), split_distance=nautical_miles(20), ingress_egress_distance=nautical_miles(45), ingress_altitude=feet(20000), egress_altitude=feet(20000), min_patrol_altitude=feet(15000), max_patrol_altitude=feet(33000), pattern_altitude=feet(5000), cap_duration=timedelta(minutes=30), cap_min_track_length=nautical_miles(15), cap_max_track_length=nautical_miles(40), cap_min_distance_from_cp=nautical_miles(10), cap_max_distance_from_cp=nautical_miles(40),