From afad73ac27cb407a66cf989b6f75a97178cf091d Mon Sep 17 00:00:00 2001 From: Druss99 <42724070+Druss99@users.noreply.github.com> Date: Sun, 10 Aug 2025 15:14:38 -0400 Subject: [PATCH] Fix bugs while loading air wing configs (#552) * fix bugs with air wing config loading * add aircraft type to airwing config for better loading --- changelog.md | 1 + game/campaignloader/campaignairwingconfig.py | 19 ++++++++++--------- .../campaignloader/defaultsquadronassigner.py | 10 +++++++--- game/theater/conflicttheater.py | 6 ++++++ qt_ui/windows/AirWingConfigurationDialog.py | 4 ++++ 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/changelog.md b/changelog.md index 07173e61..cd287cfc 100644 --- a/changelog.md +++ b/changelog.md @@ -17,6 +17,7 @@ ## Fixes * **[Flight Plans]** Fixed a bug when a package was created with only escort flights * **[Flight Plans]** Added AntiShipStrike as a fallback task for OCA/Aircraft to fix a bug where the S-3B could not do OCA/Aircraft +* **[Squadrons]** Fixed a bug where loading an air wing config would not properly load all squadrons # Retribution v1.4.1 (hotfix) diff --git a/game/campaignloader/campaignairwingconfig.py b/game/campaignloader/campaignairwingconfig.py index efe66838..af3ded5d 100644 --- a/game/campaignloader/campaignairwingconfig.py +++ b/game/campaignloader/campaignairwingconfig.py @@ -26,6 +26,7 @@ class SquadronConfig: name: Optional[str] nickname: Optional[str] female_pilot_percentage: Optional[int] + aircraft_type: Optional[str] @property def auto_assignable(self) -> set[FlightType]: @@ -51,6 +52,7 @@ class SquadronConfig: data.get("name", None), data.get("nickname", None), data.get("female_pilot_percentage", None), + data.get("aircraft_type", None), ) @staticmethod @@ -83,15 +85,14 @@ class CampaignAirWingConfig: try: base = theater.control_point_named(base_id) except: - if base_id == "Red CV": - base = next((c for c in carriers if not c.captured), None) - elif base_id == "Blue CV": - base = next((c for c in carriers if c.captured), None) - elif base_id == "Red LHA": - base = next((l for l in lhas if not l.captured), None) - elif base_id == "Blue LHA": - base = next((l for l in lhas if l.captured), None) - + logging.warning( + f"Control point {base_id} not found, trying to match by full name" + ) + if not base: + try: + base = theater.control_point_by_full_name(base_id) + except KeyError: + logging.error(f"Control point {base_id} not found, skipping") for squadron_data in squadron_configs: if base is None: logging.warning( diff --git a/game/campaignloader/defaultsquadronassigner.py b/game/campaignloader/defaultsquadronassigner.py index 624dc317..918d19ca 100644 --- a/game/campaignloader/defaultsquadronassigner.py +++ b/game/campaignloader/defaultsquadronassigner.py @@ -60,7 +60,7 @@ class DefaultSquadronAssigner: ) -> Optional[SquadronDef]: for preferred_aircraft in config.aircraft: squadron_def = self.find_preferred_squadron( - preferred_aircraft, config.primary, control_point + preferred_aircraft, config.aircraft_type, config.primary, control_point ) if squadron_def is not None: return squadron_def @@ -78,7 +78,11 @@ class DefaultSquadronAssigner: ) def find_preferred_squadron( - self, preferred_aircraft: str, task: FlightType, control_point: ControlPoint + self, + preferred_aircraft: str, + aircraft_type: Optional[str], + task: FlightType, + control_point: ControlPoint, ) -> Optional[SquadronDef]: # Attempt to find a squadron with the name in the request. squadron_def = self.find_squadron_by_name( @@ -90,7 +94,7 @@ class DefaultSquadronAssigner: # If the name didn't match a squadron available to this coalition, try to find # an aircraft with the matching name that meets the requirements. try: - aircraft = AircraftType.named(preferred_aircraft) + aircraft = AircraftType.named(aircraft_type or preferred_aircraft) except KeyError: logging.warning( "%s is neither a compatible squadron or a known aircraft type, " diff --git a/game/theater/conflicttheater.py b/game/theater/conflicttheater.py index c71af9fa..17d55a5c 100644 --- a/game/theater/conflicttheater.py +++ b/game/theater/conflicttheater.py @@ -292,6 +292,12 @@ class ConflictTheater: return cp raise KeyError(f"Cannot find ControlPoint named {name}") + def control_point_by_full_name(self, full_name: str) -> ControlPoint: + for cp in self.controlpoints: + if cp.full_name == full_name: + return cp + raise KeyError(f"Cannot find ControlPoint with full name {full_name}") + def find_carriers(self) -> List[ControlPoint]: try: carriers = [cp for cp in self.controlpoints if cp.is_carrier] diff --git a/qt_ui/windows/AirWingConfigurationDialog.py b/qt_ui/windows/AirWingConfigurationDialog.py index e674ced0..fec17c79 100644 --- a/qt_ui/windows/AirWingConfigurationDialog.py +++ b/qt_ui/windows/AirWingConfigurationDialog.py @@ -866,6 +866,7 @@ class AirWingConfigurationDialog(QDialog): if sec.value != s.primary_task.value ], "aircraft": [name], + "aircraft_type": s.aircraft.display_name, "size": s.max_size, } if squadrons.get(key): @@ -900,6 +901,9 @@ class AirWingConfigurationDialog(QDialog): w = self.tab_widget.currentWidget() assert isinstance(w, AirWingConfigurationTab) c = w.coalition + for s in c.air_wing.squadrons.values(): + for squadron in s: + c.air_wing.unclaim_squadron_def(squadron) c.air_wing.squadrons = defaultdict(list) config = CampaignAirWingConfig.from_campaign_data(airwing, c.game.theater) c.configure_default_air_wing(config)