from __future__ import annotations from datetime import timedelta from typing import Type from game.ato.flightplans.ibuilder import IBuilder from game.ato.flightplans.patrolling import PatrollingFlightPlan, PatrollingLayout from game.ato.flightplans.waypointbuilder import WaypointBuilder from game.utils import Distance, Heading, Speed, feet, knots, meters, nautical_miles class AewcFlightPlan(PatrollingFlightPlan[PatrollingLayout]): @property def patrol_duration(self) -> timedelta: return timedelta(hours=4) @property def patrol_speed(self) -> Speed: altitude = self.layout.patrol_start.alt if self.flight.unit_type.preferred_patrol_speed(altitude) is not None: return self.flight.unit_type.preferred_patrol_speed(altitude) return knots(390) @property def engagement_distance(self) -> Distance: # TODO: Factor out a common base of the combat and non-combat race-tracks. # No harm in setting this, but we ought to clean up a bit. return meters(0) @staticmethod def builder_type() -> Type[Builder]: return Builder class Builder(IBuilder[AewcFlightPlan, PatrollingLayout]): def layout(self) -> PatrollingLayout: racetrack_half_distance = nautical_miles(30).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 80nm outside the threat zone. threat_buffer = nautical_miles( self.flight.coalition.game.settings.aewc_threat_buffer_min_distance ) 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) if self.flight.unit_type.patrol_altitude is not None: altitude = self.flight.unit_type.patrol_altitude else: altitude = feet(25000) 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) -> AewcFlightPlan: return AewcFlightPlan(self.flight, self.layout())