diff --git a/game/missiongenerator/aircraft/aircraftgenerator.py b/game/missiongenerator/aircraft/aircraftgenerator.py index 905e4f9c..8c13589e 100644 --- a/game/missiongenerator/aircraft/aircraftgenerator.py +++ b/game/missiongenerator/aircraft/aircraftgenerator.py @@ -3,7 +3,7 @@ from __future__ import annotations import logging from datetime import datetime from functools import cached_property -from typing import Any, Dict, List, TYPE_CHECKING +from typing import Any, Dict, TYPE_CHECKING from dcs.country import Country from dcs.mission import Mission @@ -58,7 +58,9 @@ class AircraftGenerator: self.radio_registry = radio_registry self.tacan_registy = tacan_registry self.unit_map = unit_map - self.flights: List[FlightData] = [] + # A list of per-package briefing data, which is in turn a list of per-flight + # briefing data. + self.briefing_data: list[list[FlightData]] = [] self.mission_data = mission_data self.helipads = helipads @@ -102,13 +104,16 @@ class AircraftGenerator: for package in ato.packages: if not package.flights: continue + package_briefing_data: list[FlightData] = [] for flight in package.flights: if flight.alive: logging.info(f"Generating flight: {flight.unit_type}") - group = self.create_and_configure_flight( + group, briefing_data = self.create_and_configure_flight( flight, country, dynamic_runways ) + package_briefing_data.append(briefing_data) self.unit_map.add_aircraft(group, flight) + self.briefing_data.append(package_briefing_data) def spawn_unused_aircraft( self, player_country: Country, enemy_country: Country @@ -157,26 +162,25 @@ class AircraftGenerator: def create_and_configure_flight( self, flight: Flight, country: Country, dynamic_runways: Dict[str, RunwayData] - ) -> FlyingGroup[Any]: + ) -> tuple[FlyingGroup[Any], FlightData]: """Creates and configures the flight group in the mission.""" group = FlightGroupSpawner( flight, country, self.mission, self.helipads ).create_flight_group() - self.flights.append( - FlightGroupConfigurator( - flight, - group, - self.game, - self.mission, - self.time, - self.radio_registry, - self.tacan_registy, - self.mission_data, - dynamic_runways, - self.use_client, - self.unit_map, - ).configure() - ) + + briefing_data = FlightGroupConfigurator( + flight, + group, + self.game, + self.mission, + self.time, + self.radio_registry, + self.tacan_registy, + self.mission_data, + dynamic_runways, + self.use_client, + self.unit_map, + ).configure() wpt = group.waypoint("LANDING") if flight.is_helo and isinstance(flight.arrival, Fob) and wpt: @@ -185,4 +189,4 @@ class AircraftGenerator: wpt.link_unit = hpad.id self.helipads[flight.arrival].units.append(hpad) - return group + return group, briefing_data diff --git a/game/missiongenerator/briefinggenerator.py b/game/missiongenerator/briefinggenerator.py index 2840bc31..e456d04b 100644 --- a/game/missiongenerator/briefinggenerator.py +++ b/game/missiongenerator/briefinggenerator.py @@ -56,7 +56,7 @@ class MissionInfoGenerator: self.game = game self.awacs: List[AwacsInfo] = [] self.comms: List[CommInfo] = [] - self.flights: List[FlightData] = [] + self.briefing_data: list[list[FlightData]] = [] self.jtacs: List[JtacInfo] = [] self.tankers: List[TankerInfo] = [] self.frontlines: List[FrontLineInfo] = [] @@ -79,13 +79,13 @@ class MissionInfoGenerator: """ self.comms.append(CommInfo(name, freq)) - def add_flight(self, flight: FlightData) -> None: + def add_package_briefing_data(self, data: list[FlightData]) -> None: """Adds flight info to the mission. Args: - flight: Flight information. + data: The list of briefing data for each flight in a package. """ - self.flights.append(flight) + self.briefing_data.append(data) def add_jtac(self, jtac: JtacInfo) -> None: """Adds a JTAC to the mission. @@ -177,12 +177,13 @@ class BriefingGenerator(MissionInfoGenerator): # TODO: This should determine if runway is friendly through a method more robust than the existing string match def generate_allied_flights_by_departure(self) -> None: """Create iterable to display allied flights grouped by departure airfield.""" - for flight in self.flights: - if not flight.client_units and flight.friendly: - name = flight.departure.airfield_name - if ( - name in self.allied_flights_by_departure - ): # where else can we get this? - self.allied_flights_by_departure[name].append(flight) - else: - self.allied_flights_by_departure[name] = [flight] + for package in self.briefing_data: + for flight in package: + if not flight.client_units and flight.friendly: + name = flight.departure.airfield_name + if ( + name in self.allied_flights_by_departure + ): # where else can we get this? + self.allied_flights_by_departure[name].append(flight) + else: + self.allied_flights_by_departure[name] = [flight] diff --git a/game/missiongenerator/kneeboard.py b/game/missiongenerator/kneeboard.py index 910d318e..4df573d1 100644 --- a/game/missiongenerator/kneeboard.py +++ b/game/missiongenerator/kneeboard.py @@ -724,12 +724,13 @@ class KneeboardGenerator(MissionInfoGenerator): that aircraft. """ all_flights: Dict[AircraftType, List[KneeboardPage]] = defaultdict(list) - for flight in self.flights: - if not flight.client_units: - continue - all_flights[flight.aircraft_type].extend( - self.generate_flight_kneeboard(flight) - ) + for flights in self.briefing_data: + for flight in flights: + if not flight.client_units: + continue + all_flights[flight.aircraft_type].extend( + self.generate_flight_kneeboard(flight) + ) return all_flights def generate_task_page(self, flight: FlightData) -> Optional[KneeboardPage]: diff --git a/game/missiongenerator/luagenerator.py b/game/missiongenerator/luagenerator.py index ada2f466..29a448e3 100644 --- a/game/missiongenerator/luagenerator.py +++ b/game/missiongenerator/luagenerator.py @@ -1,5 +1,6 @@ from __future__ import annotations +import itertools import logging import os from abc import ABC, abstractmethod @@ -135,37 +136,41 @@ class LuaGenerator: crate_item.add_key_value("weight", weight) target_points = lua_data.add_item("TargetPoints") - for flight in self.mission_data.flights: - if flight.friendly and flight.flight_type in [ - FlightType.ANTISHIP, - FlightType.DEAD, - FlightType.SEAD, - FlightType.STRIKE, - ]: - flight_type = str(flight.flight_type) - flight_target = flight.package.target - if flight_target: - flight_target_name = None - flight_target_type = None - if isinstance(flight_target, TheaterGroundObject): - flight_target_name = flight_target.obj_name - flight_target_type = ( - flight_type + f" TGT ({flight_target.category})" + all_packages = itertools.chain( + self.game.blue.ato.packages, self.game.red.ato.packages + ) + for package in all_packages: + for flight in package.flights: + if flight.blue and flight.flight_type in [ + FlightType.ANTISHIP, + FlightType.DEAD, + FlightType.SEAD, + FlightType.STRIKE, + ]: + flight_type = str(flight.flight_type) + flight_target = flight.package.target + if flight_target: + flight_target_name = None + flight_target_type = None + if isinstance(flight_target, TheaterGroundObject): + flight_target_name = flight_target.obj_name + flight_target_type = ( + flight_type + f" TGT ({flight_target.category})" + ) + elif hasattr(flight_target, "name"): + flight_target_name = flight_target.name + flight_target_type = flight_type + " TGT (Airbase)" + target_item = target_points.add_item() + if flight_target_name: + target_item.add_key_value("name", flight_target_name) + if flight_target_type: + target_item.add_key_value("type", flight_target_type) + target_item.add_key_value( + "positionX", str(flight_target.position.x) + ) + target_item.add_key_value( + "positionY", str(flight_target.position.y) ) - elif hasattr(flight_target, "name"): - flight_target_name = flight_target.name - flight_target_type = flight_type + " TGT (Airbase)" - target_item = target_points.add_item() - if flight_target_name: - target_item.add_key_value("name", flight_target_name) - if flight_target_type: - target_item.add_key_value("type", flight_target_type) - target_item.add_key_value( - "positionX", str(flight_target.position.x) - ) - target_item.add_key_value( - "positionY", str(flight_target.position.y) - ) for cp in self.game.theater.controlpoints: coalition_object = ( diff --git a/game/missiongenerator/missiondata.py b/game/missiongenerator/missiondata.py index 4143f970..1f6b5609 100644 --- a/game/missiongenerator/missiondata.py +++ b/game/missiongenerator/missiondata.py @@ -90,7 +90,7 @@ class MissionData: awacs: list[AwacsInfo] = field(default_factory=list) runways: list[RunwayData] = field(default_factory=list) carriers: list[CarrierInfo] = field(default_factory=list) - flights: list[FlightData] = field(default_factory=list) + briefing_data: list[list[FlightData]] = field(default_factory=list) tankers: list[TankerInfo] = field(default_factory=list) jtacs: list[JtacInfo] = field(default_factory=list) logistics: list[LogisticsInfo] = field(default_factory=list) diff --git a/game/missiongenerator/missiongenerator.py b/game/missiongenerator/missiongenerator.py index 5c789deb..75d00669 100644 --- a/game/missiongenerator/missiongenerator.py +++ b/game/missiongenerator/missiongenerator.py @@ -281,14 +281,15 @@ class MissionGenerator: self.mission.country(self.game.red.country_name), ) - for flight in aircraft_generator.flights: - if not flight.client_units: - continue - flight.aircraft_type.assign_channels_for_flight( - flight, air_support_generator.mission_data - ) + for package in aircraft_generator.briefing_data: + for flight in package: + if not flight.client_units: + continue + flight.aircraft_type.assign_channels_for_flight( + flight, air_support_generator.mission_data + ) - self.mission_data.flights = aircraft_generator.flights + self.mission_data.briefing_data = aircraft_generator.briefing_data def generate_destroyed_units(self) -> None: """Add destroyed units to the Mission""" @@ -344,8 +345,8 @@ class MissionGenerator: if jtac.blue: gen.add_jtac(jtac) - for flight in mission_data.flights: - gen.add_flight(flight) + for package in mission_data.briefing_data: + gen.add_package_briefing_data(package) gen.generate() def setup_combined_arms(self) -> None: