dcs-retribution/game/campaignloader/defaultsquadronassigner.py
MetalStormGhost 64b1410de8 Implemented support for player controllable carriers in Pretense campaigns. This functionality can be enabled or disabled in settings, because the controllable carriers in Pretense do not build and deploy AI missions autonomously, so the old functionality is retained.
Added new options in settings:
- Carriers steam into wind
- Navmesh to use for Pretense carrier zones
- Remove ground spawn statics, including invisible FARPs, at airbases.
- Percentage of randomly selected aircraft types (only for generated squadrons)
intended to allow the user to increase aircraft variety.

Will now store the ICLS channel and Link4 frequency in missiondata.py CarrierInfo.

Implemented artillery groups as Pretense garrisons. Artillery groups are spawned by the Artillery Bunker. Will now also ensure that the logistics units spawned as part of Pretense garrisons are actually capable of ammo resupply.

Fixed the Pretense generator generating a bit too many missions per squadron. Ground spawns: Also hot start aircraft which require ground crew support (ground air or chock removal) which might not be available at roadbases. Also, pretensetgogenerator.py will now correctly handle air defence units in ground_unit_of_class(). Added Roland groups in the Pretense generator.
2024-04-06 15:46:11 +03:00

175 lines
6.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 .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, self.game.settings.squadron_random_chance
)
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
lo = self.coalition.faction.liveries_overrides
squadron_def = self.find_squadron_for_airframe(aircraft, task, control_point)
if squadron_def is not None and lo.get(aircraft) is 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]:
for squadron in self.air_wing.squadron_defs[aircraft]:
if not squadron.claimed and 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.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