Recovery tanker support (#429)

* fix conflict

* squash bugs and reuse patrol layout

* fix tanker tacan and formatting

* fix unlimited fuel option

* update pretense for tanker changes

* reuse refueling flight plan and bugfix for sunken carrier

changelog

* remove unitmap dependency

* formatting and more unit map removal

* more formatting

* typing and black

* keep tanker out of clouds

* fix if there are no clouds

* better cloud handling

* groundwork for recovery task

* remove changes to game/commander

* Finishing up recovery tankers

---------

Co-authored-by: Raffson <Raffson@users.noreply.github.com>
This commit is contained in:
Druss99
2024-12-22 23:39:10 -05:00
committed by GitHub
parent a4671571bc
commit dd7e4c908e
46 changed files with 395 additions and 25 deletions

View File

@@ -60,6 +60,16 @@ class CustomFlightPlan(FlightPlan[CustomLayout]):
def mission_departure_time(self) -> datetime:
return self.package.time_over_target
@property
def landing_time(self) -> datetime:
arrival = (
self.layout.custom_waypoints[-1]
if self.layout.custom_waypoints
else self.layout.departure
)
return_time = self.total_time_between_waypoints(self.tot_waypoint, arrival)
return self.tot + return_time
class Builder(IBuilder[CustomFlightPlan, CustomLayout]):
def __init__(

View File

@@ -296,6 +296,10 @@ class FlightPlan(ABC, Generic[LayoutT]):
"""The time that the mission is complete and the flight RTBs."""
raise NotImplementedError
@property
def landing_time(self) -> datetime:
raise NotImplementedError
@self_type_guard
def is_loiter(self, flight_plan: FlightPlan[Any]) -> TypeGuard[LoiterFlightPlan]:
return False

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
from typing import Any, TYPE_CHECKING, Type
from game.ato import FlightType
from game.theater.controlpoint import NavalControlPoint
from .aewc import AewcFlightPlan
from .airassault import AirAssaultFlightPlan
from .airlift import AirliftFlightPlan
@@ -22,6 +23,7 @@ from .planningerror import PlanningError
from .pretensecargo import PretenseCargoFlightPlan
from .sead import SeadFlightPlan
from .seadsweep import SeadSweepFlightPlan
from .shiprecoverytanker import RecoveryTankerFlightPlan
from .strike import StrikeFlightPlan
from .sweep import SweepFlightPlan
from .tarcap import TarCapFlightPlan
@@ -64,6 +66,7 @@ class FlightPlanBuilderTypes:
FlightType.AIR_ASSAULT: AirAssaultFlightPlan.builder_type(),
FlightType.PRETENSE_CARGO: PretenseCargoFlightPlan.builder_type(),
FlightType.ARMED_RECON: ArmedReconFlightPlan.builder_type(),
FlightType.RECOVERY: RecoveryTankerFlightPlan.builder_type(),
}
try:
return builder_dict[flight.flight_type]

View File

@@ -0,0 +1,61 @@
from __future__ import annotations
from datetime import timedelta
from typing import Type
from game.ato.flightplans.ibuilder import IBuilder
from game.ato.flightplans.waypointbuilder import WaypointBuilder
from .patrolling import PatrollingLayout
from .refuelingflightplan import RefuelingFlightPlan
from .. import FlightWaypoint
from ...utils import knots
class RecoveryTankerFlightPlan(RefuelingFlightPlan):
@staticmethod
def builder_type() -> Type[Builder]:
return Builder
@property
def patrol_duration(self) -> timedelta:
return self.flight.coalition.game.settings.desired_tanker_on_station_time
@property
def tot_waypoint(self) -> FlightWaypoint:
return self.layout.departure
class Builder(IBuilder[RecoveryTankerFlightPlan, PatrollingLayout]):
def layout(self) -> PatrollingLayout:
builder = WaypointBuilder(self.flight)
altitude = builder.get_patrol_altitude
station_time = self.coalition.game.settings.desired_tanker_on_station_time
time_to_landing = station_time.total_seconds()
hdg = (self.coalition.game.conditions.weather.wind.at_0m.direction + 180) % 360
recovery_ship = self.package.target.position.point_from_heading(
hdg, time_to_landing * knots(20).meters_per_second
)
recovery_tanker = builder.recovery_tanker(recovery_ship)
patrol_end = builder.race_track_end(recovery_tanker.position, altitude)
patrol_end.only_for_player = True # avoid generating the waypoints
return PatrollingLayout(
departure=builder.takeoff(self.flight.departure),
nav_to=builder.nav_path(
self.flight.departure.position, recovery_ship, altitude
),
nav_from=builder.nav_path(
recovery_ship, self.flight.arrival.position, altitude
),
patrol_start=recovery_tanker,
patrol_end=patrol_end,
arrival=builder.land(self.flight.arrival),
divert=builder.divert(self.flight.divert),
bullseye=builder.bullseye(),
custom_waypoints=list(),
)
def build(self, dump_debug_info: bool = False) -> RecoveryTankerFlightPlan:
return RecoveryTankerFlightPlan(self.flight, self.layout())

View File

@@ -3,6 +3,7 @@ from __future__ import annotations
from abc import ABC
from copy import deepcopy
from dataclasses import dataclass
from datetime import datetime
from typing import TYPE_CHECKING, TypeVar, Optional
from game.ato.flightplans.flightplan import FlightPlan, Layout
@@ -86,3 +87,10 @@ class StandardFlightPlan(FlightPlan[LayoutT], ABC):
others are guaranteed to have certain properties like departure and arrival points,
potentially a divert field, and a bullseye
"""
@property
def landing_time(self) -> datetime:
return_time = self.total_time_between_waypoints(
self.tot_waypoint, self.layout.arrival
)
return self.tot + return_time

View File

@@ -800,3 +800,18 @@ class WaypointBuilder:
x_adj = random.randint(int(-deviation.meters), int(deviation.meters))
y_adj = random.randint(int(-deviation.meters), int(deviation.meters))
return point + Vector2(x_adj, y_adj)
@staticmethod
def recovery_tanker(position: Point) -> FlightWaypoint:
alt_type: AltitudeReference = "BARO"
return FlightWaypoint(
"RECOVERY",
FlightWaypointType.RECOVERY_TANKER,
position,
feet(6000),
alt_type,
description="Recovery tanker for aircraft carriers",
pretty_name="Recovery",
only_for_player=True, # for visual purposes in Retribution only
)

View File

@@ -60,6 +60,7 @@ class FlightType(Enum):
SEAD_SWEEP = "SEAD Sweep" # Reintroduce legacy "engage-whatever-you-can-find" SEAD
PRETENSE_CARGO = "Cargo Transport" # For Pretense campaign AI cargo planes
ARMED_RECON = "Armed Recon"
RECOVERY = "Recovery"
def __str__(self) -> str:
return self.value
@@ -117,6 +118,7 @@ class FlightType(Enum):
FlightType.INTERCEPTION: AirEntity.FIGHTER,
FlightType.OCA_AIRCRAFT: AirEntity.ATTACK_STRIKE,
FlightType.OCA_RUNWAY: AirEntity.ATTACK_STRIKE,
FlightType.RECOVERY: AirEntity.TANKER,
FlightType.REFUELING: AirEntity.TANKER,
FlightType.SEAD: AirEntity.SUPPRESSION_OF_ENEMY_AIR_DEFENCE,
FlightType.SEAD_ESCORT: AirEntity.SUPPRESSION_OF_ENEMY_AIR_DEFENCE,

View File

@@ -52,3 +52,4 @@ class FlightWaypointType(IntEnum):
INGRESS_ANTI_SHIP = 32
INGRESS_SEAD_SWEEP = 33
INGRESS_ARMED_RECON = 34
RECOVERY_TANKER = 35 # Tanker recovery point

View File

@@ -188,6 +188,7 @@ class Package(RadioFrequencyContainer):
FlightType.BARCAP,
FlightType.AEWC,
FlightType.FERRY,
FlightType.RECOVERY,
FlightType.REFUELING,
FlightType.SWEEP,
FlightType.SEAD_ESCORT,