mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
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:
parent
6f4a12658d
commit
fbbc2536a1
@ -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
|
||||||
|
|||||||
@ -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:
|
||||||
|
if squadron.aircraft.helicopter and (
|
||||||
|
squadron.aircraft.capable_of(FlightType.TRANSPORT)
|
||||||
|
or squadron.aircraft.capable_of(FlightType.AIR_ASSAULT)
|
||||||
|
):
|
||||||
|
autogenerate_transport_helicopter_squadron = False
|
||||||
|
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 aircraft_type in air_wing.squadrons:
|
||||||
for squadron in air_wing.squadrons[aircraft_type]:
|
for squadron in air_wing.squadrons[aircraft_type]:
|
||||||
if squadron.aircraft.helicopter and (
|
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_transport_helicopter_squadron = False
|
number_of_pretense_cargo_plane_squadrons += 1
|
||||||
elif not squadron.aircraft.helicopter and (
|
return number_of_pretense_cargo_plane_squadrons
|
||||||
squadron.aircraft.capable_of(FlightType.TRANSPORT)
|
|
||||||
or squadron.aircraft.capable_of(FlightType.AIR_ASSAULT)
|
|
||||||
):
|
|
||||||
autogenerate_cargo_plane_squadron = False
|
|
||||||
return (
|
|
||||||
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)
|
||||||
|
|
||||||
|
|||||||
@ -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,32 +210,17 @@ 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,
|
||||||
)
|
)
|
||||||
|
aircraft_generator.generate_packages(
|
||||||
ato = self.game.blue.ato
|
country,
|
||||||
country = self.p_country
|
ato,
|
||||||
aircraft_generator.generate_packages(
|
tgo_generator.runways,
|
||||||
country,
|
)
|
||||||
ato,
|
|
||||||
tgo_generator.runways,
|
|
||||||
)
|
|
||||||
|
|
||||||
ato = self.game.red.ato
|
|
||||||
country = self.e_country
|
|
||||||
aircraft_generator.generate_packages(
|
|
||||||
country,
|
|
||||||
ato,
|
|
||||||
tgo_generator.runways,
|
|
||||||
)
|
|
||||||
|
|
||||||
self.mission_data.flights = aircraft_generator.flights
|
self.mission_data.flights = aircraft_generator.flights
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user