diff --git a/game/pretense/pretenseaircraftgenerator.py b/game/pretense/pretenseaircraftgenerator.py index aebf990b..3a956879 100644 --- a/game/pretense/pretenseaircraftgenerator.py +++ b/game/pretense/pretenseaircraftgenerator.py @@ -4,7 +4,7 @@ import logging import random from datetime import datetime from functools import cached_property -from typing import Any, Dict, List, TYPE_CHECKING, Tuple +from typing import Any, Dict, List, TYPE_CHECKING, Tuple, Optional from uuid import UUID from dcs import Point @@ -18,6 +18,7 @@ from game.ato.flightstate import Completed, WaitingForStart, Navigating from game.ato.flighttype import FlightType from game.ato.package import Package from game.ato.starttype import StartType +from game.coalition import Coalition from game.missiongenerator.aircraft.flightgroupconfigurator import ( FlightGroupConfigurator, ) @@ -32,11 +33,13 @@ from game.theater.controlpoint import ( ControlPoint, OffMapSpawn, ParkingType, + Airfield, ) from game.unitmap import UnitMap from game.missiongenerator.aircraft.aircraftpainter import AircraftPainter from game.missiongenerator.aircraft.flightdata import FlightData from game.data.weapons import WeaponType +from game.squadrons import Squadron if TYPE_CHECKING: from game import Game @@ -163,27 +166,26 @@ class PretenseAircraftGenerator: autogenerate_cargo_plane_squadron, ) - def generate_pretense_transport_squadron( + def generate_pretense_squadron( self, cp: ControlPoint, + coalition: Coalition, flight_type: FlightType, fixed_wing: bool, num_retries: int, - ) -> None: - from game.squadrons import Squadron - + ) -> Optional[Squadron]: """ - Generates a Pretense transport squadron from the faction squadron definitions. Use FlightType AIR_ASSAULT + Generates a Pretense squadron from the faction squadron definitions. Use FlightType AIR_ASSAULT for Pretense supply helicopters and TRANSPORT for off-map cargo plane squadrons. - + Retribution does not differentiate between fixed wing and rotary wing transport squadron definitions, which is why there is a retry mechanism in case the wrong type is returned. Use fixed_wing False for Pretense supply helicopters and fixed_wing True for off-map cargo plane squadrons. - - TODO: Find out if Pretense can handle rotary wing "cargo planes". + + TODO: Find out if Pretense can handle rotary wing "cargo planes". """ - squadron_def = cp.coalition.air_wing.squadron_def_generator.generate_for_task( + squadron_def = coalition.air_wing.squadron_def_generator.generate_for_task( flight_type, cp ) print( @@ -192,27 +194,27 @@ class PretenseAircraftGenerator: for retries in range(num_retries): if squadron_def is None or fixed_wing == squadron_def.aircraft.helicopter: squadron_def = ( - cp.coalition.air_wing.squadron_def_generator.generate_for_task( + coalition.air_wing.squadron_def_generator.generate_for_task( flight_type, cp ) ) # Failed, stop here if squadron_def is None: - return + return None squadron = Squadron.create_from( squadron_def, flight_type, 2, cp, - cp.coalition, + coalition, self.game, ) - if squadron.aircraft not in cp.coalition.air_wing.squadrons: - cp.coalition.air_wing.squadrons[squadron.aircraft] = list() - cp.coalition.air_wing.add_squadron(squadron) - return + if squadron.aircraft not in coalition.air_wing.squadrons: + coalition.air_wing.squadrons[squadron.aircraft] = list() + coalition.air_wing.add_squadron(squadron) + return squadron def generate_pretense_aircraft( self, cp: ControlPoint, ato: AirTaskingOrder @@ -287,6 +289,7 @@ class PretenseAircraftGenerator: FlightType.BARCAP in mission_types or FlightType.TARCAP in mission_types or FlightType.ESCORT in mission_types + or FlightType.INTERCEPTION in mission_types ) and num_of_cap < PRETENSE_BARCAP_FLIGHTS_PER_CP: flight_type = FlightType.BARCAP num_of_cap += 1 @@ -330,6 +333,137 @@ class PretenseAircraftGenerator: ato.add_package(package) return + def generate_pretense_aircraft_for_other_side( + self, cp: ControlPoint, coalition: Coalition, ato: AirTaskingOrder + ) -> None: + """ + Plans and generates AI aircraft groups/packages for Pretense + for the other side, which doesn't initially hold this control point. + + Aircraft generation is done by walking the control points which will be made into + Pretense "zones" and spawning flights for different missions. + After the flight is generated the package is added to the ATO so the flights + can be configured. + + Args: + cp: Control point to generate aircraft for. + coalition: Coalition to generate aircraft for. + ato: The ATO to generate aircraft for. + """ + + aircraft_per_flight = 1 + if cp.has_helipads and not cp.is_fleet: + flight_type = FlightType.AIR_ASSAULT + squadron = self.generate_pretense_squadron( + cp, + coalition, + flight_type, + False, + PRETENSE_SQUADRON_DEF_RETRIES, + ) + if squadron is not None: + squadron.owned_aircraft += PRETENSE_AI_AIRCRAFT_PER_FLIGHT + squadron.untasked_aircraft += PRETENSE_AI_AIRCRAFT_PER_FLIGHT + package = Package(cp, squadron.flight_db, auto_asap=False) + flight = Flight( + package, + squadron, + aircraft_per_flight, + flight_type, + StartType.COLD, + divert=cp, + ) + print( + f"Generated flight for {flight_type} flying {squadron.aircraft.name} at {squadron.location.name}" + ) + + package.add_flight(flight) + flight.state = WaitingForStart( + flight, self.game.settings, self.game.conditions.start_time + ) + ato.add_package(package) + if isinstance(cp, Airfield): + # Generate SEAD flight + flight_type = FlightType.SEAD + aircraft_per_flight = PRETENSE_AI_AIRCRAFT_PER_FLIGHT + squadron = self.generate_pretense_squadron( + cp, + coalition, + flight_type, + True, + PRETENSE_SQUADRON_DEF_RETRIES, + ) + if squadron is None: + squadron = self.generate_pretense_squadron( + cp, + coalition, + FlightType.DEAD, + True, + PRETENSE_SQUADRON_DEF_RETRIES, + ) + if squadron is not None: + squadron.owned_aircraft += PRETENSE_AI_AIRCRAFT_PER_FLIGHT + squadron.untasked_aircraft += PRETENSE_AI_AIRCRAFT_PER_FLIGHT + package = Package(cp, squadron.flight_db, auto_asap=False) + flight = Flight( + package, + squadron, + aircraft_per_flight, + flight_type, + StartType.COLD, + divert=cp, + ) + print( + f"Generated flight for {flight_type} flying {squadron.aircraft.name} at {squadron.location.name}" + ) + + package.add_flight(flight) + flight.state = WaitingForStart( + flight, self.game.settings, self.game.conditions.start_time + ) + ato.add_package(package) + + # Generate CAS flight + flight_type = FlightType.CAS + aircraft_per_flight = PRETENSE_AI_AIRCRAFT_PER_FLIGHT + squadron = self.generate_pretense_squadron( + cp, + coalition, + flight_type, + True, + PRETENSE_SQUADRON_DEF_RETRIES, + ) + if squadron is None: + squadron = self.generate_pretense_squadron( + cp, + coalition, + FlightType.BAI, + True, + PRETENSE_SQUADRON_DEF_RETRIES, + ) + if squadron is not None: + squadron.owned_aircraft += PRETENSE_AI_AIRCRAFT_PER_FLIGHT + squadron.untasked_aircraft += PRETENSE_AI_AIRCRAFT_PER_FLIGHT + package = Package(cp, squadron.flight_db, auto_asap=False) + flight = Flight( + package, + squadron, + aircraft_per_flight, + flight_type, + StartType.COLD, + divert=cp, + ) + print( + f"Generated flight for {flight_type} flying {squadron.aircraft.name} at {squadron.location.name}" + ) + + package.add_flight(flight) + flight.state = WaitingForStart( + flight, self.game.settings, self.game.conditions.start_time + ) + ato.add_package(package) + return + def initialize_pretense_data_structures( self, cp: ControlPoint, flight: Flight ) -> None: @@ -343,11 +477,15 @@ class PretenseAircraftGenerator: flight: The current flight being generated. """ flight_type = flight.flight_type.name - cp_side = 2 if cp.captured else 1 + is_player = True + cp_side = 2 if flight.coalition == self.game.coalition_for(is_player) else 1 cp_name_trimmed = "".join([i for i in cp.name.lower() if i.isalnum()]) if cp_name_trimmed not in flight.coalition.game.pretense_air[cp_side]: flight.coalition.game.pretense_air[cp_side][cp_name_trimmed] = {} + print( + f"Populated flight.coalition.game.pretense_air[{cp_side}][{cp_name_trimmed}]" + ) if ( flight_type not in flight.coalition.game.pretense_air[cp_side][cp_name_trimmed] @@ -355,6 +493,9 @@ class PretenseAircraftGenerator: flight.coalition.game.pretense_air[cp_side][cp_name_trimmed][ flight_type ] = list() + print( + f"Populated flight.coalition.game.pretense_air[{cp_side}][{cp_name_trimmed}][{flight_type}]" + ) return def generate_flights( @@ -373,29 +514,40 @@ class PretenseAircraftGenerator: dynamic_runways: Runway data for carriers and FARPs. """ - offmap_transport_cp = self.find_pretense_cargo_plane_cp(cp) + if country == cp.coalition.faction.country: + offmap_transport_cp = self.find_pretense_cargo_plane_cp(cp) - ( - autogenerate_transport_helicopter_squadron, - autogenerate_cargo_plane_squadron, - ) = self.should_generate_pretense_transports(cp.coalition.air_wing) + ( + autogenerate_transport_helicopter_squadron, + autogenerate_cargo_plane_squadron, + ) = self.should_generate_pretense_transports(cp.coalition.air_wing) - if autogenerate_transport_helicopter_squadron: - self.generate_pretense_transport_squadron( - offmap_transport_cp, - FlightType.AIR_ASSAULT, - False, - PRETENSE_SQUADRON_DEF_RETRIES, + if autogenerate_transport_helicopter_squadron: + self.generate_pretense_squadron( + offmap_transport_cp, + offmap_transport_cp.coalition, + FlightType.AIR_ASSAULT, + False, + PRETENSE_SQUADRON_DEF_RETRIES, + ) + if autogenerate_cargo_plane_squadron: + self.generate_pretense_squadron( + offmap_transport_cp, + offmap_transport_cp.coalition, + FlightType.TRANSPORT, + True, + PRETENSE_SQUADRON_DEF_RETRIES, + ) + + self.generate_pretense_aircraft(cp, ato) + else: + is_player = True + coalition = ( + self.game.coalition_for(is_player) + if country == self.game.coalition_for(is_player).faction.country + else self.game.coalition_for(False) ) - if autogenerate_cargo_plane_squadron: - self.generate_pretense_transport_squadron( - offmap_transport_cp, - FlightType.TRANSPORT, - True, - PRETENSE_SQUADRON_DEF_RETRIES, - ) - - self.generate_pretense_aircraft(cp, ato) + self.generate_pretense_aircraft_for_other_side(cp, coalition, ato) self._reserve_frequencies_and_tacan(ato) diff --git a/game/pretense/pretenseflightgroupspawner.py b/game/pretense/pretenseflightgroupspawner.py index 6f785ceb..51732d57 100644 --- a/game/pretense/pretenseflightgroupspawner.py +++ b/game/pretense/pretenseflightgroupspawner.py @@ -73,7 +73,13 @@ class PretenseFlightGroupSpawner(FlightGroupSpawner): def generate_flight_at_departure(self) -> FlyingGroup[Any]: cp = self.flight.departure name = namegen.next_pretense_aircraft_name(cp, self.flight) - cp_side = 2 if cp.captured else 1 + is_player = True + cp_side = ( + 2 + if self.flight.coalition + == self.flight.coalition.game.coalition_for(is_player) + else 1 + ) cp_name_trimmed = "".join([i for i in cp.name.lower() if i.isalnum()]) try: @@ -161,7 +167,13 @@ class PretenseFlightGroupSpawner(FlightGroupSpawner): def generate_mid_mission(self) -> FlyingGroup[Any]: assert isinstance(self.flight.state, InFlight) name = namegen.next_pretense_aircraft_name(self.flight.departure, self.flight) - cp_side = 2 if self.flight.departure.captured else 1 + is_player = True + cp_side = ( + 2 + if self.flight.coalition + == self.flight.coalition.game.coalition_for(is_player) + else 1 + ) cp_name_trimmed = "".join( [i for i in self.flight.departure.name.lower() if i.isalnum()] ) diff --git a/game/pretense/pretenseluagenerator.py b/game/pretense/pretenseluagenerator.py index 966724ef..7c5dc964 100644 --- a/game/pretense/pretenseluagenerator.py +++ b/game/pretense/pretenseluagenerator.py @@ -23,6 +23,8 @@ from game.missiongenerator.missiondata import MissionData if TYPE_CHECKING: from game import Game +PRETENSE_RED_SIDE = 1 +PRETENSE_BLUE_SIDE = 2 PRETENSE_NUMBER_OF_ZONES_TO_CONNECT_CARRIERS_TO = 2 @@ -54,68 +56,18 @@ class PretenseLuaGenerator(LuaGenerator): self.mission.triggerrules.triggers.remove(t) self.mission.triggerrules.triggers.append(t) - def generate_pretense_zone_land(self, cp_name: str, cp_side: int) -> str: + def generate_pretense_land_upgrade_supply(self, cp_name: str, cp_side: int): lua_string_zones = "" cp_name_trimmed = "".join([i for i in cp_name.lower() if i.isalnum()]) + cp_side_str = "blue" if cp_side == PRETENSE_BLUE_SIDE else "red" - lua_string_zones += f"zones.{cp_name_trimmed}:defineUpgrades(" + "{\n" - lua_string_zones += " [1] = { --red side\n" - lua_string_zones += " presets.upgrades.basic.tent:extend({\n" - lua_string_zones += f" name='{cp_name_trimmed}-tent-red',\n" - lua_string_zones += " products = {\n" - lua_string_zones += ( - " presets.special.red.infantry:extend({ name='" - + cp_name_trimmed - + "-defense-red'})\n" - ) - lua_string_zones += " }\n" - lua_string_zones += " }),\n" - lua_string_zones += " presets.upgrades.basic.comPost:extend({\n" - lua_string_zones += f" name = '{cp_name_trimmed}-com-red',\n" - lua_string_zones += " products = {\n" - lua_string_zones += ( - " presets.special.red.infantry:extend({ name='" - + cp_name_trimmed - + "-defense-red'}),\n" - ) - lua_string_zones += ( - " presets.defenses.red.infantry:extend({ name='" - + cp_name_trimmed - + "-garrison-red' })\n" - ) - lua_string_zones += " }\n" - lua_string_zones += " }),\n" - lua_string_zones += " },\n" - lua_string_zones += " [2] = --blue side\n" - lua_string_zones += " {\n" - lua_string_zones += " presets.upgrades.basic.tent:extend({\n" - lua_string_zones += f" name='{cp_name_trimmed}-tent-blue',\n" - lua_string_zones += " products = {\n" - lua_string_zones += ( - " presets.special.blue.infantry:extend({ name='" - + cp_name_trimmed - + "-defense-blue'})\n" - ) - lua_string_zones += " }\n" - lua_string_zones += " }),\n" - lua_string_zones += " presets.upgrades.basic.comPost:extend({\n" - lua_string_zones += f" name = '{cp_name_trimmed}-com-blue',\n" - lua_string_zones += " products = {\n" - lua_string_zones += ( - " presets.special.blue.infantry:extend({ name='" - + cp_name_trimmed - + "-defense-blue'}),\n" - ) - lua_string_zones += ( - " presets.defenses.blue.infantry:extend({ name='" - + cp_name_trimmed - + "-garrison-blue' })\n" - ) - lua_string_zones += " }\n" - lua_string_zones += " }),\n" lua_string_zones += " presets.upgrades.supply.fuelTank:extend({\n" lua_string_zones += ( - " name = '" + cp_name_trimmed + "-fueltank-blue',\n" + " name = '" + + cp_name_trimmed + + "-fueltank-" + + cp_side_str + + "',\n" ) lua_string_zones += " products = {\n" for ground_group in self.game.pretense_ground_supply[cp_side][cp_name_trimmed]: @@ -146,13 +98,19 @@ class PretenseLuaGenerator(LuaGenerator): lua_string_zones += " }),\n" lua_string_zones += " presets.upgrades.airdef.comCenter:extend({\n" lua_string_zones += ( - f" name = '{cp_name_trimmed}-mission-command-blue',\n" + f" name = '{cp_name_trimmed}-mission-command-" + + cp_side_str + + "',\n" ) lua_string_zones += " products = {\n" lua_string_zones += ( - " presets.defenses.blue.shorad:extend({ name='" + " presets.defenses." + + cp_side_str + + ".shorad:extend({ name='" + cp_name_trimmed - + "-sam-blue' }),\n" + + "-sam-" + + cp_side_str + + "' }),\n" ) for mission_type in self.game.pretense_air[cp_side][cp_name_trimmed]: if mission_type == FlightType.SEAD.name: @@ -256,6 +214,78 @@ class PretenseLuaGenerator(LuaGenerator): ) lua_string_zones += " }\n" lua_string_zones += " })\n" + + return lua_string_zones + + def generate_pretense_zone_land(self, cp_name: str) -> str: + lua_string_zones = "" + cp_name_trimmed = "".join([i for i in cp_name.lower() if i.isalnum()]) + + lua_string_zones += f"zones.{cp_name_trimmed}:defineUpgrades(" + "{\n" + lua_string_zones += " [1] = { --red side\n" + lua_string_zones += " presets.upgrades.basic.tent:extend({\n" + lua_string_zones += f" name='{cp_name_trimmed}-tent-red',\n" + lua_string_zones += " products = {\n" + lua_string_zones += ( + " presets.special.red.infantry:extend({ name='" + + cp_name_trimmed + + "-defense-red'})\n" + ) + lua_string_zones += " }\n" + lua_string_zones += " }),\n" + lua_string_zones += " presets.upgrades.basic.comPost:extend({\n" + lua_string_zones += f" name = '{cp_name_trimmed}-com-red',\n" + lua_string_zones += " products = {\n" + lua_string_zones += ( + " presets.special.red.infantry:extend({ name='" + + cp_name_trimmed + + "-defense-red'}),\n" + ) + lua_string_zones += ( + " presets.defenses.red.infantry:extend({ name='" + + cp_name_trimmed + + "-garrison-red' })\n" + ) + lua_string_zones += " }\n" + lua_string_zones += " }),\n" + + lua_string_zones += self.generate_pretense_land_upgrade_supply( + cp_name, PRETENSE_RED_SIDE + ) + + lua_string_zones += " },\n" + lua_string_zones += " [2] = --blue side\n" + lua_string_zones += " {\n" + lua_string_zones += " presets.upgrades.basic.tent:extend({\n" + lua_string_zones += f" name='{cp_name_trimmed}-tent-blue',\n" + lua_string_zones += " products = {\n" + lua_string_zones += ( + " presets.special.blue.infantry:extend({ name='" + + cp_name_trimmed + + "-defense-blue'})\n" + ) + lua_string_zones += " }\n" + lua_string_zones += " }),\n" + lua_string_zones += " presets.upgrades.basic.comPost:extend({\n" + lua_string_zones += f" name = '{cp_name_trimmed}-com-blue',\n" + lua_string_zones += " products = {\n" + lua_string_zones += ( + " presets.special.blue.infantry:extend({ name='" + + cp_name_trimmed + + "-defense-blue'}),\n" + ) + lua_string_zones += ( + " presets.defenses.blue.infantry:extend({ name='" + + cp_name_trimmed + + "-garrison-blue' })\n" + ) + lua_string_zones += " }\n" + lua_string_zones += " }),\n" + + lua_string_zones += self.generate_pretense_land_upgrade_supply( + cp_name, PRETENSE_BLUE_SIDE + ) + lua_string_zones += " }\n" lua_string_zones += "})\n" @@ -522,7 +552,7 @@ class PretenseLuaGenerator(LuaGenerator): if cp.is_fleet: lua_string_zones += self.generate_pretense_zone_sea(cp.name, cp_side) else: - lua_string_zones += self.generate_pretense_zone_land(cp.name, cp_side) + lua_string_zones += self.generate_pretense_zone_land(cp.name) lua_string_connman = " cm = ConnectionManager:new()\n" diff --git a/game/pretense/pretensemissiongenerator.py b/game/pretense/pretensemissiongenerator.py index 52e7349c..5d64622b 100644 --- a/game/pretense/pretensemissiongenerator.py +++ b/game/pretense/pretensemissiongenerator.py @@ -207,18 +207,19 @@ class PretenseMissionGenerator(MissionGenerator): self.game.red.ato.clear() for cp in self.game.theater.controlpoints: - if cp.captured: - ato = self.game.blue.ato - cp_country = self.p_country - else: - ato = self.game.red.ato - cp_country = self.e_country - aircraft_generator.generate_flights( - cp_country, - cp, - ato, - tgo_generator.runways, - ) + for country in (self.p_country, self.e_country): + + if country == self.p_country: + 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( + country, + cp, + ato, + tgo_generator.runways, + ) self.mission_data.flights = aircraft_generator.flights diff --git a/game/pretense/pretensetgogenerator.py b/game/pretense/pretensetgogenerator.py index ed86f157..bcb9a0c2 100644 --- a/game/pretense/pretensetgogenerator.py +++ b/game/pretense/pretensetgogenerator.py @@ -72,12 +72,15 @@ from game.theater import ( TheaterGroundObject, TheaterUnit, NavalControlPoint, + PresetLocation, ) from game.theater.theatergroundobject import ( CarrierGroundObject, GenericCarrierGroundObject, LhaGroundObject, MissileSiteGroundObject, + BuildingGroundObject, + VehicleGroupGroundObject, ) from game.theater.theatergroup import SceneryUnit, IadsGroundGroup, TheaterGroup from game.unitmap import UnitMap @@ -171,12 +174,7 @@ class PretenseGroundObjectGenerator(GroundObjectGenerator): cp_name_trimmed = "".join( [i for i in self.ground_object.control_point.name.lower() if i.isalnum()] ) - cp_side = 2 if self.ground_object.control_point.captured else 1 - for side in range(1, 3): - if cp_name_trimmed not in self.game.pretense_ground_supply[cp_side]: - self.game.pretense_ground_supply[side][cp_name_trimmed] = list() - if cp_name_trimmed not in self.game.pretense_ground_assault[cp_side]: - self.game.pretense_ground_assault[side][cp_name_trimmed] = list() + for group in self.ground_object.groups: vehicle_units: list[TheaterUnit] = [] ship_units: list[TheaterUnit] = [] @@ -275,7 +273,12 @@ class PretenseGroundObjectGenerator(GroundObjectGenerator): cp_name_trimmed = "".join( [i for i in self.ground_object.control_point.name.lower() if i.isalnum()] ) - cp_side = 2 if self.ground_object.control_point.captured else 1 + is_player = True + side = ( + 2 + if self.country == self.game.coalition_for(is_player).faction.country + else 1 + ) for unit in units: assert issubclass(unit.type, VehicleType) @@ -296,11 +299,11 @@ class PretenseGroundObjectGenerator(GroundObjectGenerator): group_role = group_name.split("-")[1] if group_role == "supply": - self.game.pretense_ground_supply[cp_side][cp_name_trimmed].append( + self.game.pretense_ground_supply[side][cp_name_trimmed].append( f"{vehicle_group.name}" ) elif group_role == "assault": - self.game.pretense_ground_assault[cp_side][cp_name_trimmed].append( + self.game.pretense_ground_assault[side][cp_name_trimmed].append( f"{vehicle_group.name}" ) else: @@ -361,6 +364,14 @@ class PretenseTgoGenerator(TgoGenerator): def generate(self) -> None: for cp in self.game.theater.controlpoints: + cp_name_trimmed = "".join([i for i in cp.name.lower() if i.isalnum()]) + for side in range(1, 3): + if cp_name_trimmed not in self.game.pretense_ground_supply[side]: + self.game.pretense_ground_supply[side][cp_name_trimmed] = list() + if cp_name_trimmed not in self.game.pretense_ground_assault[side]: + self.game.pretense_ground_assault[side][cp_name_trimmed] = list() + + # First generate units for the coalition, which initially holds this CP country = self.m.country(cp.coalition.faction.country.name) # Generate helipads @@ -431,4 +442,49 @@ class PretenseTgoGenerator(TgoGenerator): ground_object, country, self.game, self.m, self.unit_map ) generator.generate() + # Then generate ground supply and assault groups for the other coalition + other_coalition = cp.coalition + for coalition in cp.coalition.game.coalitions: + if coalition == cp.coalition: + continue + else: + other_coalition = coalition + country = self.m.country(other_coalition.faction.country.name) + for ground_object in cp.ground_objects: + generator: GroundObjectGenerator + if isinstance(ground_object, BuildingGroundObject): + new_ground_object = BuildingGroundObject( + name=ground_object.name, + category=ground_object.category, + location=PresetLocation( + f"{ground_object.name} {ground_object.id}", + ground_object.position, + ground_object.heading, + ), + control_point=ground_object.control_point, + is_fob_structure=ground_object.is_fob_structure, + task=ground_object.task, + ) + generator = PretenseGroundObjectGenerator( + new_ground_object, country, self.game, self.m, self.unit_map + ) + elif isinstance(ground_object, VehicleGroupGroundObject): + new_ground_object = VehicleGroupGroundObject( + name=ground_object.name, + location=PresetLocation( + f"{ground_object.name} {ground_object.id}", + ground_object.position, + ground_object.heading, + ), + control_point=ground_object.control_point, + task=ground_object.task, + ) + generator = PretenseGroundObjectGenerator( + new_ground_object, country, self.game, self.m, self.unit_map + ) + else: + continue + + generator.generate() + self.mission_data.runways = list(self.runways.values())