示例#1
0
 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),
         )
示例#2
0
    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(),
        )
示例#3
0
    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(),
        )
示例#4
0
    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(),
        )
示例#5
0
 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(),
        )
示例#7
0
    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(),
        )
示例#8
0
    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(),
        )
示例#9
0
    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(),
        )
示例#10
0
    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
示例#12
0
    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),