Implement ferry flights for squadron transfers.

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/1145
This commit is contained in:
Dan Albert
2021-08-31 22:14:32 -07:00
parent f9f0b429b6
commit 1a4be911c0
8 changed files with 179 additions and 16 deletions

View File

@@ -57,6 +57,7 @@ from dcs.task import (
Transport,
WeaponType,
TargetType,
Nothing,
)
from dcs.terrain.terrain import Airport, NoParkingSlotError
from dcs.triggers import Event, TriggerOnce, TriggerRule
@@ -1086,6 +1087,23 @@ class AircraftConflictGenerator:
restrict_jettison=True,
)
def configure_ferry(
self,
group: FlyingGroup[Any],
package: Package,
flight: Flight,
dynamic_runways: Dict[str, RunwayData],
) -> None:
group.task = Nothing.name
self._setup_group(group, package, flight, dynamic_runways)
self.configure_behavior(
flight,
group,
react_on_threat=OptReactOnThreat.Values.EvadeFire,
roe=OptROE.Values.WeaponHold,
restrict_jettison=True,
)
def configure_unknown_task(self, group: FlyingGroup[Any], flight: Flight) -> None:
logging.error(f"Unhandled flight type: {flight.flight_type}")
self.configure_behavior(flight, group)
@@ -1130,6 +1148,8 @@ class AircraftConflictGenerator:
self.configure_oca_strike(group, package, flight, dynamic_runways)
elif flight_type == FlightType.TRANSPORT:
self.configure_transport(group, package, flight, dynamic_runways)
elif flight_type == FlightType.FERRY:
self.configure_ferry(group, package, flight, dynamic_runways)
else:
self.configure_unknown_task(group, flight)

View File

@@ -183,6 +183,7 @@ class Package:
FlightType.TARCAP,
FlightType.BARCAP,
FlightType.AEWC,
FlightType.FERRY,
FlightType.REFUELING,
FlightType.SWEEP,
FlightType.ESCORT,

View File

@@ -70,6 +70,7 @@ class FlightType(Enum):
TRANSPORT = "Transport"
SEAD_ESCORT = "SEAD Escort"
REFUELING = "Refueling"
FERRY = "Ferry"
def __str__(self) -> str:
return self.value

View File

@@ -37,10 +37,8 @@ from game.theater.theatergroundobject import (
NavalGroundObject,
BuildingGroundObject,
)
from game.threatzones import ThreatZones
from game.utils import Distance, Heading, Speed, feet, meters, nautical_miles, knots
from .closestairfields import ObjectiveDistanceCache
from .flight import Flight, FlightType, FlightWaypoint, FlightWaypointType
from .traveltime import GroundSpeed, TravelTime
@@ -836,6 +834,39 @@ class AirliftFlightPlan(FlightPlan):
return self.package.time_over_target
@dataclass(frozen=True)
class FerryFlightPlan(FlightPlan):
takeoff: FlightWaypoint
nav_to_destination: list[FlightWaypoint]
land: FlightWaypoint
divert: Optional[FlightWaypoint]
bullseye: FlightWaypoint
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.takeoff
yield from self.nav_to_destination
yield self.land
if self.divert is not None:
yield self.divert
yield self.bullseye
@property
def tot_waypoint(self) -> Optional[FlightWaypoint]:
return self.land
def tot_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
# TOT planning isn't really useful for ferries. They're behind the front
# lines so no need to wait for escorts or for other missions to complete.
return None
def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> Optional[timedelta]:
return None
@property
def mission_departure_time(self) -> timedelta:
return self.package.time_over_target
@dataclass(frozen=True)
class CustomFlightPlan(FlightPlan):
custom_waypoints: List[FlightWaypoint]
@@ -958,6 +989,8 @@ class FlightPlanBuilder:
return self.generate_transport(flight)
elif task == FlightType.REFUELING:
return self.generate_refueling_racetrack(flight)
elif task == FlightType.FERRY:
return self.generate_ferry(flight)
raise PlanningError(f"{task} flight plan generation not implemented")
def regenerate_package_waypoints(self) -> None:
@@ -1244,6 +1277,42 @@ class FlightPlanBuilder:
bullseye=builder.bullseye(),
)
def generate_ferry(self, flight: Flight) -> FerryFlightPlan:
"""Generate a ferry flight at a given location.
Args:
flight: The flight to generate the flight plan for.
"""
if flight.departure == flight.arrival:
raise PlanningError(
f"Cannot plan ferry flight: departure and arrival are both "
f"{flight.departure}"
)
altitude_is_agl = flight.unit_type.dcs_unit_type.helicopter
altitude = (
feet(1500)
if altitude_is_agl
else flight.unit_type.preferred_patrol_altitude
)
builder = WaypointBuilder(flight, self.coalition)
return FerryFlightPlan(
package=self.package,
flight=flight,
takeoff=builder.takeoff(flight.departure),
nav_to_destination=builder.nav_path(
flight.departure.position,
flight.arrival.position,
altitude,
altitude_is_agl,
),
land=builder.land(flight.arrival),
divert=builder.divert(flight.divert),
bullseye=builder.bullseye(),
)
def cap_racetrack_for_objective(
self, location: MissionTarget, barcap: bool
) -> Tuple[Point, Point]: