Now generates air units for both sides at airfields.

This commit is contained in:
MetalStormGhost 2023-09-17 15:58:06 +03:00
parent 4e4eeff9ec
commit 51a4b6603d
5 changed files with 373 additions and 122 deletions

View File

@ -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)

View File

@ -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()]
)

View File

@ -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"

View File

@ -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

View File

@ -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())