mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Pick divert airfields when planning.
https://github.com/Khopa/dcs_liberation/issues/342
This commit is contained in:
parent
ae68a35a1a
commit
a594f45aae
@ -4,7 +4,7 @@ from __future__ import annotations
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from typing import Dict, Iterable, Iterator, Set, Tuple, TYPE_CHECKING
|
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
|
from gen.flights.flight import Flight
|
||||||
|
|
||||||
@ -17,9 +17,9 @@ class ControlPointAircraftInventory:
|
|||||||
|
|
||||||
def __init__(self, control_point: ControlPoint) -> None:
|
def __init__(self, control_point: ControlPoint) -> None:
|
||||||
self.control_point = control_point
|
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.
|
"""Adds aircraft to the inventory.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -28,7 +28,7 @@ class ControlPointAircraftInventory:
|
|||||||
"""
|
"""
|
||||||
self.inventory[aircraft] += count
|
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.
|
"""Removes aircraft from the inventory.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -47,7 +47,7 @@ class ControlPointAircraftInventory:
|
|||||||
)
|
)
|
||||||
self.inventory[aircraft] -= count
|
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.
|
"""Returns the number of available aircraft of the given type.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
@ -59,14 +59,14 @@ class ControlPointAircraftInventory:
|
|||||||
return 0
|
return 0
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def types_available(self) -> Iterator[UnitType]:
|
def types_available(self) -> Iterator[FlyingType]:
|
||||||
"""Iterates over all available aircraft types."""
|
"""Iterates over all available aircraft types."""
|
||||||
for aircraft, count in self.inventory.items():
|
for aircraft, count in self.inventory.items():
|
||||||
if count > 0:
|
if count > 0:
|
||||||
yield aircraft
|
yield aircraft
|
||||||
|
|
||||||
@property
|
@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."""
|
"""Iterates over all available aircraft types, including amounts."""
|
||||||
for aircraft, count in self.inventory.items():
|
for aircraft, count in self.inventory.items():
|
||||||
if count > 0:
|
if count > 0:
|
||||||
@ -106,9 +106,9 @@ class GlobalAircraftInventory:
|
|||||||
return self.inventories[control_point]
|
return self.inventories[control_point]
|
||||||
|
|
||||||
@property
|
@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."""
|
"""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():
|
for control_point, inventory in self.inventories.items():
|
||||||
if control_point.captured:
|
if control_point.captured:
|
||||||
for aircraft in inventory.types_available:
|
for aircraft in inventory.types_available:
|
||||||
|
|||||||
@ -16,6 +16,7 @@ from dcs.ships import (
|
|||||||
Type_071_Amphibious_Transport_Dock,
|
Type_071_Amphibious_Transport_Dock,
|
||||||
)
|
)
|
||||||
from dcs.terrain.terrain import Airport
|
from dcs.terrain.terrain import Airport
|
||||||
|
from dcs.unittype import FlyingType
|
||||||
|
|
||||||
from game import db
|
from game import db
|
||||||
from gen.ground_forces.combat_stance import CombatStance
|
from gen.ground_forces.combat_stance import CombatStance
|
||||||
@ -366,6 +367,13 @@ class ControlPoint(MissionTarget):
|
|||||||
# TODO: FlightType.STRIKE
|
# 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):
|
class OffMapSpawn(ControlPoint):
|
||||||
def __init__(self, id: int, name: str, position: Point):
|
def __init__(self, id: int, name: str, position: Point):
|
||||||
|
|||||||
@ -16,7 +16,7 @@ from typing import (
|
|||||||
Type,
|
Type,
|
||||||
)
|
)
|
||||||
|
|
||||||
from dcs.unittype import FlyingType, UnitType
|
from dcs.unittype import FlyingType
|
||||||
|
|
||||||
from game import db
|
from game import db
|
||||||
from game.data.radar_db import UNITS_WITH_RADAR
|
from game.data.radar_db import UNITS_WITH_RADAR
|
||||||
@ -119,7 +119,7 @@ class AircraftAllocator:
|
|||||||
|
|
||||||
def find_aircraft_for_flight(
|
def find_aircraft_for_flight(
|
||||||
self, flight: ProposedFlight
|
self, flight: ProposedFlight
|
||||||
) -> Optional[Tuple[ControlPoint, UnitType]]:
|
) -> Optional[Tuple[ControlPoint, FlyingType]]:
|
||||||
"""Finds aircraft suitable for the given mission.
|
"""Finds aircraft suitable for the given mission.
|
||||||
|
|
||||||
Searches for aircraft capable of performing the given mission within the
|
Searches for aircraft capable of performing the given mission within the
|
||||||
@ -190,7 +190,7 @@ class AircraftAllocator:
|
|||||||
|
|
||||||
def find_aircraft_of_type(
|
def find_aircraft_of_type(
|
||||||
self, flight: ProposedFlight, types: List[Type[FlyingType]],
|
self, flight: ProposedFlight, types: List[Type[FlyingType]],
|
||||||
) -> Optional[Tuple[ControlPoint, UnitType]]:
|
) -> Optional[Tuple[ControlPoint, FlyingType]]:
|
||||||
airfields_in_range = self.closest_airfields.airfields_within(
|
airfields_in_range = self.closest_airfields.airfields_within(
|
||||||
flight.max_distance
|
flight.max_distance
|
||||||
)
|
)
|
||||||
@ -214,6 +214,8 @@ class PackageBuilder:
|
|||||||
global_inventory: GlobalAircraftInventory,
|
global_inventory: GlobalAircraftInventory,
|
||||||
is_player: bool,
|
is_player: bool,
|
||||||
start_type: str) -> None:
|
start_type: str) -> None:
|
||||||
|
self.closest_airfields = closest_airfields
|
||||||
|
self.is_player = is_player
|
||||||
self.package = Package(location)
|
self.package = Package(location)
|
||||||
self.allocator = AircraftAllocator(closest_airfields, global_inventory,
|
self.allocator = AircraftAllocator(closest_airfields, global_inventory,
|
||||||
is_player)
|
is_player)
|
||||||
@ -239,10 +241,25 @@ class PackageBuilder:
|
|||||||
|
|
||||||
flight = Flight(self.package, aircraft, plan.num_aircraft, plan.task,
|
flight = Flight(self.package, aircraft, plan.num_aircraft, plan.task,
|
||||||
start_type, departure=airfield, arrival=airfield,
|
start_type, departure=airfield, arrival=airfield,
|
||||||
divert=None)
|
divert=self.find_divert_field(aircraft, airfield))
|
||||||
self.package.add_flight(flight)
|
self.package.add_flight(flight)
|
||||||
return True
|
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:
|
def build(self) -> Package:
|
||||||
"""Returns the built package."""
|
"""Returns the built package."""
|
||||||
return self.package
|
return self.package
|
||||||
|
|||||||
@ -3,13 +3,13 @@ from typing import Iterable
|
|||||||
|
|
||||||
from PySide2.QtWidgets import QComboBox
|
from PySide2.QtWidgets import QComboBox
|
||||||
|
|
||||||
from dcs.planes import PlaneType
|
from dcs.unittype import FlyingType
|
||||||
|
|
||||||
|
|
||||||
class QAircraftTypeSelector(QComboBox):
|
class QAircraftTypeSelector(QComboBox):
|
||||||
"""Combo box for selecting among the given aircraft types."""
|
"""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__()
|
super().__init__()
|
||||||
for aircraft in aircraft_types:
|
for aircraft in aircraft_types:
|
||||||
self.addItem(f"{aircraft.id}", userData=aircraft)
|
self.addItem(f"{aircraft.id}", userData=aircraft)
|
||||||
|
|||||||
@ -2,7 +2,7 @@
|
|||||||
from typing import Iterable
|
from typing import Iterable
|
||||||
|
|
||||||
from PySide2.QtWidgets import QComboBox
|
from PySide2.QtWidgets import QComboBox
|
||||||
from dcs.planes import PlaneType
|
from dcs.unittype import FlyingType
|
||||||
|
|
||||||
from game import db
|
from game import db
|
||||||
from game.theater.controlpoint import ControlPoint
|
from game.theater.controlpoint import ControlPoint
|
||||||
@ -16,7 +16,7 @@ class QArrivalAirfieldSelector(QComboBox):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, destinations: Iterable[ControlPoint],
|
def __init__(self, destinations: Iterable[ControlPoint],
|
||||||
aircraft: PlaneType, optional_text: str) -> None:
|
aircraft: FlyingType, optional_text: str) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.destinations = list(destinations)
|
self.destinations = list(destinations)
|
||||||
self.aircraft = aircraft
|
self.aircraft = aircraft
|
||||||
@ -24,23 +24,16 @@ class QArrivalAirfieldSelector(QComboBox):
|
|||||||
self.rebuild_selector()
|
self.rebuild_selector()
|
||||||
self.setCurrentIndex(0)
|
self.setCurrentIndex(0)
|
||||||
|
|
||||||
def change_aircraft(self, aircraft: PlaneType) -> None:
|
def change_aircraft(self, aircraft: FlyingType) -> None:
|
||||||
if self.aircraft == aircraft:
|
if self.aircraft == aircraft:
|
||||||
return
|
return
|
||||||
self.aircraft = aircraft
|
self.aircraft = aircraft
|
||||||
self.rebuild_selector()
|
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:
|
def rebuild_selector(self) -> None:
|
||||||
self.clear()
|
self.clear()
|
||||||
for destination in self.destinations:
|
for destination in self.destinations:
|
||||||
if self.valid_destination(destination):
|
if destination.can_land(self.aircraft):
|
||||||
self.addItem(destination.name, destination)
|
self.addItem(destination.name, destination)
|
||||||
self.model().sort(0)
|
self.model().sort(0)
|
||||||
self.insertItem(0, self.optional_text, None)
|
self.insertItem(0, self.optional_text, None)
|
||||||
|
|||||||
@ -3,7 +3,7 @@ from typing import Iterable
|
|||||||
|
|
||||||
from PySide2.QtCore import Signal
|
from PySide2.QtCore import Signal
|
||||||
from PySide2.QtWidgets import QComboBox
|
from PySide2.QtWidgets import QComboBox
|
||||||
from dcs.planes import PlaneType
|
from dcs.unittype import FlyingType
|
||||||
|
|
||||||
from game.inventory import GlobalAircraftInventory
|
from game.inventory import GlobalAircraftInventory
|
||||||
from game.theater.controlpoint import ControlPoint
|
from game.theater.controlpoint import ControlPoint
|
||||||
@ -20,7 +20,7 @@ class QOriginAirfieldSelector(QComboBox):
|
|||||||
|
|
||||||
def __init__(self, global_inventory: GlobalAircraftInventory,
|
def __init__(self, global_inventory: GlobalAircraftInventory,
|
||||||
origins: Iterable[ControlPoint],
|
origins: Iterable[ControlPoint],
|
||||||
aircraft: PlaneType) -> None:
|
aircraft: FlyingType) -> None:
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.global_inventory = global_inventory
|
self.global_inventory = global_inventory
|
||||||
self.origins = list(origins)
|
self.origins = list(origins)
|
||||||
@ -28,7 +28,7 @@ class QOriginAirfieldSelector(QComboBox):
|
|||||||
self.rebuild_selector()
|
self.rebuild_selector()
|
||||||
self.currentIndexChanged.connect(self.index_changed)
|
self.currentIndexChanged.connect(self.index_changed)
|
||||||
|
|
||||||
def change_aircraft(self, aircraft: PlaneType) -> None:
|
def change_aircraft(self, aircraft: FlyingType) -> None:
|
||||||
if self.aircraft == aircraft:
|
if self.aircraft == aircraft:
|
||||||
return
|
return
|
||||||
self.aircraft = aircraft
|
self.aircraft = aircraft
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user