mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
The doctrine/task limits were capturing a reasonable average for the era, but it did a bad job for cases like the Harrier vs the Hornet, which perform similar missions but have drastically different max ranges. It also forced us into limiting CAS missions (even those flown by long range aircraft like the A-10) to 50nm since helicopters could commonly be fragged to them. This should allow us to design campaigns without needing airfields to be a max of ~50-100nm apart.
77 lines
3.4 KiB
Python
77 lines
3.4 KiB
Python
from typing import Optional, Tuple
|
|
|
|
from game.commander.missionproposals import ProposedFlight
|
|
from game.inventory import GlobalAircraftInventory
|
|
from game.squadrons import AirWing, Squadron
|
|
from game.theater import ControlPoint, MissionTarget
|
|
from game.utils import meters
|
|
from gen.flights.ai_flight_planner_db import aircraft_for_task
|
|
from gen.flights.closestairfields import ClosestAirfields
|
|
from gen.flights.flight import FlightType
|
|
|
|
|
|
class AircraftAllocator:
|
|
"""Finds suitable aircraft for proposed missions."""
|
|
|
|
def __init__(
|
|
self,
|
|
air_wing: AirWing,
|
|
closest_airfields: ClosestAirfields,
|
|
global_inventory: GlobalAircraftInventory,
|
|
is_player: bool,
|
|
) -> None:
|
|
self.air_wing = air_wing
|
|
self.closest_airfields = closest_airfields
|
|
self.global_inventory = global_inventory
|
|
self.is_player = is_player
|
|
|
|
def find_squadron_for_flight(
|
|
self, target: MissionTarget, flight: ProposedFlight
|
|
) -> Optional[Tuple[ControlPoint, Squadron]]:
|
|
"""Finds aircraft suitable for the given mission.
|
|
|
|
Searches for aircraft capable of performing the given mission within the
|
|
maximum allowed range. If insufficient aircraft are available for the
|
|
mission, None is returned.
|
|
|
|
Airfields are searched ordered nearest to farthest from the target and
|
|
searched twice. The first search looks for aircraft which prefer the
|
|
mission type, and the second search looks for any aircraft which are
|
|
capable of the mission type. For example, an F-14 from a nearby carrier
|
|
will be preferred for the CAP of an airfield that has only F-16s, but if
|
|
the carrier has only F/A-18s the F-16s will be used for CAP instead.
|
|
|
|
Note that aircraft *will* be removed from the global inventory on
|
|
success. This is to ensure that the same aircraft are not matched twice
|
|
on subsequent calls. If the found aircraft are not used, the caller is
|
|
responsible for returning them to the inventory.
|
|
"""
|
|
return self.find_aircraft_for_task(target, flight, flight.task)
|
|
|
|
def find_aircraft_for_task(
|
|
self, target: MissionTarget, flight: ProposedFlight, task: FlightType
|
|
) -> Optional[Tuple[ControlPoint, Squadron]]:
|
|
types = aircraft_for_task(task)
|
|
for airfield in self.closest_airfields.operational_airfields:
|
|
if not airfield.is_friendly(self.is_player):
|
|
continue
|
|
inventory = self.global_inventory.for_control_point(airfield)
|
|
for aircraft in types:
|
|
if not airfield.can_operate(aircraft):
|
|
continue
|
|
if inventory.available(aircraft) < flight.num_aircraft:
|
|
continue
|
|
distance_to_target = meters(target.distance_to(airfield))
|
|
if distance_to_target > aircraft.max_mission_range:
|
|
continue
|
|
# Valid location with enough aircraft available. Find a squadron to fit
|
|
# the role.
|
|
squadrons = self.air_wing.auto_assignable_for_task_with_type(
|
|
aircraft, task
|
|
)
|
|
for squadron in squadrons:
|
|
if squadron.can_provide_pilots(flight.num_aircraft):
|
|
inventory.remove_aircraft(aircraft, flight.num_aircraft)
|
|
return airfield, squadron
|
|
return None
|