diff --git a/game/ato/package.py b/game/ato/package.py index dea9c166..b91c8a61 100644 --- a/game/ato/package.py +++ b/game/ato/package.py @@ -13,6 +13,7 @@ from .flightplans.formation import FormationFlightPlan from .flighttype import FlightType from .packagewaypoints import PackageWaypoints from .traveltime import TotEstimator +from ..radio.radios import RadioFrequency if TYPE_CHECKING: from game.theater import ControlPoint, MissionTarget @@ -27,9 +28,11 @@ class Package: db: Database[Flight], auto_asap: bool = False, custom_name: str | None = None, + frequency: RadioFrequency | None = None, ) -> None: self.target = target self._db = db + self.frequency = frequency self.custom_name = custom_name # True if the package ToT should be reset to ASAP whenever the player makes a diff --git a/game/migrator.py b/game/migrator.py index 085c2d1d..d2821bef 100644 --- a/game/migrator.py +++ b/game/migrator.py @@ -48,3 +48,5 @@ class Migrator: for p in c.ato.packages: if not hasattr(p, "custom_name"): p.custom_name = None + if not hasattr(p, "frequency"): + p.frequency = None diff --git a/game/missiongenerator/aircraft/flightgroupconfigurator.py b/game/missiongenerator/aircraft/flightgroupconfigurator.py index 6e40caa2..2e5acab7 100644 --- a/game/missiongenerator/aircraft/flightgroupconfigurator.py +++ b/game/missiongenerator/aircraft/flightgroupconfigurator.py @@ -137,7 +137,11 @@ class FlightGroupConfigurator: channel = self.radio_registry.alloc_uhf() self.register_air_support(channel) else: - channel = self.flight.unit_type.alloc_flight_radio(self.radio_registry) + if (channel := self.flight.package.frequency) is None: + channel = self.radio_registry.alloc_uhf() + self.flight.package.frequency = channel + if self.flight.client_count: + channel = self.flight.unit_type.alloc_flight_radio(self.radio_registry) self.group.set_frequency(channel.mhz) return channel diff --git a/game/missiongenerator/kneeboard.py b/game/missiongenerator/kneeboard.py index 1834a5e1..37dac354 100644 --- a/game/missiongenerator/kneeboard.py +++ b/game/missiongenerator/kneeboard.py @@ -27,6 +27,7 @@ import math import textwrap from collections import defaultdict from dataclasses import dataclass +from itertools import groupby from pathlib import Path from typing import Dict, Iterator, List, Optional, TYPE_CHECKING, Tuple @@ -482,6 +483,7 @@ class SupportPage(KneeboardPage): def __init__( self, flight: FlightData, + package_flights: List[FlightData], comms: List[CommInfo], awacs: List[AwacsInfo], tankers: List[TankerInfo], @@ -490,6 +492,7 @@ class SupportPage(KneeboardPage): dark_kneeboard: bool, ) -> None: self.flight = flight + self.package_flights = package_flights self.comms = list(comms) self.awacs = awacs self.tankers = tankers @@ -506,6 +509,36 @@ class SupportPage(KneeboardPage): custom_name_title = "" writer.title(f"{self.flight.callsign} Support Info{custom_name_title}") + # Package Section + package = self.flight.package + custom = f' "{package.custom_name}"' if package.custom_name else "" + writer.heading(f"{package.package_description} Package{custom}") + freq = self.format_frequency(package.frequency).replace("\n", " - ") + writer.text(f" FREQ: {freq}", font=writer.table_font) + comm_ladder = [] + for comm in self.comms: + comm_ladder.append( + [ + comm.name, + "", + "", + str(len(self.flight.units)), + self.format_frequency(comm.freq), + ] + ) + for f in self.package_flights: + comm_ladder.append( + [ + f.callsign, + str(f.flight_type), + str(f.aircraft_type), + str(len(f.units)), + self.format_frequency(f.intra_flight_channel), + ] + ) + + writer.table(comm_ladder, headers=["Callsign", "Task", "Type", "#A/C", "FREQ"]) + # AEW&C writer.heading("AEW&C") aewc_ladder = [] @@ -534,14 +567,8 @@ class SupportPage(KneeboardPage): headers=["Callsign", "FREQ", "Depature", "ETD", "ETA"], ) - # Package Section - writer.heading("Comm ladder") comm_ladder = [] - for comm in self.comms: - comm_ladder.append( - [comm.name, "", "", "", self.format_frequency(comm.freq)] - ) - + writer.heading("Tankers:") for tanker in self.tankers: comm_ladder.append( [ @@ -573,7 +600,9 @@ class SupportPage(KneeboardPage): writer.write(path) - def format_frequency(self, frequency: RadioFrequency) -> str: + def format_frequency(self, frequency: Optional[RadioFrequency]) -> str: + if frequency is None: + return "" channel = self.flight.channel_for(frequency) if channel is None: return str(frequency) @@ -733,8 +762,13 @@ class KneeboardGenerator(MissionInfoGenerator): for flight in self.flights: if not flight.client_units: continue + package_flights = [ + f + for f in self.flights + if f.package is flight.package and f is not flight + ] all_flights[flight.aircraft_type].extend( - self.generate_flight_kneeboard(flight) + self.generate_flight_kneeboard(flight, package_flights) ) return all_flights @@ -745,7 +779,9 @@ class KneeboardGenerator(MissionInfoGenerator): return StrikeTaskPage(flight, self.dark_kneeboard) return None - def generate_flight_kneeboard(self, flight: FlightData) -> List[KneeboardPage]: + def generate_flight_kneeboard( + self, flight: FlightData, package_flights: List[FlightData] + ) -> List[KneeboardPage]: """Returns a list of kneeboard pages for the given flight.""" if flight.aircraft_type.utc_kneeboard: @@ -765,6 +801,7 @@ class KneeboardGenerator(MissionInfoGenerator): ), SupportPage( flight, + package_flights, self.comms, self.awacs, self.tankers, diff --git a/game/missiongenerator/missiongenerator.py b/game/missiongenerator/missiongenerator.py index e325ec5d..7b504862 100644 --- a/game/missiongenerator/missiongenerator.py +++ b/game/missiongenerator/missiongenerator.py @@ -250,13 +250,13 @@ class MissionGenerator: self.mission.country(self.game.red.country_name), ) + self.mission_data.flights = aircraft_generator.flights + for flight in aircraft_generator.flights: if not flight.client_units: continue flight.aircraft_type.assign_channels_for_flight(flight, self.mission_data) - self.mission_data.flights = aircraft_generator.flights - def generate_destroyed_units(self) -> None: """Add destroyed units to the Mission""" if not self.game.settings.perf_destroyed_units: diff --git a/game/radio/channels.py b/game/radio/channels.py index 8f18a14d..3b6600ce 100644 --- a/game/radio/channels.py +++ b/game/radio/channels.py @@ -76,6 +76,9 @@ class CommonRadioChannelAllocator(RadioChannelAllocator): for jtac in mission_data.jtacs: flight.assign_channel(radio_id, next(channel_alloc), jtac.freq) + if (freq := flight.package.frequency) is not None: + flight.assign_channel(radio_id, next(channel_alloc), freq) + if flight.arrival != flight.departure and flight.arrival.atc is not None: flight.assign_channel(radio_id, next(channel_alloc), flight.arrival.atc)