Clean up aircraft allocation and procurement.

This also does improve the over-purchase problems, though I can't spot
the behavior change that's causing that. Presumably the old
implementation had a bug I can't spot and in rewriting it I solved the
problem...

Fixes https://github.com/dcs-liberation/dcs_liberation/issues/1582
This commit is contained in:
Dan Albert
2021-09-03 15:09:48 -07:00
parent 94fb0d8c66
commit ab2bb6814e
6 changed files with 76 additions and 132 deletions

View File

@@ -2,20 +2,21 @@ from __future__ import annotations
import itertools
from collections import defaultdict
from typing import Sequence, Iterator, TYPE_CHECKING
from typing import Sequence, Iterator, TYPE_CHECKING, Optional
from game.dcs.aircrafttype import AircraftType
from gen.flights.ai_flight_planner_db import aircraft_for_task
from gen.flights.closestairfields import ObjectiveDistanceCache
from .squadron import Squadron
from ..theater import ControlPoint
from ..theater import ControlPoint, MissionTarget
if TYPE_CHECKING:
from game import Game
from gen.flights.flight import FlightType
class AirWing:
def __init__(self, game: Game) -> None:
self.game = game
def __init__(self, player: bool) -> None:
self.player = player
self.squadrons: dict[AircraftType, list[Squadron]] = defaultdict(list)
def add_squadron(self, squadron: Squadron) -> None:
@@ -31,6 +32,35 @@ class AirWing:
except StopIteration:
return False
def best_squadrons_for(
self, location: MissionTarget, task: FlightType, size: int, this_turn: bool
) -> list[Squadron]:
airfield_cache = ObjectiveDistanceCache.get_closest_airfields(location)
best_aircraft = aircraft_for_task(task)
ordered: list[Squadron] = []
for control_point in airfield_cache.operational_airfields:
if control_point.captured != self.player:
continue
capable_at_base = []
for squadron in control_point.squadrons:
if squadron.can_auto_assign_mission(location, task, size, this_turn):
capable_at_base.append(squadron)
ordered.extend(
sorted(
capable_at_base,
key=lambda s: best_aircraft.index(s.aircraft),
)
)
return ordered
def best_squadron_for(
self, location: MissionTarget, task: FlightType, size: int, this_turn: bool
) -> Optional[Squadron]:
for squadron in self.best_squadrons_for(location, task, size, this_turn):
return squadron
return None
@property
def available_aircraft_types(self) -> Iterator[AircraftType]:
for aircraft, squadrons in self.squadrons.items():
@@ -51,17 +81,6 @@ class AirWing:
if squadron.can_auto_assign(task) and squadron.location == base:
yield squadron
def auto_assignable_for_task_with_type(
self, aircraft: AircraftType, task: FlightType, base: ControlPoint
) -> Iterator[Squadron]:
for squadron in self.squadrons_for(aircraft):
if (
squadron.location == base
and squadron.can_auto_assign(task)
and squadron.has_available_pilots
):
yield squadron
def squadron_for(self, aircraft: AircraftType) -> Squadron:
return self.squadrons_for(aircraft)[0]

View File

@@ -16,12 +16,13 @@ from gen.ato import Package
from gen.flights.flight import FlightType, Flight
from gen.flights.flightplan import FlightPlanBuilder
from .pilot import Pilot, PilotStatus
from ..utils import meters
if TYPE_CHECKING:
from game import Game
from game.coalition import Coalition
from game.dcs.aircrafttype import AircraftType
from game.theater import ControlPoint, ConflictTheater
from game.theater import ControlPoint, ConflictTheater, MissionTarget
from .operatingbases import OperatingBases
from .squadrondef import SquadronDef
@@ -252,6 +253,17 @@ class Squadron:
def can_auto_assign(self, task: FlightType) -> bool:
return task in self.auto_assignable_mission_types
def can_auto_assign_mission(
self, location: MissionTarget, task: FlightType, size: int, this_turn: bool
) -> bool:
if not self.can_auto_assign(task):
return False
if this_turn and not self.can_fulfill_flight(size):
return False
distance_to_target = meters(location.distance_to(self.location))
return distance_to_target <= self.aircraft.max_mission_range
def operates_from(self, control_point: ControlPoint) -> bool:
if control_point.is_carrier:
return self.operating_bases.carrier