Now generates one transport helicopter squadron for each control point which can operate one. Also implemented generating several Pretense cargo plane squadrons, defined by PRETENSE_AI_CARGO_PLANES_PER_SIDE. Cleaned up PretenseMissionGenerator.generate_air_units() a bit.

This commit is contained in:
MetalStormGhost 2023-09-23 12:59:50 +03:00
parent 6f4a12658d
commit fbbc2536a1
3 changed files with 75 additions and 68 deletions

View File

@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import random
from collections.abc import Iterator from collections.abc import Iterator
from dataclasses import dataclass from dataclasses import dataclass
from datetime import timedelta from datetime import timedelta
@ -17,7 +18,8 @@ if TYPE_CHECKING:
from ..flightwaypoint import FlightWaypoint from ..flightwaypoint import FlightWaypoint
PRETENSE_CARGO_FLIGHT_DISTANCE = 50000 PRETENSE_CARGO_FLIGHT_DISTANCE = 100000
PRETENSE_CARGO_FLIGHT_HEADING_RANGE = 20
class PretenseCargoFlightPlan(StandardFlightPlan[FerryLayout]): class PretenseCargoFlightPlan(StandardFlightPlan[FerryLayout]):
@ -67,8 +69,12 @@ class Builder(IBuilder[PretenseCargoFlightPlan, FerryLayout]):
offmap_transport_cp = self.coalition.game.theater.find_control_point_by_id( offmap_transport_cp = self.coalition.game.theater.find_control_point_by_id(
offmap_transport_cp_id offmap_transport_cp_id
) )
offmap_heading = random.randrange(
int(heading_from_flot - PRETENSE_CARGO_FLIGHT_HEADING_RANGE),
int(heading_from_flot + PRETENSE_CARGO_FLIGHT_HEADING_RANGE),
)
offmap_transport_spawn = offmap_transport_cp.position.point_from_heading( offmap_transport_spawn = offmap_transport_cp.position.point_from_heading(
heading_from_flot, PRETENSE_CARGO_FLIGHT_DISTANCE offmap_heading, PRETENSE_CARGO_FLIGHT_DISTANCE
) )
altitude_is_agl = self.flight.unit_type.dcs_unit_type.helicopter altitude_is_agl = self.flight.unit_type.dcs_unit_type.helicopter

View File

@ -37,6 +37,8 @@ from game.theater.controlpoint import (
OffMapSpawn, OffMapSpawn,
ParkingType, ParkingType,
Airfield, Airfield,
Carrier,
Lha,
) )
from game.theater.theatergroundobject import EwrGroundObject, SamGroundObject from game.theater.theatergroundobject import EwrGroundObject, SamGroundObject
from game.unitmap import UnitMap from game.unitmap import UnitMap
@ -47,13 +49,14 @@ if TYPE_CHECKING:
PRETENSE_SQUADRON_DEF_RETRIES = 100 PRETENSE_SQUADRON_DEF_RETRIES = 100
PRETENSE_SEAD_FLIGHTS_PER_CP = 1 PRETENSE_SEAD_FLIGHTS_PER_CP = 2
PRETENSE_CAS_FLIGHTS_PER_CP = 1 PRETENSE_CAS_FLIGHTS_PER_CP = 2
PRETENSE_STRIKE_FLIGHTS_PER_CP = 1 PRETENSE_STRIKE_FLIGHTS_PER_CP = 2
PRETENSE_BARCAP_FLIGHTS_PER_CP = 1 PRETENSE_BARCAP_FLIGHTS_PER_CP = 2
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_AI_CARGO_PLANES_PER_SIDE = 8
PRETENSE_PLAYER_AIRCRAFT_PER_FLIGHT = 2 PRETENSE_PLAYER_AIRCRAFT_PER_FLIGHT = 2
@ -138,35 +141,41 @@ class PretenseAircraftGenerator:
offmap_transport_cp_id = front_line_cp.id offmap_transport_cp_id = front_line_cp.id
return self.game.theater.find_control_point_by_id(offmap_transport_cp_id) return self.game.theater.find_control_point_by_id(offmap_transport_cp_id)
def should_generate_pretense_transports( def should_generate_pretense_transports_at(
self, air_wing: AirWing self, control_point: ControlPoint
) -> tuple[bool, bool]: ) -> bool:
""" """
Returns a tuple of booleans, telling whether transport helicopter and aircraft Returns a boolean, telling whether a transport helicopter squadron
squadrons should be generated from the faction squadron definitions. should be generated at control point from the faction squadron definitions.
This helps to ensure that the faction has at least one transport helicopter and one cargo plane squadron. This helps to ensure that the faction has at least one transport helicopter at each control point.
(autogenerate_transport_helicopter_squadron, autogenerate_cargo_plane_squadron)
""" """
autogenerate_transport_helicopter_squadron = True autogenerate_transport_helicopter_squadron = True
autogenerate_cargo_plane_squadron = True for squadron in control_point.squadrons:
for aircraft_type in air_wing.squadrons:
for squadron in air_wing.squadrons[aircraft_type]:
if squadron.aircraft.helicopter and ( if squadron.aircraft.helicopter and (
squadron.aircraft.capable_of(FlightType.TRANSPORT) squadron.aircraft.capable_of(FlightType.TRANSPORT)
or squadron.aircraft.capable_of(FlightType.AIR_ASSAULT) or squadron.aircraft.capable_of(FlightType.AIR_ASSAULT)
): ):
autogenerate_transport_helicopter_squadron = False autogenerate_transport_helicopter_squadron = False
elif not squadron.aircraft.helicopter and ( return autogenerate_transport_helicopter_squadron
def number_of_pretense_cargo_plane_sq_for(self, air_wing: AirWing) -> int:
"""
Returns how many Pretense cargo plane squadrons a specific coalition has.
This is used to define how many such squadrons should be generated from
the faction squadron definitions.
This helps to ensure that the faction has enough cargo plane squadrons.
"""
number_of_pretense_cargo_plane_squadrons = 0
for aircraft_type in air_wing.squadrons:
for squadron in air_wing.squadrons[aircraft_type]:
if not squadron.aircraft.helicopter and (
squadron.aircraft.capable_of(FlightType.TRANSPORT) squadron.aircraft.capable_of(FlightType.TRANSPORT)
or squadron.aircraft.capable_of(FlightType.AIR_ASSAULT) or squadron.aircraft.capable_of(FlightType.AIR_ASSAULT)
): ):
autogenerate_cargo_plane_squadron = False number_of_pretense_cargo_plane_squadrons += 1
return ( return number_of_pretense_cargo_plane_squadrons
autogenerate_transport_helicopter_squadron,
autogenerate_cargo_plane_squadron,
)
def generate_pretense_squadron( def generate_pretense_squadron(
self, self,
@ -375,6 +384,9 @@ class PretenseAircraftGenerator:
flight, self.game.settings, self.game.conditions.start_time flight, self.game.settings, self.game.conditions.start_time
) )
print(
f"Generated flight for {flight_type} flying {squadron.aircraft.name} at {squadron.location.name}"
)
ato.add_package(package) ato.add_package(package)
return return
@ -397,7 +409,7 @@ class PretenseAircraftGenerator:
""" """
aircraft_per_flight = 1 aircraft_per_flight = 1
if cp.has_helipads and not cp.is_fleet: if (cp.has_helipads or isinstance(cp, Airfield)) and not cp.is_fleet:
flight_type = FlightType.AIR_ASSAULT flight_type = FlightType.AIR_ASSAULT
squadron = self.generate_pretense_squadron( squadron = self.generate_pretense_squadron(
cp, cp,
@ -586,9 +598,6 @@ class PretenseAircraftGenerator:
for side in range(1, 3): for side in range(1, 3):
if cp_name_trimmed not in cp.coalition.game.pretense_air[side]: if cp_name_trimmed not in cp.coalition.game.pretense_air[side]:
cp.coalition.game.pretense_air[side][cp_name_trimmed] = {} cp.coalition.game.pretense_air[side][cp_name_trimmed] = {}
print(
f"Populated flight.coalition.game.pretense_air[{side}][{cp_name_trimmed}]"
)
return return
def initialize_pretense_data_structures_for_flight( def initialize_pretense_data_structures_for_flight(
@ -609,9 +618,6 @@ class PretenseAircraftGenerator:
for side in range(1, 3): for side in range(1, 3):
if cp_name_trimmed not in flight.coalition.game.pretense_air[side]: if cp_name_trimmed not in flight.coalition.game.pretense_air[side]:
flight.coalition.game.pretense_air[side][cp_name_trimmed] = {} flight.coalition.game.pretense_air[side][cp_name_trimmed] = {}
print(
f"Populated flight.coalition.game.pretense_air[{side}][{cp_name_trimmed}]"
)
if ( if (
flight_type flight_type
not in flight.coalition.game.pretense_air[side][cp_name_trimmed] not in flight.coalition.game.pretense_air[side][cp_name_trimmed]
@ -619,9 +625,6 @@ class PretenseAircraftGenerator:
flight.coalition.game.pretense_air[side][cp_name_trimmed][ flight.coalition.game.pretense_air[side][cp_name_trimmed][
flight_type flight_type
] = list() ] = list()
print(
f"Populated flight.coalition.game.pretense_air[{side}][{cp_name_trimmed}][{flight_type}]"
)
return return
def generate_flights( def generate_flights(
@ -644,20 +647,24 @@ class PretenseAircraftGenerator:
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)
( if (
autogenerate_transport_helicopter_squadron, cp.has_helipads
autogenerate_cargo_plane_squadron, or isinstance(cp, Airfield)
) = self.should_generate_pretense_transports(cp.coalition.air_wing) or isinstance(cp, Carrier)
or isinstance(cp, Lha)
if autogenerate_transport_helicopter_squadron: ) and self.should_generate_pretense_transports_at(cp):
self.generate_pretense_squadron( self.generate_pretense_squadron(
offmap_transport_cp, cp,
offmap_transport_cp.coalition, cp.coalition,
FlightType.AIR_ASSAULT, FlightType.AIR_ASSAULT,
False, False,
PRETENSE_SQUADRON_DEF_RETRIES, PRETENSE_SQUADRON_DEF_RETRIES,
) )
if autogenerate_cargo_plane_squadron: num_of_cargo_sq_to_generate = (
PRETENSE_AI_CARGO_PLANES_PER_SIDE
- self.number_of_pretense_cargo_plane_sq_for(cp.coalition.air_wing)
)
for i in range(num_of_cargo_sq_to_generate):
self.generate_pretense_squadron( self.generate_pretense_squadron(
offmap_transport_cp, offmap_transport_cp,
offmap_transport_cp.coalition, offmap_transport_cp.coalition,
@ -688,14 +695,19 @@ class PretenseAircraftGenerator:
ato: AirTaskingOrder, ato: AirTaskingOrder,
dynamic_runways: Dict[str, RunwayData], dynamic_runways: Dict[str, RunwayData],
) -> None: ) -> None:
for package in reversed(sorted(ato.packages, key=lambda x: x.time_over_target)): for package in ato.packages:
logging.info(f"Generating package for target: {package.target.name}") logging.info(
f"Generating package for target: {package.target.name}, has_players: {package.has_players}"
)
if not package.flights: if not package.flights:
continue continue
for flight in package.flights: for flight in package.flights:
self.initialize_pretense_data_structures_for_flight( self.initialize_pretense_data_structures_for_flight(
flight.departure, flight flight.departure, flight
) )
logging.info(
f"Generating flight in {flight.coalition.faction.name} package {flight.squadron.aircraft} {flight.flight_type} for target: {package.target.name}, departure: {flight.from_cp.name}"
)
if flight.alive: if flight.alive:
if not flight.squadron.location.runway_is_operational(): if not flight.squadron.location.runway_is_operational():
@ -712,6 +724,9 @@ class PretenseAircraftGenerator:
flight, country, dynamic_runways flight, country, dynamic_runways
) )
except NoParkingSlotError: except NoParkingSlotError:
logging.warning(
f"No room on runway or parking slots for {flight.squadron.aircraft} {flight.flight_type} for target: {package.target.name}. Not generating flight."
)
return return
self.unit_map.add_aircraft(group, flight) self.unit_map.add_aircraft(group, flight)

View File

@ -46,6 +46,7 @@ from .pretensetgogenerator import PretenseTgoGenerator
from .pretensetriggergenerator import PretenseTriggerGenerator from .pretensetriggergenerator import PretenseTriggerGenerator
from game.missiongenerator.visualsgenerator import VisualsGenerator from game.missiongenerator.visualsgenerator import VisualsGenerator
from ..ato import Flight from ..ato import Flight
from ..ato.airtaaskingorder import AirTaskingOrder
from ..missiongenerator import MissionGenerator from ..missiongenerator import MissionGenerator
from ..radio.TacanContainer import TacanContainer from ..radio.TacanContainer import TacanContainer
@ -209,27 +210,12 @@ class PretenseMissionGenerator(MissionGenerator):
for cp in self.game.theater.controlpoints: for cp in self.game.theater.controlpoints:
for country in (self.p_country, self.e_country): for country in (self.p_country, self.e_country):
if country == self.p_country: ato = AirTaskingOrder()
ato = self.game.blue.ato
else:
ato = self.game.red.ato
print(f"Running generate_flights for {country.name} at {cp.name}")
aircraft_generator.generate_flights( aircraft_generator.generate_flights(
country, country,
cp, cp,
ato, ato,
) )
ato = self.game.blue.ato
country = self.p_country
aircraft_generator.generate_packages(
country,
ato,
tgo_generator.runways,
)
ato = self.game.red.ato
country = self.e_country
aircraft_generator.generate_packages( aircraft_generator.generate_packages(
country, country,
ato, ato,