mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Obey squadron mission types in auto-planning.
https://github.com/dcs-liberation/dcs_liberation/issues/276
This commit is contained in:
parent
dae3835eb0
commit
d7768f86d3
@ -7,7 +7,16 @@ from collections import defaultdict
|
|||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import unique, Enum
|
from enum import unique, Enum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Type, Tuple, List, TYPE_CHECKING, Optional, Iterable, Iterator
|
from typing import (
|
||||||
|
Type,
|
||||||
|
Tuple,
|
||||||
|
List,
|
||||||
|
TYPE_CHECKING,
|
||||||
|
Optional,
|
||||||
|
Iterable,
|
||||||
|
Iterator,
|
||||||
|
Sequence,
|
||||||
|
)
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from dcs.unittype import FlyingType
|
from dcs.unittype import FlyingType
|
||||||
@ -278,8 +287,11 @@ class AirWing:
|
|||||||
)
|
)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
def squadrons_for(self, aircraft: Type[FlyingType]) -> Sequence[Squadron]:
|
||||||
|
return self.squadrons[aircraft]
|
||||||
|
|
||||||
def squadron_for(self, aircraft: Type[FlyingType]) -> Squadron:
|
def squadron_for(self, aircraft: Type[FlyingType]) -> Squadron:
|
||||||
return self.squadrons[aircraft][0]
|
return self.squadrons_for(aircraft)[0]
|
||||||
|
|
||||||
def iter_squadrons(self) -> Iterator[Squadron]:
|
def iter_squadrons(self) -> Iterator[Squadron]:
|
||||||
return itertools.chain.from_iterable(self.squadrons.values())
|
return itertools.chain.from_iterable(self.squadrons.values())
|
||||||
|
|||||||
@ -80,7 +80,7 @@ from game.data.weapons import Pylon
|
|||||||
from game.db import GUN_RELIANT_AIRFRAMES
|
from game.db import GUN_RELIANT_AIRFRAMES
|
||||||
from game.factions.faction import Faction
|
from game.factions.faction import Faction
|
||||||
from game.settings import Settings
|
from game.settings import Settings
|
||||||
from game.squadrons import Pilot
|
from game.squadrons import Pilot, Squadron
|
||||||
from game.theater.controlpoint import (
|
from game.theater.controlpoint import (
|
||||||
Airfield,
|
Airfield,
|
||||||
ControlPoint,
|
ControlPoint,
|
||||||
|
|||||||
@ -25,7 +25,7 @@ from dcs.unittype import FlyingType
|
|||||||
from game.factions.faction import Faction
|
from game.factions.faction import Faction
|
||||||
from game.infos.information import Information
|
from game.infos.information import Information
|
||||||
from game.procurement import AircraftProcurementRequest
|
from game.procurement import AircraftProcurementRequest
|
||||||
from game.squadrons import AirWing
|
from game.squadrons import AirWing, Squadron
|
||||||
from game.theater import (
|
from game.theater import (
|
||||||
Airfield,
|
Airfield,
|
||||||
ControlPoint,
|
ControlPoint,
|
||||||
@ -123,17 +123,19 @@ class AircraftAllocator:
|
|||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
air_wing: AirWing,
|
||||||
closest_airfields: ClosestAirfields,
|
closest_airfields: ClosestAirfields,
|
||||||
global_inventory: GlobalAircraftInventory,
|
global_inventory: GlobalAircraftInventory,
|
||||||
is_player: bool,
|
is_player: bool,
|
||||||
) -> None:
|
) -> None:
|
||||||
|
self.air_wing = air_wing
|
||||||
self.closest_airfields = closest_airfields
|
self.closest_airfields = closest_airfields
|
||||||
self.global_inventory = global_inventory
|
self.global_inventory = global_inventory
|
||||||
self.is_player = is_player
|
self.is_player = is_player
|
||||||
|
|
||||||
def find_aircraft_for_flight(
|
def find_squadron_for_flight(
|
||||||
self, flight: ProposedFlight
|
self, flight: ProposedFlight
|
||||||
) -> Optional[Tuple[ControlPoint, Type[FlyingType]]]:
|
) -> Optional[Tuple[ControlPoint, Squadron]]:
|
||||||
"""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
|
||||||
@ -152,16 +154,18 @@ class AircraftAllocator:
|
|||||||
on subsequent calls. If the found aircraft are not used, the caller is
|
on subsequent calls. If the found aircraft are not used, the caller is
|
||||||
responsible for returning them to the inventory.
|
responsible for returning them to the inventory.
|
||||||
"""
|
"""
|
||||||
return self.find_aircraft_of_type(flight, aircraft_for_task(flight.task))
|
return self.find_aircraft_for_task(flight, flight.task)
|
||||||
|
|
||||||
def find_aircraft_of_type(
|
def find_aircraft_for_task(
|
||||||
self,
|
self, flight: ProposedFlight, task: FlightType
|
||||||
flight: ProposedFlight,
|
) -> Optional[Tuple[ControlPoint, Squadron]]:
|
||||||
types: List[Type[FlyingType]],
|
types = aircraft_for_task(task)
|
||||||
) -> Optional[Tuple[ControlPoint, Type[FlyingType]]]:
|
|
||||||
airfields_in_range = self.closest_airfields.airfields_within(
|
airfields_in_range = self.closest_airfields.airfields_within(
|
||||||
flight.max_distance
|
flight.max_distance
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Prefer using squadrons with pilots first
|
||||||
|
best_understaffed: Optional[Tuple[ControlPoint, Squadron]] = None
|
||||||
for airfield in airfields_in_range:
|
for airfield in airfields_in_range:
|
||||||
if not airfield.is_friendly(self.is_player):
|
if not airfield.is_friendly(self.is_player):
|
||||||
continue
|
continue
|
||||||
@ -169,11 +173,28 @@ class AircraftAllocator:
|
|||||||
for aircraft in types:
|
for aircraft in types:
|
||||||
if not airfield.can_operate(aircraft):
|
if not airfield.can_operate(aircraft):
|
||||||
continue
|
continue
|
||||||
if inventory.available(aircraft) >= flight.num_aircraft:
|
if inventory.available(aircraft) < flight.num_aircraft:
|
||||||
inventory.remove_aircraft(aircraft, flight.num_aircraft)
|
continue
|
||||||
return airfield, aircraft
|
# Valid location with enough aircraft available. Find a squadron to fit
|
||||||
|
# the role.
|
||||||
|
for squadron in self.air_wing.squadrons_for(aircraft):
|
||||||
|
if task not in squadron.mission_types:
|
||||||
|
continue
|
||||||
|
if len(squadron.available_pilots) >= flight.num_aircraft:
|
||||||
|
inventory.remove_aircraft(aircraft, flight.num_aircraft)
|
||||||
|
return airfield, squadron
|
||||||
|
|
||||||
return None
|
# A compatible squadron that doesn't have enough pilots. Remember it
|
||||||
|
# as a fallback in case we find no better choices.
|
||||||
|
if best_understaffed is None:
|
||||||
|
best_understaffed = airfield, squadron
|
||||||
|
|
||||||
|
if best_understaffed is not None:
|
||||||
|
airfield, squadron = best_understaffed
|
||||||
|
self.global_inventory.for_control_point(airfield).remove_aircraft(
|
||||||
|
squadron.aircraft, flight.num_aircraft
|
||||||
|
)
|
||||||
|
return best_understaffed
|
||||||
|
|
||||||
|
|
||||||
class PackageBuilder:
|
class PackageBuilder:
|
||||||
@ -192,11 +213,10 @@ class PackageBuilder:
|
|||||||
) -> None:
|
) -> None:
|
||||||
self.closest_airfields = closest_airfields
|
self.closest_airfields = closest_airfields
|
||||||
self.is_player = is_player
|
self.is_player = is_player
|
||||||
self.air_wing = air_wing
|
|
||||||
self.package_country = package_country
|
self.package_country = package_country
|
||||||
self.package = Package(location, auto_asap=asap)
|
self.package = Package(location, auto_asap=asap)
|
||||||
self.allocator = AircraftAllocator(
|
self.allocator = AircraftAllocator(
|
||||||
closest_airfields, global_inventory, is_player
|
air_wing, closest_airfields, global_inventory, is_player
|
||||||
)
|
)
|
||||||
self.global_inventory = global_inventory
|
self.global_inventory = global_inventory
|
||||||
self.start_type = start_type
|
self.start_type = start_type
|
||||||
@ -209,10 +229,10 @@ class PackageBuilder:
|
|||||||
caller should return any previously planned flights to the inventory
|
caller should return any previously planned flights to the inventory
|
||||||
using release_planned_aircraft.
|
using release_planned_aircraft.
|
||||||
"""
|
"""
|
||||||
assignment = self.allocator.find_aircraft_for_flight(plan)
|
assignment = self.allocator.find_squadron_for_flight(plan)
|
||||||
if assignment is None:
|
if assignment is None:
|
||||||
return False
|
return False
|
||||||
airfield, aircraft = assignment
|
airfield, squadron = assignment
|
||||||
if isinstance(airfield, OffMapSpawn):
|
if isinstance(airfield, OffMapSpawn):
|
||||||
start_type = "In Flight"
|
start_type = "In Flight"
|
||||||
else:
|
else:
|
||||||
@ -221,13 +241,13 @@ class PackageBuilder:
|
|||||||
flight = Flight(
|
flight = Flight(
|
||||||
self.package,
|
self.package,
|
||||||
self.package_country,
|
self.package_country,
|
||||||
self.air_wing.squadron_for(aircraft),
|
squadron,
|
||||||
plan.num_aircraft,
|
plan.num_aircraft,
|
||||||
plan.task,
|
plan.task,
|
||||||
start_type,
|
start_type,
|
||||||
departure=airfield,
|
departure=airfield,
|
||||||
arrival=airfield,
|
arrival=airfield,
|
||||||
divert=self.find_divert_field(aircraft, airfield),
|
divert=self.find_divert_field(squadron.aircraft, airfield),
|
||||||
)
|
)
|
||||||
self.package.add_flight(flight)
|
self.package.add_flight(flight)
|
||||||
return True
|
return True
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user