2023-08-15 21:50:20 +02:00

133 lines
4.5 KiB
Python

from __future__ import annotations
from datetime import timedelta
from typing import Type
from .airassault import AirAssaultLayout
from .airlift import AirliftLayout
from .formationattack import (
FormationAttackBuilder,
FormationAttackFlightPlan,
FormationAttackLayout,
)
from .waypointbuilder import WaypointBuilder
from .. import FlightType
from ..traveltime import TravelTime, GroundSpeed
from ...utils import feet
class EscortFlightPlan(FormationAttackFlightPlan):
@property
def push_time(self) -> timedelta:
hold2join_time = (
TravelTime.between_points(
self.layout.hold.position,
self.layout.join.position,
GroundSpeed.for_flight(self.flight, self.layout.hold.alt),
)
if self.layout.hold is not None
else timedelta(0)
)
return self.join_time - hold2join_time
@staticmethod
def builder_type() -> Type[Builder]:
return Builder
class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
def layout(self) -> FormationAttackLayout:
assert self.package.waypoints is not None
builder = WaypointBuilder(self.flight, self.coalition)
ingress, target = builder.escort(
self.package.waypoints.ingress, self.package.target
)
ingress.only_for_player = True
target.only_for_player = True
if not self.primary_flight_is_air_assault:
hold = builder.hold(self._hold_point())
elif self.package.primary_flight is not None:
fp = self.package.primary_flight.flight_plan
assert isinstance(fp.layout, AirAssaultLayout)
assert fp.layout.pickup is not None
hold = builder.hold(fp.layout.pickup.position)
join = builder.join(self.package.waypoints.join)
split = builder.split(self.package.waypoints.split)
ingress_alt = self.doctrine.ingress_altitude
initial = builder.escort_hold(
target.position
if builder.flight.is_helo
else self.package.waypoints.initial,
min(feet(500), ingress_alt) if builder.flight.is_helo else ingress_alt,
)
pf = self.package.primary_flight
if pf and pf.flight_type in [FlightType.AIR_ASSAULT, FlightType.TRANSPORT]:
layout = pf.flight_plan.layout
assert isinstance(layout, AirAssaultLayout) or isinstance(
layout, AirliftLayout
)
if isinstance(layout, AirliftLayout):
join = builder.join(layout.departure.position)
else:
join = builder.join(layout.ingress.position)
if layout.pickup:
join = builder.join(layout.pickup.position)
split = builder.split(layout.arrival.position)
if layout.drop_off:
initial = builder.escort_hold(
layout.drop_off.position,
min(feet(200), ingress_alt)
if builder.flight.is_helo
else ingress_alt,
)
refuel = None
if not self.flight.is_helo:
refuel = builder.refuel(self.package.waypoints.refuel)
departure = builder.takeoff(self.flight.departure)
if hold:
nav_to = builder.nav_path(
hold.position, join.position, self.doctrine.ingress_altitude
)
else:
nav_to = builder.nav_path(
departure.position, join.position, self.doctrine.ingress_altitude
)
if refuel:
nav_from = builder.nav_path(
refuel.position,
self.flight.arrival.position,
self.doctrine.ingress_altitude,
)
else:
nav_from = builder.nav_path(
split.position,
self.flight.arrival.position,
self.doctrine.ingress_altitude,
)
return FormationAttackLayout(
departure=departure,
hold=hold,
nav_to=nav_to,
join=join,
ingress=ingress,
initial=initial,
targets=[target],
split=split,
refuel=refuel,
nav_from=nav_from,
arrival=builder.land(self.flight.arrival),
divert=builder.divert(self.flight.divert),
bullseye=builder.bullseye(),
)
def build(self) -> EscortFlightPlan:
return EscortFlightPlan(self.flight, self.layout())