Changed helipad generation structure as to not impact "Game" object, as suggested by Dan.

This commit is contained in:
Khopa 2021-08-07 01:05:57 +02:00
parent 5412487178
commit 5e715daded
6 changed files with 44 additions and 82 deletions

View File

@ -1,25 +0,0 @@
from __future__ import annotations
from typing import Optional
from dcs import Point
from dcs.unitgroup import StaticGroup
from game.point_with_heading import PointWithHeading
from game.utils import Heading
class Helipad(PointWithHeading):
def __init__(self) -> None:
super(Helipad, self).__init__()
self.heading = Heading.from_degrees(0)
self.occupied = False
self.static_unit: Optional[StaticGroup] = None
@staticmethod
def from_point(point: Point, heading: Heading) -> Helipad:
h = Helipad()
h.x = point.x
h.y = point.y
h.heading = heading
return h

View File

@ -375,6 +375,7 @@ class Operation:
cls.laser_code_registry, cls.laser_code_registry,
cls.unit_map, cls.unit_map,
air_support=cls.airsupportgen.air_support, air_support=cls.airsupportgen.air_support,
helipads=cls.groundobjectgen.helipads,
) )
cls.airgen.clear_parking_slots() cls.airgen.clear_parking_slots()

View File

@ -56,7 +56,6 @@ from .landmap import Landmap, load_landmap, poly_contains
from .latlon import LatLon from .latlon import LatLon
from .projections import TransverseMercator from .projections import TransverseMercator
from .seasonalconditions import SeasonalConditions from .seasonalconditions import SeasonalConditions
from ..helipad import Helipad
from ..point_with_heading import PointWithHeading from ..point_with_heading import PointWithHeading
from ..positioned import Positioned from ..positioned import Positioned
from ..profiling import logged_duration from ..profiling import logged_duration
@ -482,7 +481,7 @@ class MizCampaignLoader:
for static in self.helipads: for static in self.helipads:
closest, distance = self.objective_info(static) closest, distance = self.objective_info(static)
closest.helipads.append( closest.helipads.append(
Helipad.from_point( PointWithHeading.from_point(
static.position, Heading.from_degrees(static.units[0].heading) static.position, Heading.from_degrees(static.units[0].heading)
) )
) )

View File

@ -49,7 +49,6 @@ from .theatergroundobject import (
) )
from ..dcs.aircrafttype import AircraftType from ..dcs.aircrafttype import AircraftType
from ..dcs.groundunittype import GroundUnitType from ..dcs.groundunittype import GroundUnitType
from ..helipad import Helipad
from ..utils import nautical_miles from ..utils import nautical_miles
from ..weather import Conditions from ..weather import Conditions
@ -307,7 +306,7 @@ class ControlPoint(MissionTarget, ABC):
self.at = at self.at = at
self.connected_objectives: List[TheaterGroundObject[Any]] = [] self.connected_objectives: List[TheaterGroundObject[Any]] = []
self.preset_locations = PresetLocations() self.preset_locations = PresetLocations()
self.helipads: List[Helipad] = [] self.helipads: List[PointWithHeading] = []
# TODO: Should be Airbase specific. # TODO: Should be Airbase specific.
self.size = size self.size = size
@ -400,22 +399,6 @@ class ControlPoint(MissionTarget, ABC):
""" """
return len(self.helipads) > 0 return len(self.helipads) > 0
@property
def has_free_helipad(self) -> bool:
"""
Returns true if cp has a free helipad
"""
return not all(h.occupied for h in self.helipads)
def get_free_helipad(self) -> Optional[Helipad]:
"""
Returns the first free additional helipad
"""
for h in self.helipads:
if not h.occupied:
return h
return None
def can_recruit_ground_units(self, game: Game) -> bool: def can_recruit_ground_units(self, game: Game) -> bool:
"""Returns True if this control point is capable of recruiting ground units.""" """Returns True if this control point is capable of recruiting ground units."""
if not self.can_deploy_ground_units: if not self.can_deploy_ground_units:

View File

@ -68,7 +68,6 @@ from game import db
from game.data.weapons import Pylon, WeaponType as WeaponTypeEnum from game.data.weapons import Pylon, WeaponType as WeaponTypeEnum
from game.dcs.aircrafttype import AircraftType from game.dcs.aircrafttype import AircraftType
from game.factions.faction import Faction from game.factions.faction import Faction
from game.helipad import Helipad
from game.settings import Settings from game.settings import Settings
from game.squadrons import Pilot from game.squadrons import Pilot
from game.theater.controlpoint import ( from game.theater.controlpoint import (
@ -229,6 +228,7 @@ class AircraftConflictGenerator:
laser_code_registry: LaserCodeRegistry, laser_code_registry: LaserCodeRegistry,
unit_map: UnitMap, unit_map: UnitMap,
air_support: AirSupport, air_support: AirSupport,
helipads: dict[ControlPoint, list[StaticGroup]],
) -> None: ) -> None:
self.m = mission self.m = mission
self.game = game self.game = game
@ -239,6 +239,7 @@ class AircraftConflictGenerator:
self.unit_map = unit_map self.unit_map = unit_map
self.flights: List[FlightData] = [] self.flights: List[FlightData] = []
self.air_support = air_support self.air_support = air_support
self.helipads = helipads
@cached_property @cached_property
def use_client(self) -> bool: def use_client(self) -> bool:
@ -550,40 +551,37 @@ class AircraftConflictGenerator:
unit_type, side.id, cp.name unit_type, side.id, cp.name
) )
) )
helipad = cp.get_free_helipad()
if helipad is not None and helipad.static_unit is not None: try:
helipad = self.helipads[cp].pop()
except IndexError as ex:
raise RuntimeError(f"Not enough helipads available at {cp}") from ex
group = self._generate_at_group( group = self._generate_at_group(
name=name, name=name,
side=side, side=side,
unit_type=unit_type, unit_type=unit_type,
count=count, count=count,
start_type=start_type, start_type=start_type,
at=helipad.static_unit, at=helipad,
) )
# Note : A bit dirty, need better support in pydcs # Note : A bit dirty, need better support in pydcs
group.points[0].action = PointAction.FromGroundArea group.points[0].action = PointAction.FromGroundArea
group.points[0].type = "TakeOffGround" group.points[0].type = "TakeOffGround"
group.units[0].heading = helipad.heading group.units[0].heading = helipad.units[0].heading
if start_type != "Cold": if start_type != "Cold":
group.points[0].action = PointAction.FromGroundAreaHot group.points[0].action = PointAction.FromGroundAreaHot
group.points[0].type = "TakeOffGroundHot" group.points[0].type = "TakeOffGroundHot"
helipad.occupied = True
for i in range(count - 1): for i in range(count - 1):
helipad = cp.get_free_helipad() try:
if helipad is not None: helipad = self.helipads[cp].pop()
helipad.occupied = True
group.units[1 + i].position = Point(helipad.x, helipad.y) group.units[1 + i].position = Point(helipad.x, helipad.y)
group.units[1 + i].heading = helipad.heading group.units[1 + i].heading = helipad.units[0].heading
else: except IndexError as ex:
raise RuntimeError( raise RuntimeError(f"Not enough helipads available at {cp}") from ex
f"Control Point {cp.name} does not have enough helipads"
)
return group return group
else:
raise RuntimeError(f"Control Point {cp.name} does not have enough helipads")
def _add_radio_waypoint( def _add_radio_waypoint(
self, self,

View File

@ -9,6 +9,7 @@ from __future__ import annotations
import logging import logging
import random import random
from collections import defaultdict
from typing import ( from typing import (
Dict, Dict,
Iterator, Iterator,
@ -587,6 +588,7 @@ class HelipadGenerator:
self.game = game self.game = game
self.radio_registry = radio_registry self.radio_registry = radio_registry
self.tacan_registry = tacan_registry self.tacan_registry = tacan_registry
self.helipads: list[StaticGroup] = []
def generate(self) -> None: def generate(self) -> None:
@ -595,7 +597,7 @@ class HelipadGenerator:
country = self.m.country(self.game.coalition_for(self.cp.captured).country_name) country = self.m.country(self.game.coalition_for(self.cp.captured).country_name)
for i, helipad in enumerate(self.cp.helipads): for i, helipad in enumerate(self.cp.helipads):
name = self.cp.name + "_helipad_" + str(i) name = self.cp.name + "_helipad_" + str(i)
logging.info("Generating helipad : " + name) logging.info("Generating helipad static : " + name)
pad = InvisibleFARP(name=name) pad = InvisibleFARP(name=name)
pad.position = Point(helipad.x, helipad.y) pad.position = Point(helipad.x, helipad.y)
pad.heading = helipad.heading.degrees pad.heading = helipad.heading.degrees
@ -606,8 +608,7 @@ class HelipadGenerator:
sg.add_point(sp) sg.add_point(sp)
neutral_country.add_static_group(sg) neutral_country.add_static_group(sg)
helipad.static_unit = sg self.helipads.append(sg)
helipad.occupied = False
# Generate a FARP Ammo and Fuel stack for each pad # Generate a FARP Ammo and Fuel stack for each pad
self.m.static_group( self.m.static_group(
@ -652,13 +653,18 @@ class GroundObjectsGenerator:
self.unit_map = unit_map self.unit_map = unit_map
self.icls_alloc = iter(range(1, 21)) self.icls_alloc = iter(range(1, 21))
self.runways: Dict[str, RunwayData] = {} self.runways: Dict[str, RunwayData] = {}
self.helipads: dict[ControlPoint, list[StaticGroup]] = defaultdict(list)
def generate(self) -> None: def generate(self) -> None:
for cp in self.game.theater.controlpoints: for cp in self.game.theater.controlpoints:
country = self.m.country(self.game.coalition_for(cp.captured).country_name) country = self.m.country(self.game.coalition_for(cp.captured).country_name)
HelipadGenerator(
# Generate helipads
helipad_gen = HelipadGenerator(
self.m, cp, self.game, self.radio_registry, self.tacan_registry self.m, cp, self.game, self.radio_registry, self.tacan_registry
).generate() )
helipad_gen.generate()
self.helipads[cp] = helipad_gen.helipads
for ground_object in cp.ground_objects: for ground_object in cp.ground_objects:
generator: GenericGroundObjectGenerator[Any] generator: GenericGroundObjectGenerator[Any]