mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
180 lines
6.5 KiB
Python
180 lines
6.5 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
import random
|
|
from typing import Optional, TYPE_CHECKING
|
|
|
|
from game.squadrons import Squadron
|
|
from game.squadrons.squadrondef import SquadronDef
|
|
from .campaignairwingconfig import CampaignAirWingConfig, SquadronConfig
|
|
from ..ato.flighttype import FlightType
|
|
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
|
|
|
|
def assign(self) -> None:
|
|
for control_point in self.game.theater.control_points_for(
|
|
self.coalition.player
|
|
):
|
|
for squadron_config in self.config.by_location[control_point]:
|
|
squadron_def = self.override_squadron_defaults(
|
|
self.find_squadron_for(squadron_config, control_point),
|
|
squadron_config,
|
|
)
|
|
|
|
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
|
|
|
|
squadron = Squadron.create_from(
|
|
squadron_def,
|
|
squadron_config.primary,
|
|
squadron_config.max_size,
|
|
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.air_wing.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:
|
|
logging.warning(
|
|
"%s is neither a compatible squadron or a known aircraft type, "
|
|
"ignoring",
|
|
preferred_aircraft,
|
|
)
|
|
return None
|
|
|
|
if aircraft not in self.coalition.faction.all_aircrafts:
|
|
return None
|
|
|
|
squadron_def = self.find_squadron_for_airframe(aircraft, task, control_point)
|
|
if squadron_def is not None and (
|
|
squadron_def.livery is not None or squadron_def.livery_set is not None
|
|
):
|
|
return squadron_def
|
|
|
|
# No premade squadron available for this aircraft that meets the requirements,
|
|
# so generate one if possible.
|
|
return self.air_wing.squadron_def_generator.generate_for_aircraft(aircraft)
|
|
|
|
@staticmethod
|
|
def squadron_compatible_with(
|
|
squadron: SquadronDef,
|
|
task: FlightType,
|
|
control_point: ControlPoint,
|
|
ignore_base_preference: bool = False,
|
|
) -> bool:
|
|
if ignore_base_preference:
|
|
return control_point.can_operate(squadron.aircraft)
|
|
return squadron.operates_from(control_point) and squadron.capable_of(task)
|
|
|
|
def find_squadron_for_airframe(
|
|
self, aircraft: AircraftType, task: FlightType, control_point: ControlPoint
|
|
) -> Optional[SquadronDef]:
|
|
choices = []
|
|
for squadron in self.air_wing.squadron_defs[aircraft]:
|
|
if not squadron.claimed and self.squadron_compatible_with(
|
|
squadron, task, control_point
|
|
):
|
|
choices.append(squadron)
|
|
if choices:
|
|
return random.choice(choices)
|
|
return None
|
|
|
|
def find_squadron_by_name(
|
|
self, name: str, task: FlightType, control_point: ControlPoint
|
|
) -> Optional[SquadronDef]:
|
|
for squadrons in self.air_wing.squadron_defs.values():
|
|
for squadron in squadrons:
|
|
if (
|
|
not squadron.claimed
|
|
and squadron.name == name
|
|
and self.squadron_compatible_with(
|
|
squadron, task, control_point, ignore_base_preference=True
|
|
)
|
|
):
|
|
return squadron
|
|
return None
|
|
|
|
def find_squadron_for_task(
|
|
self, task: FlightType, control_point: ControlPoint
|
|
) -> Optional[SquadronDef]:
|
|
for squadrons in self.air_wing.squadron_defs.values():
|
|
for squadron in squadrons:
|
|
if not squadron.claimed and self.squadron_compatible_with(
|
|
squadron, task, control_point
|
|
):
|
|
return squadron
|
|
return None
|
|
|
|
@staticmethod
|
|
def override_squadron_defaults(
|
|
squadron_def: Optional[SquadronDef], config: SquadronConfig
|
|
) -> Optional[SquadronDef]:
|
|
if squadron_def is None:
|
|
return None
|
|
|
|
if config.name is not None:
|
|
squadron_def.name = config.name
|
|
if config.nickname is not None:
|
|
squadron_def.nickname = config.nickname
|
|
if config.female_pilot_percentage is not None:
|
|
squadron_def.female_pilot_percentage = config.female_pilot_percentage
|
|
|
|
return squadron_def
|