mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Implement ferry flights for squadron transfers.
Fixes https://github.com/dcs-liberation/dcs_liberation/issues/1145
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -183,6 +183,7 @@ class Package:
|
||||
FlightType.TARCAP,
|
||||
FlightType.BARCAP,
|
||||
FlightType.AEWC,
|
||||
FlightType.FERRY,
|
||||
FlightType.REFUELING,
|
||||
FlightType.SWEEP,
|
||||
FlightType.ESCORT,
|
||||
|
||||
@@ -70,6 +70,7 @@ class FlightType(Enum):
|
||||
TRANSPORT = "Transport"
|
||||
SEAD_ESCORT = "SEAD Escort"
|
||||
REFUELING = "Refueling"
|
||||
FERRY = "Ferry"
|
||||
|
||||
def __str__(self) -> str:
|
||||
return self.value
|
||||
|
||||
@@ -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]:
|
||||
|
||||
Reference in New Issue
Block a user