mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Implemented generating player slots in the Pretense campaign.
This commit is contained in:
parent
95bac8ec17
commit
946d578ffb
@ -9,6 +9,7 @@ from typing import Any, Dict, List, TYPE_CHECKING, Tuple, Optional
|
|||||||
from dcs import Point
|
from dcs import Point
|
||||||
from dcs.country import Country
|
from dcs.country import Country
|
||||||
from dcs.mission import Mission
|
from dcs.mission import Mission
|
||||||
|
from dcs.terrain import NoParkingSlotError
|
||||||
from dcs.unitgroup import FlyingGroup, StaticGroup
|
from dcs.unitgroup import FlyingGroup, StaticGroup
|
||||||
|
|
||||||
from game.ato.airtaaskingorder import AirTaskingOrder
|
from game.ato.airtaaskingorder import AirTaskingOrder
|
||||||
@ -19,6 +20,7 @@ from game.ato.package import Package
|
|||||||
from game.ato.starttype import StartType
|
from game.ato.starttype import StartType
|
||||||
from game.coalition import Coalition
|
from game.coalition import Coalition
|
||||||
from game.data.weapons import WeaponType
|
from game.data.weapons import WeaponType
|
||||||
|
from game.dcs.aircrafttype import AircraftType
|
||||||
from game.missiongenerator.aircraft.flightdata import FlightData
|
from game.missiongenerator.aircraft.flightdata import FlightData
|
||||||
from game.missiongenerator.aircraft.flightgroupconfigurator import (
|
from game.missiongenerator.aircraft.flightgroupconfigurator import (
|
||||||
FlightGroupConfigurator,
|
FlightGroupConfigurator,
|
||||||
@ -36,6 +38,7 @@ from game.theater.controlpoint import (
|
|||||||
ParkingType,
|
ParkingType,
|
||||||
Airfield,
|
Airfield,
|
||||||
)
|
)
|
||||||
|
from game.theater.theatergroundobject import EwrGroundObject, SamGroundObject
|
||||||
from game.unitmap import UnitMap
|
from game.unitmap import UnitMap
|
||||||
from game.squadrons import Squadron
|
from game.squadrons import Squadron
|
||||||
|
|
||||||
@ -51,6 +54,7 @@ PRETENSE_BARCAP_FLIGHTS_PER_CP = 1
|
|||||||
PRETENSE_AI_AIRCRAFT_PER_FLIGHT = 2
|
PRETENSE_AI_AIRCRAFT_PER_FLIGHT = 2
|
||||||
PRETENSE_AI_AWACS_PER_FLIGHT = 1
|
PRETENSE_AI_AWACS_PER_FLIGHT = 1
|
||||||
PRETENSE_AI_TANKERS_PER_FLIGHT = 1
|
PRETENSE_AI_TANKERS_PER_FLIGHT = 1
|
||||||
|
PRETENSE_PLAYER_AIRCRAFT_PER_FLIGHT = 2
|
||||||
|
|
||||||
|
|
||||||
class PretenseAircraftGenerator:
|
class PretenseAircraftGenerator:
|
||||||
@ -214,6 +218,49 @@ class PretenseAircraftGenerator:
|
|||||||
coalition.air_wing.add_squadron(squadron)
|
coalition.air_wing.add_squadron(squadron)
|
||||||
return squadron
|
return squadron
|
||||||
|
|
||||||
|
def generate_pretense_squadron_for(
|
||||||
|
self,
|
||||||
|
aircraft_type: AircraftType,
|
||||||
|
cp: ControlPoint,
|
||||||
|
coalition: Coalition,
|
||||||
|
) -> Optional[Squadron]:
|
||||||
|
"""
|
||||||
|
Generates a Pretense squadron from the faction squadron definitions for the designated
|
||||||
|
AircraftType. Use FlightType AIR_ASSAULT
|
||||||
|
for Pretense supply helicopters and TRANSPORT for off-map cargo plane squadrons.
|
||||||
|
"""
|
||||||
|
|
||||||
|
squadron_def = coalition.air_wing.squadron_def_generator.generate_for_aircraft(
|
||||||
|
aircraft_type
|
||||||
|
)
|
||||||
|
flight_type = random.choice(list(squadron_def.auto_assignable_mission_types))
|
||||||
|
if flight_type == FlightType.ESCORT and aircraft_type.helicopter:
|
||||||
|
flight_type = FlightType.CAS
|
||||||
|
if flight_type in (
|
||||||
|
FlightType.INTERCEPTION,
|
||||||
|
FlightType.ESCORT,
|
||||||
|
FlightType.SWEEP,
|
||||||
|
):
|
||||||
|
flight_type = FlightType.BARCAP
|
||||||
|
if flight_type in (FlightType.SEAD_ESCORT, FlightType.SEAD_SWEEP):
|
||||||
|
flight_type = FlightType.SEAD
|
||||||
|
if flight_type == FlightType.ANTISHIP:
|
||||||
|
flight_type = FlightType.STRIKE
|
||||||
|
if flight_type == FlightType.TRANSPORT:
|
||||||
|
flight_type = FlightType.AIR_ASSAULT
|
||||||
|
squadron = Squadron.create_from(
|
||||||
|
squadron_def,
|
||||||
|
flight_type,
|
||||||
|
2,
|
||||||
|
cp,
|
||||||
|
coalition,
|
||||||
|
self.game,
|
||||||
|
)
|
||||||
|
if squadron.aircraft not in coalition.air_wing.squadrons:
|
||||||
|
coalition.air_wing.squadrons[squadron.aircraft] = list()
|
||||||
|
coalition.air_wing.add_squadron(squadron)
|
||||||
|
return squadron
|
||||||
|
|
||||||
def generate_pretense_aircraft(
|
def generate_pretense_aircraft(
|
||||||
self, cp: ControlPoint, ato: AirTaskingOrder
|
self, cp: ControlPoint, ato: AirTaskingOrder
|
||||||
) -> None:
|
) -> None:
|
||||||
@ -462,6 +509,68 @@ class PretenseAircraftGenerator:
|
|||||||
ato.add_package(package)
|
ato.add_package(package)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def generate_pretense_aircraft_for_players(
|
||||||
|
self, cp: ControlPoint, coalition: Coalition, ato: AirTaskingOrder
|
||||||
|
) -> None:
|
||||||
|
"""
|
||||||
|
Plans and generates player piloted aircraft groups/packages for Pretense.
|
||||||
|
|
||||||
|
Aircraft generation is done by walking the control points which will be made into
|
||||||
|
Pretense "zones" and spawning flights for different missions.
|
||||||
|
After the flight is generated the package is added to the ATO so the flights
|
||||||
|
can be configured.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
cp: Control point to generate aircraft for.
|
||||||
|
coalition: Coalition to generate aircraft for.
|
||||||
|
ato: The ATO to generate aircraft for.
|
||||||
|
"""
|
||||||
|
|
||||||
|
aircraft_per_flight = PRETENSE_PLAYER_AIRCRAFT_PER_FLIGHT
|
||||||
|
random_aircraft_list = list(coalition.faction.aircraft)
|
||||||
|
random.shuffle(random_aircraft_list)
|
||||||
|
for aircraft_type in random_aircraft_list:
|
||||||
|
# Don't generate any player flights for non-flyable types (obviously)
|
||||||
|
if not aircraft_type.flyable:
|
||||||
|
continue
|
||||||
|
if not cp.can_operate(aircraft_type):
|
||||||
|
continue
|
||||||
|
|
||||||
|
squadron = self.generate_pretense_squadron_for(
|
||||||
|
aircraft_type,
|
||||||
|
cp,
|
||||||
|
coalition,
|
||||||
|
)
|
||||||
|
if squadron is not None:
|
||||||
|
squadron.owned_aircraft += PRETENSE_PLAYER_AIRCRAFT_PER_FLIGHT
|
||||||
|
squadron.untasked_aircraft += PRETENSE_PLAYER_AIRCRAFT_PER_FLIGHT
|
||||||
|
squadron.populate_for_turn_0(False)
|
||||||
|
for pilot in squadron.pilot_pool:
|
||||||
|
pilot.player = True
|
||||||
|
package = Package(cp, squadron.flight_db, auto_asap=False)
|
||||||
|
flight = Flight(
|
||||||
|
package,
|
||||||
|
squadron,
|
||||||
|
aircraft_per_flight,
|
||||||
|
squadron.primary_task,
|
||||||
|
StartType.COLD,
|
||||||
|
divert=cp,
|
||||||
|
)
|
||||||
|
for pilot in flight.roster.pilots:
|
||||||
|
if pilot is not None:
|
||||||
|
pilot.player = True
|
||||||
|
print(
|
||||||
|
f"Generated flight for {squadron.primary_task} flying {squadron.aircraft.name} at {squadron.location.name}. Pilot client count: {flight.client_count}"
|
||||||
|
)
|
||||||
|
|
||||||
|
package.add_flight(flight)
|
||||||
|
flight.state = WaitingForStart(
|
||||||
|
flight, self.game.settings, self.game.conditions.start_time
|
||||||
|
)
|
||||||
|
ato.add_package(package)
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
def initialize_pretense_data_structures(self, cp: ControlPoint) -> None:
|
def initialize_pretense_data_structures(self, cp: ControlPoint) -> None:
|
||||||
"""
|
"""
|
||||||
Ensures that the data structures used to pass flight group information
|
Ensures that the data structures used to pass flight group information
|
||||||
@ -531,6 +640,7 @@ class PretenseAircraftGenerator:
|
|||||||
"""
|
"""
|
||||||
self.initialize_pretense_data_structures(cp)
|
self.initialize_pretense_data_structures(cp)
|
||||||
|
|
||||||
|
is_player = True
|
||||||
if country == cp.coalition.faction.country:
|
if country == cp.coalition.faction.country:
|
||||||
offmap_transport_cp = self.find_pretense_cargo_plane_cp(cp)
|
offmap_transport_cp = self.find_pretense_cargo_plane_cp(cp)
|
||||||
|
|
||||||
@ -558,7 +668,6 @@ class PretenseAircraftGenerator:
|
|||||||
|
|
||||||
self.generate_pretense_aircraft(cp, ato)
|
self.generate_pretense_aircraft(cp, ato)
|
||||||
else:
|
else:
|
||||||
is_player = True
|
|
||||||
coalition = (
|
coalition = (
|
||||||
self.game.coalition_for(is_player)
|
self.game.coalition_for(is_player)
|
||||||
if country == self.game.coalition_for(is_player).faction.country
|
if country == self.game.coalition_for(is_player).faction.country
|
||||||
@ -566,6 +675,11 @@ class PretenseAircraftGenerator:
|
|||||||
)
|
)
|
||||||
self.generate_pretense_aircraft_for_other_side(cp, coalition, ato)
|
self.generate_pretense_aircraft_for_other_side(cp, coalition, ato)
|
||||||
|
|
||||||
|
if country == self.game.coalition_for(is_player).faction.country:
|
||||||
|
if not isinstance(cp, OffMapSpawn):
|
||||||
|
coalition = self.game.coalition_for(is_player)
|
||||||
|
self.generate_pretense_aircraft_for_players(cp, coalition, ato)
|
||||||
|
|
||||||
self._reserve_frequencies_and_tacan(ato)
|
self._reserve_frequencies_and_tacan(ato)
|
||||||
|
|
||||||
def generate_packages(
|
def generate_packages(
|
||||||
@ -590,10 +704,15 @@ class PretenseAircraftGenerator:
|
|||||||
)
|
)
|
||||||
flight.return_pilots_and_aircraft()
|
flight.return_pilots_and_aircraft()
|
||||||
continue
|
continue
|
||||||
logging.info(f"Generating flight: {flight.unit_type}")
|
logging.info(
|
||||||
|
f"Generating flight: {flight.unit_type} for {flight.flight_type.name}"
|
||||||
|
)
|
||||||
|
try:
|
||||||
group = self.create_and_configure_flight(
|
group = self.create_and_configure_flight(
|
||||||
flight, country, dynamic_runways
|
flight, country, dynamic_runways
|
||||||
)
|
)
|
||||||
|
except NoParkingSlotError:
|
||||||
|
return
|
||||||
self.unit_map.add_aircraft(group, flight)
|
self.unit_map.add_aircraft(group, flight)
|
||||||
|
|
||||||
def create_and_configure_flight(
|
def create_and_configure_flight(
|
||||||
@ -632,6 +751,67 @@ class PretenseAircraftGenerator:
|
|||||||
self.use_client,
|
self.use_client,
|
||||||
).configure()
|
).configure()
|
||||||
)
|
)
|
||||||
|
else:
|
||||||
|
if flight.client_count > 0:
|
||||||
|
if flight.flight_type == FlightType.CAS:
|
||||||
|
for conflict in self.game.theater.conflicts():
|
||||||
|
flight.package.target = conflict
|
||||||
|
break
|
||||||
|
elif (
|
||||||
|
flight.flight_type == FlightType.STRIKE
|
||||||
|
or flight.flight_type == FlightType.BAI
|
||||||
|
):
|
||||||
|
for cp in self.game.theater.closest_opposing_control_points():
|
||||||
|
if cp.coalition == flight.coalition:
|
||||||
|
continue
|
||||||
|
for mission_target in cp.ground_objects:
|
||||||
|
flight.package.target = mission_target
|
||||||
|
elif (
|
||||||
|
flight.flight_type == FlightType.OCA_RUNWAY
|
||||||
|
or flight.flight_type == FlightType.OCA_AIRCRAFT
|
||||||
|
):
|
||||||
|
for cp in self.game.theater.controlpoints:
|
||||||
|
if cp.coalition == flight.coalition or not isinstance(
|
||||||
|
cp, Airfield
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
flight.package.target = cp
|
||||||
|
elif flight.flight_type == FlightType.DEAD:
|
||||||
|
for cp in self.game.theater.controlpoints:
|
||||||
|
if cp.coalition == flight.coalition:
|
||||||
|
continue
|
||||||
|
for ground_object in cp.ground_objects:
|
||||||
|
is_ewr = isinstance(ground_object, EwrGroundObject)
|
||||||
|
is_sam = isinstance(ground_object, SamGroundObject)
|
||||||
|
|
||||||
|
if is_ewr or is_sam:
|
||||||
|
flight.package.target = ground_object
|
||||||
|
elif flight.flight_type == FlightType.AIR_ASSAULT:
|
||||||
|
for cp in self.game.theater.closest_opposing_control_points():
|
||||||
|
if cp.coalition == flight.coalition:
|
||||||
|
continue
|
||||||
|
if flight.is_hercules:
|
||||||
|
if cp.coalition == flight.coalition or not isinstance(
|
||||||
|
cp, Airfield
|
||||||
|
):
|
||||||
|
continue
|
||||||
|
flight.package.target = cp
|
||||||
|
|
||||||
|
FlightGroupConfigurator(
|
||||||
|
flight,
|
||||||
|
group,
|
||||||
|
self.game,
|
||||||
|
self.mission,
|
||||||
|
self.time,
|
||||||
|
self.radio_registry,
|
||||||
|
self.tacan_registy,
|
||||||
|
self.laser_code_registry,
|
||||||
|
self.mission_data,
|
||||||
|
dynamic_runways,
|
||||||
|
self.use_client,
|
||||||
|
).configure()
|
||||||
|
# for unit in group.units:
|
||||||
|
# unit.set_client()
|
||||||
|
|
||||||
if self.ewrj:
|
if self.ewrj:
|
||||||
self._track_ewrj_flight(flight, group)
|
self._track_ewrj_flight(flight, group)
|
||||||
|
|||||||
@ -82,6 +82,7 @@ class PretenseFlightGroupSpawner(FlightGroupSpawner):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
if self.start_type is StartType.IN_FLIGHT:
|
if self.start_type is StartType.IN_FLIGHT:
|
||||||
|
if self.flight.client_count == 0:
|
||||||
self.flight.coalition.game.pretense_air[cp_side][cp_name_trimmed][
|
self.flight.coalition.game.pretense_air[cp_side][cp_name_trimmed][
|
||||||
self.flight.flight_type.name
|
self.flight.flight_type.name
|
||||||
].append(name)
|
].append(name)
|
||||||
@ -95,6 +96,7 @@ class PretenseFlightGroupSpawner(FlightGroupSpawner):
|
|||||||
f"Carrier group {carrier_group} is a "
|
f"Carrier group {carrier_group} is a "
|
||||||
f"{carrier_group.__class__.__name__}, expected a ShipGroup"
|
f"{carrier_group.__class__.__name__}, expected a ShipGroup"
|
||||||
)
|
)
|
||||||
|
if self.flight.client_count == 0:
|
||||||
self.flight.coalition.game.pretense_air[cp_side][cp_name_trimmed][
|
self.flight.coalition.game.pretense_air[cp_side][cp_name_trimmed][
|
||||||
self.flight.flight_type.name
|
self.flight.flight_type.name
|
||||||
].append(name)
|
].append(name)
|
||||||
@ -125,6 +127,7 @@ class PretenseFlightGroupSpawner(FlightGroupSpawner):
|
|||||||
pad_group = self._generate_at_cp_ground_spawn(name, cp)
|
pad_group = self._generate_at_cp_ground_spawn(name, cp)
|
||||||
if pad_group is not None:
|
if pad_group is not None:
|
||||||
return pad_group
|
return pad_group
|
||||||
|
if self.flight.client_count == 0:
|
||||||
self.flight.coalition.game.pretense_air[cp_side][cp_name_trimmed][
|
self.flight.coalition.game.pretense_air[cp_side][cp_name_trimmed][
|
||||||
self.flight.flight_type.name
|
self.flight.flight_type.name
|
||||||
].append(name)
|
].append(name)
|
||||||
@ -145,6 +148,7 @@ class PretenseFlightGroupSpawner(FlightGroupSpawner):
|
|||||||
pad_group = self._generate_at_cp_ground_spawn(name, cp)
|
pad_group = self._generate_at_cp_ground_spawn(name, cp)
|
||||||
if pad_group is not None:
|
if pad_group is not None:
|
||||||
return pad_group
|
return pad_group
|
||||||
|
if self.flight.client_count == 0:
|
||||||
self.flight.coalition.game.pretense_air[cp_side][cp_name_trimmed][
|
self.flight.coalition.game.pretense_air[cp_side][cp_name_trimmed][
|
||||||
self.flight.flight_type.name
|
self.flight.flight_type.name
|
||||||
].append(name)
|
].append(name)
|
||||||
@ -155,6 +159,13 @@ class PretenseFlightGroupSpawner(FlightGroupSpawner):
|
|||||||
)
|
)
|
||||||
except NoParkingSlotError:
|
except NoParkingSlotError:
|
||||||
# Generated when there is no place on Runway or on Parking Slots
|
# Generated when there is no place on Runway or on Parking Slots
|
||||||
|
if self.flight.client_count > 0:
|
||||||
|
# Don't generate player airstarts
|
||||||
|
logging.warning(
|
||||||
|
"No room on runway or parking slots. Not generating a player air-start."
|
||||||
|
)
|
||||||
|
raise NoParkingSlotError
|
||||||
|
else:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
"No room on runway or parking slots. Starting from the air."
|
"No room on runway or parking slots. Starting from the air."
|
||||||
)
|
)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user