Pick divert airfields when planning.

https://github.com/Khopa/dcs_liberation/issues/342
This commit is contained in:
Dan Albert 2020-11-20 17:29:58 -08:00
parent ae68a35a1a
commit a594f45aae
6 changed files with 47 additions and 29 deletions

View File

@ -4,7 +4,7 @@ from __future__ import annotations
from collections import defaultdict
from typing import Dict, Iterable, Iterator, Set, Tuple, TYPE_CHECKING
from dcs.unittype import UnitType
from dcs.unittype import FlyingType
from gen.flights.flight import Flight
@ -17,9 +17,9 @@ class ControlPointAircraftInventory:
def __init__(self, control_point: ControlPoint) -> None:
self.control_point = control_point
self.inventory: Dict[UnitType, int] = defaultdict(int)
self.inventory: Dict[FlyingType, int] = defaultdict(int)
def add_aircraft(self, aircraft: UnitType, count: int) -> None:
def add_aircraft(self, aircraft: FlyingType, count: int) -> None:
"""Adds aircraft to the inventory.
Args:
@ -28,7 +28,7 @@ class ControlPointAircraftInventory:
"""
self.inventory[aircraft] += count
def remove_aircraft(self, aircraft: UnitType, count: int) -> None:
def remove_aircraft(self, aircraft: FlyingType, count: int) -> None:
"""Removes aircraft from the inventory.
Args:
@ -47,7 +47,7 @@ class ControlPointAircraftInventory:
)
self.inventory[aircraft] -= count
def available(self, aircraft: UnitType) -> int:
def available(self, aircraft: FlyingType) -> int:
"""Returns the number of available aircraft of the given type.
Args:
@ -59,14 +59,14 @@ class ControlPointAircraftInventory:
return 0
@property
def types_available(self) -> Iterator[UnitType]:
def types_available(self) -> Iterator[FlyingType]:
"""Iterates over all available aircraft types."""
for aircraft, count in self.inventory.items():
if count > 0:
yield aircraft
@property
def all_aircraft(self) -> Iterator[Tuple[UnitType, int]]:
def all_aircraft(self) -> Iterator[Tuple[FlyingType, int]]:
"""Iterates over all available aircraft types, including amounts."""
for aircraft, count in self.inventory.items():
if count > 0:
@ -106,9 +106,9 @@ class GlobalAircraftInventory:
return self.inventories[control_point]
@property
def available_types_for_player(self) -> Iterator[UnitType]:
def available_types_for_player(self) -> Iterator[FlyingType]:
"""Iterates over all aircraft types available to the player."""
seen: Set[UnitType] = set()
seen: Set[FlyingType] = set()
for control_point, inventory in self.inventories.items():
if control_point.captured:
for aircraft in inventory.types_available:

View File

@ -16,6 +16,7 @@ from dcs.ships import (
Type_071_Amphibious_Transport_Dock,
)
from dcs.terrain.terrain import Airport
from dcs.unittype import FlyingType
from game import db
from gen.ground_forces.combat_stance import CombatStance
@ -366,6 +367,13 @@ class ControlPoint(MissionTarget):
# TODO: FlightType.STRIKE
]
def can_land(self, aircraft: FlyingType) -> bool:
if self.is_carrier and aircraft not in db.CARRIER_CAPABLE:
return False
if self.is_lha and aircraft not in db.LHA_CAPABLE:
return False
return True
class OffMapSpawn(ControlPoint):
def __init__(self, id: int, name: str, position: Point):

View File

@ -16,7 +16,7 @@ from typing import (
Type,
)
from dcs.unittype import FlyingType, UnitType
from dcs.unittype import FlyingType
from game import db
from game.data.radar_db import UNITS_WITH_RADAR
@ -119,7 +119,7 @@ class AircraftAllocator:
def find_aircraft_for_flight(
self, flight: ProposedFlight
) -> Optional[Tuple[ControlPoint, UnitType]]:
) -> Optional[Tuple[ControlPoint, FlyingType]]:
"""Finds aircraft suitable for the given mission.
Searches for aircraft capable of performing the given mission within the
@ -190,7 +190,7 @@ class AircraftAllocator:
def find_aircraft_of_type(
self, flight: ProposedFlight, types: List[Type[FlyingType]],
) -> Optional[Tuple[ControlPoint, UnitType]]:
) -> Optional[Tuple[ControlPoint, FlyingType]]:
airfields_in_range = self.closest_airfields.airfields_within(
flight.max_distance
)
@ -214,6 +214,8 @@ class PackageBuilder:
global_inventory: GlobalAircraftInventory,
is_player: bool,
start_type: str) -> None:
self.closest_airfields = closest_airfields
self.is_player = is_player
self.package = Package(location)
self.allocator = AircraftAllocator(closest_airfields, global_inventory,
is_player)
@ -239,10 +241,25 @@ class PackageBuilder:
flight = Flight(self.package, aircraft, plan.num_aircraft, plan.task,
start_type, departure=airfield, arrival=airfield,
divert=None)
divert=self.find_divert_field(aircraft, airfield))
self.package.add_flight(flight)
return True
def find_divert_field(self, aircraft: FlyingType,
arrival: ControlPoint) -> Optional[ControlPoint]:
divert_limit = nm_to_meter(150)
for airfield in self.closest_airfields.airfields_within(divert_limit):
if airfield.captured != self.is_player:
continue
if airfield == arrival:
continue
if not airfield.can_land(aircraft):
continue
if isinstance(airfield, OffMapSpawn):
continue
return airfield
return None
def build(self) -> Package:
"""Returns the built package."""
return self.package

View File

@ -3,13 +3,13 @@ from typing import Iterable
from PySide2.QtWidgets import QComboBox
from dcs.planes import PlaneType
from dcs.unittype import FlyingType
class QAircraftTypeSelector(QComboBox):
"""Combo box for selecting among the given aircraft types."""
def __init__(self, aircraft_types: Iterable[PlaneType]) -> None:
def __init__(self, aircraft_types: Iterable[FlyingType]) -> None:
super().__init__()
for aircraft in aircraft_types:
self.addItem(f"{aircraft.id}", userData=aircraft)

View File

@ -2,7 +2,7 @@
from typing import Iterable
from PySide2.QtWidgets import QComboBox
from dcs.planes import PlaneType
from dcs.unittype import FlyingType
from game import db
from game.theater.controlpoint import ControlPoint
@ -16,7 +16,7 @@ class QArrivalAirfieldSelector(QComboBox):
"""
def __init__(self, destinations: Iterable[ControlPoint],
aircraft: PlaneType, optional_text: str) -> None:
aircraft: FlyingType, optional_text: str) -> None:
super().__init__()
self.destinations = list(destinations)
self.aircraft = aircraft
@ -24,23 +24,16 @@ class QArrivalAirfieldSelector(QComboBox):
self.rebuild_selector()
self.setCurrentIndex(0)
def change_aircraft(self, aircraft: PlaneType) -> None:
def change_aircraft(self, aircraft: FlyingType) -> None:
if self.aircraft == aircraft:
return
self.aircraft = aircraft
self.rebuild_selector()
def valid_destination(self, destination: ControlPoint) -> bool:
if destination.is_carrier and self.aircraft not in db.CARRIER_CAPABLE:
return False
if destination.is_lha and self.aircraft not in db.LHA_CAPABLE:
return False
return True
def rebuild_selector(self) -> None:
self.clear()
for destination in self.destinations:
if self.valid_destination(destination):
if destination.can_land(self.aircraft):
self.addItem(destination.name, destination)
self.model().sort(0)
self.insertItem(0, self.optional_text, None)

View File

@ -3,7 +3,7 @@ from typing import Iterable
from PySide2.QtCore import Signal
from PySide2.QtWidgets import QComboBox
from dcs.planes import PlaneType
from dcs.unittype import FlyingType
from game.inventory import GlobalAircraftInventory
from game.theater.controlpoint import ControlPoint
@ -20,7 +20,7 @@ class QOriginAirfieldSelector(QComboBox):
def __init__(self, global_inventory: GlobalAircraftInventory,
origins: Iterable[ControlPoint],
aircraft: PlaneType) -> None:
aircraft: FlyingType) -> None:
super().__init__()
self.global_inventory = global_inventory
self.origins = list(origins)
@ -28,7 +28,7 @@ class QOriginAirfieldSelector(QComboBox):
self.rebuild_selector()
self.currentIndexChanged.connect(self.index_changed)
def change_aircraft(self, aircraft: PlaneType) -> None:
def change_aircraft(self, aircraft: FlyingType) -> None:
if self.aircraft == aircraft:
return
self.aircraft = aircraft