mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
https://github.com/dcs-liberation/dcs_liberation/issues/1145 Currently this is fixed at the start of the campaign. The squadron locations are defined by the campaign file. Follow up work: * Track aircraft ownership per-squadron rather than per-airbase. * UI for relocating squadrons. * Ferry missions for squadrons that are relocating. * Auto-relocation (probably only for retreat handling). Fixes https://github.com/dcs-liberation/dcs_liberation/issues/1138
143 lines
5.5 KiB
Python
143 lines
5.5 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from typing import Optional, TYPE_CHECKING
|
|
|
|
from game.squadrons import Squadron
|
|
from game.squadrons.squadrondef import SquadronDef
|
|
from game.squadrons.squadrondefloader import SquadronDefLoader
|
|
from gen.flights.flight import FlightType
|
|
from .campaignairwingconfig import CampaignAirWingConfig, SquadronConfig
|
|
from .squadrondefgenerator import SquadronDefGenerator
|
|
from ..dcs.aircrafttype import AircraftType
|
|
from ..theater import ControlPoint
|
|
|
|
if TYPE_CHECKING:
|
|
from game import Game
|
|
from game.coalition import Coalition
|
|
|
|
|
|
class DefaultSquadronAssigner:
|
|
def __init__(
|
|
self, config: CampaignAirWingConfig, game: Game, coalition: Coalition
|
|
) -> None:
|
|
self.config = config
|
|
self.game = game
|
|
self.coalition = coalition
|
|
self.air_wing = coalition.air_wing
|
|
self.squadron_defs = SquadronDefLoader(game, coalition).load()
|
|
self.squadron_def_generator = SquadronDefGenerator(self.coalition)
|
|
|
|
def claim_squadron_def(self, squadron: SquadronDef) -> None:
|
|
try:
|
|
self.squadron_defs[squadron.aircraft].remove(squadron)
|
|
except ValueError:
|
|
pass
|
|
|
|
def assign(self) -> None:
|
|
for control_point, squadron_configs in self.config.by_location.items():
|
|
if not control_point.is_friendly(self.coalition.player):
|
|
continue
|
|
for squadron_config in squadron_configs:
|
|
squadron_def = self.find_squadron_for(squadron_config, control_point)
|
|
if squadron_def is None:
|
|
logging.info(
|
|
f"{self.coalition.faction.name} has no aircraft compatible "
|
|
f"with {squadron_config.primary} at {control_point}"
|
|
)
|
|
continue
|
|
|
|
self.claim_squadron_def(squadron_def)
|
|
squadron = Squadron.create_from(
|
|
squadron_def, control_point, self.coalition, self.game
|
|
)
|
|
squadron.set_auto_assignable_mission_types(
|
|
squadron_config.auto_assignable
|
|
)
|
|
self.air_wing.add_squadron(squadron)
|
|
|
|
def find_squadron_for(
|
|
self, config: SquadronConfig, control_point: ControlPoint
|
|
) -> Optional[SquadronDef]:
|
|
for preferred_aircraft in config.aircraft:
|
|
squadron_def = self.find_preferred_squadron(
|
|
preferred_aircraft, config.primary, control_point
|
|
)
|
|
if squadron_def is not None:
|
|
return squadron_def
|
|
|
|
# If we didn't find any of the preferred types we should use any squadron
|
|
# compatible with the primary task.
|
|
squadron_def = self.find_squadron_for_task(config.primary, control_point)
|
|
if squadron_def is not None:
|
|
return squadron_def
|
|
|
|
# If we can't find any squadron matching the requirement, we should
|
|
# create one.
|
|
return self.squadron_def_generator.generate_for_task(
|
|
config.primary, control_point
|
|
)
|
|
|
|
def find_preferred_squadron(
|
|
self, preferred_aircraft: str, task: FlightType, control_point: ControlPoint
|
|
) -> Optional[SquadronDef]:
|
|
# Attempt to find a squadron with the name in the request.
|
|
squadron_def = self.find_squadron_by_name(
|
|
preferred_aircraft, task, control_point
|
|
)
|
|
if squadron_def is not None:
|
|
return squadron_def
|
|
|
|
# If the name didn't match a squadron available to this coalition, try to find
|
|
# an aircraft with the matching name that meets the requirements.
|
|
try:
|
|
aircraft = AircraftType.named(preferred_aircraft)
|
|
except KeyError:
|
|
# No aircraft with this name.
|
|
return None
|
|
|
|
if aircraft not in self.coalition.faction.aircrafts:
|
|
return None
|
|
|
|
squadron_def = self.find_squadron_for_airframe(aircraft, task, control_point)
|
|
if squadron_def is not None:
|
|
return squadron_def
|
|
|
|
# No premade squadron available for this aircraft that meets the requirements,
|
|
# so generate one if possible.
|
|
return self.squadron_def_generator.generate_for_aircraft(aircraft)
|
|
|
|
@staticmethod
|
|
def squadron_compatible_with(
|
|
squadron: SquadronDef, task: FlightType, control_point: ControlPoint
|
|
) -> bool:
|
|
return squadron.operates_from(control_point) and task in squadron.mission_types
|
|
|
|
def find_squadron_for_airframe(
|
|
self, aircraft: AircraftType, task: FlightType, control_point: ControlPoint
|
|
) -> Optional[SquadronDef]:
|
|
for squadron in self.squadron_defs[aircraft]:
|
|
if self.squadron_compatible_with(squadron, task, control_point):
|
|
return squadron
|
|
return None
|
|
|
|
def find_squadron_by_name(
|
|
self, name: str, task: FlightType, control_point: ControlPoint
|
|
) -> Optional[SquadronDef]:
|
|
for squadrons in self.squadron_defs.values():
|
|
for squadron in squadrons:
|
|
if squadron.name == name and self.squadron_compatible_with(
|
|
squadron, task, control_point
|
|
):
|
|
return squadron
|
|
return None
|
|
|
|
def find_squadron_for_task(
|
|
self, task: FlightType, control_point: ControlPoint
|
|
) -> Optional[SquadronDef]:
|
|
for squadrons in self.squadron_defs.values():
|
|
for squadron in squadrons:
|
|
if self.squadron_compatible_with(squadron, task, control_point):
|
|
return squadron
|
|
return None
|