Recovery tanker follow up (#2659)

Fix timing issues for RecoveryTankerFlightPlan.

AEWC and Refueling can be planned on LHA.
This commit is contained in:
SnappyComebacks 2022-12-20 21:47:50 -07:00 committed by GitHub
parent 22503d4e95
commit 0fd0f0e7c0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 36 additions and 27 deletions

View File

@ -15,6 +15,7 @@ Saves from 6.0.0 are compatible with 6.1.0
* **[Engine]** Support for DCS 2.8.1.34437.
* **[Factions]** Defaulted bluefor modern to use Georgian and Ukrainian liveries for Russian aircraft.
* **[Factions]** Added Peru.
* **[Flight Planning]** AEW&C and Refueling flights are now plannable on LHA carriers.
* **[Flight Planning]** Refueling flights planned on aircraft carriers will act as a recovery tanker for the carrier.
* **[Loadouts]** Adjusted F-15E loadouts.
* **[Mission Generation]** The previous turn will now be saved as last_turn.liberation when submitting mission results. This is often essential for debugging bug reports. **Include this file in the bug report whenever it is available.**

View File

@ -3,8 +3,7 @@ from __future__ import annotations
from typing import Any, TYPE_CHECKING, Type
from game.ato import FlightType
from game.ato.flightplans.shiprecoverytanker import RecoveryTankerFlightPlan
from game.theater.controlpoint import Carrier
from game.theater.controlpoint import NavalControlPoint
from .aewc import AewcFlightPlan
from .airassault import AirAssaultFlightPlan
from .airlift import AirliftFlightPlan
@ -21,6 +20,7 @@ from .ocarunway import OcaRunwayFlightPlan
from .packagerefueling import PackageRefuelingFlightPlan
from .planningerror import PlanningError
from .sead import SeadFlightPlan
from .shiprecoverytanker import RecoveryTankerFlightPlan
from .strike import StrikeFlightPlan
from .sweep import SweepFlightPlan
from .tarcap import TarCapFlightPlan
@ -37,7 +37,7 @@ class FlightPlanBuilderTypes:
if flight.flight_type is FlightType.REFUELING:
target = flight.package.target
if target.is_friendly(flight.squadron.player) and isinstance(
target, Carrier
target, NavalControlPoint
):
return RecoveryTankerFlightPlan.builder_type()
if target.is_friendly(flight.squadron.player) or isinstance(

View File

@ -8,7 +8,6 @@ from game.ato.flightplans.ibuilder import IBuilder
from game.ato.flightplans.standard import StandardLayout
from game.ato.flightplans.waypointbuilder import WaypointBuilder
from game.ato.flightwaypoint import FlightWaypoint
from game.utils import feet
@dataclass(frozen=True)
@ -39,7 +38,7 @@ class RecoveryTankerFlightPlan(StandardFlightPlan[RecoveryTankerLayout]):
@property
def mission_departure_time(self) -> timedelta:
return timedelta(hours=2)
return self.patrol_end_time
@property
def patrol_start_time(self) -> timedelta:
@ -47,7 +46,7 @@ class RecoveryTankerFlightPlan(StandardFlightPlan[RecoveryTankerLayout]):
@property
def patrol_end_time(self) -> timedelta:
return self.tot + self.mission_departure_time
return self.tot + timedelta(hours=2)
def tot_for_waypoint(self, waypoint: FlightWaypoint) -> timedelta | None:
if waypoint == self.tot_waypoint:
@ -56,28 +55,33 @@ class RecoveryTankerFlightPlan(StandardFlightPlan[RecoveryTankerLayout]):
def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> timedelta | None:
if waypoint == self.tot_waypoint:
return self.tot + self.mission_departure_time
return self.mission_departure_time
return None
class Builder(IBuilder[RecoveryTankerFlightPlan, RecoveryTankerLayout]):
def layout(self) -> RecoveryTankerLayout:
# TODO: Propagate the ship position.
ship = self.package.target.position
builder = WaypointBuilder(self.flight, self.coalition)
recovery = builder.recovery_tanker(ship)
# TODO: Propagate the ship position to the Tanker's TOT,
# so that we minimize the tanker's need to catch up to the carrier.
recovery_ship = self.package.target.position
recovery_tanker = builder.recovery_tanker(recovery_ship)
# We don't have per aircraft cruise altitudes, so just reuse patrol altitude?
tanker_type = self.flight.unit_type
altitude = tanker_type.preferred_patrol_altitude
nav_cruise_altitude = tanker_type.preferred_patrol_altitude
return RecoveryTankerLayout(
departure=builder.takeoff(self.flight.departure),
nav_to=builder.nav_path(self.flight.departure.position, ship, altitude),
nav_from=builder.nav_path(ship, self.flight.arrival.position, altitude),
recovery_ship=recovery,
nav_to=builder.nav_path(
self.flight.departure.position, recovery_ship, nav_cruise_altitude
),
nav_from=builder.nav_path(
recovery_ship, self.flight.arrival.position, nav_cruise_altitude
),
recovery_ship=recovery_tanker,
arrival=builder.land(self.flight.arrival),
divert=builder.divert(self.flight.divert),
bullseye=builder.bullseye(),

View File

@ -2,24 +2,27 @@ from dcs.point import MovingPoint
from dcs.task import ActivateBeaconCommand, RecoveryTanker
from game.ato import FlightType
from game.missiongenerator.missiondata import TankerInfo
from game.utils import feet, knots
from .pydcswaypointbuilder import PydcsWaypointBuilder
class RecoveryTankerBuilder(PydcsWaypointBuilder):
def add_tasks(self, waypoint: MovingPoint) -> None:
if self.flight.flight_type == FlightType.REFUELING:
group_id = self._get_carrier_group_id()
speed = knots(250).meters_per_second
altitude = feet(6000).meters
# Last waypoint has index of 1.
last_waypoint = 2
recovery_tanker = RecoveryTanker(group_id, speed, altitude, last_waypoint)
waypoint.add_task(recovery_tanker)
assert self.flight.flight_type == FlightType.REFUELING
group_id = self._get_carrier_group_id()
speed = knots(250).meters_per_second
altitude = feet(6000).meters
self.configure_tanker_tacan(waypoint)
# Last waypoint has index of 1.
# Give the tanker a end condition of the last carrier waypoint.
# If the carrier ever gets more than one waypoint this approach needs to change.
last_waypoint = 2
recovery_tanker = RecoveryTanker(group_id, speed, altitude, last_waypoint)
waypoint.add_task(recovery_tanker)
self.configure_tanker_tacan(waypoint)
def _get_carrier_group_id(self) -> int:
name = self.package.target.name

View File

@ -1177,6 +1177,8 @@ class NavalControlPoint(ControlPoint, ABC):
if self.is_friendly(for_player):
yield from [
FlightType.AEWC,
FlightType.REFUELING,
# TODO: FlightType.INTERCEPTION
# TODO: Buddy tanking for the A-4?
# TODO: Rescue chopper?
@ -1272,8 +1274,7 @@ class Carrier(NavalControlPoint):
yield from super().mission_types(for_player)
if self.is_friendly(for_player):
yield from [
FlightType.AEWC,
FlightType.REFUELING,
# Nothing yet.
]
def capture(self, game: Game, events: GameUpdateEvents, for_player: bool) -> None: