mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Helicopter flights can be planned from FOBs
This commit is contained in:
parent
844dc48d65
commit
d5990e60c9
13
game/helipad.py
Normal file
13
game/helipad.py
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from dcs.unitgroup import StaticGroup
|
||||||
|
|
||||||
|
from game.point_with_heading import PointWithHeading
|
||||||
|
|
||||||
|
|
||||||
|
class Helipad(PointWithHeading):
|
||||||
|
def __init__(self):
|
||||||
|
super(Helipad, self).__init__()
|
||||||
|
self.heading = 0
|
||||||
|
self.occupied = False
|
||||||
|
self.static_unit: Optional[StaticGroup] = None
|
||||||
@ -41,6 +41,7 @@ from dcs.unitgroup import (
|
|||||||
)
|
)
|
||||||
from dcs.vehicles import AirDefence, Armor, MissilesSS, Unarmed
|
from dcs.vehicles import AirDefence, Armor, MissilesSS, Unarmed
|
||||||
|
|
||||||
|
from ..helipad import Helipad
|
||||||
from ..scenery_group import SceneryGroup
|
from ..scenery_group import SceneryGroup
|
||||||
from pyproj import CRS, Transformer
|
from pyproj import CRS, Transformer
|
||||||
from shapely import geometry, ops
|
from shapely import geometry, ops
|
||||||
@ -549,7 +550,7 @@ class MizCampaignLoader:
|
|||||||
for group in self.helipads:
|
for group in self.helipads:
|
||||||
closest, distance = self.objective_info(group)
|
closest, distance = self.objective_info(group)
|
||||||
closest.helipads.append(
|
closest.helipads.append(
|
||||||
PointWithHeading.from_point(group.position, group.units[0].heading)
|
Helipad.from_point(group.position, group.units[0].heading)
|
||||||
)
|
)
|
||||||
|
|
||||||
for group in self.factories:
|
for group in self.factories:
|
||||||
|
|||||||
@ -10,6 +10,7 @@ from enum import Enum
|
|||||||
from functools import total_ordering
|
from functools import total_ordering
|
||||||
from typing import Any, Dict, Iterator, List, Optional, Set, TYPE_CHECKING, Type, Union
|
from typing import Any, Dict, Iterator, List, Optional, Set, TYPE_CHECKING, Type, Union
|
||||||
|
|
||||||
|
from dcs import helicopters
|
||||||
from dcs.mapping import Point
|
from dcs.mapping import Point
|
||||||
from dcs.ships import (
|
from dcs.ships import (
|
||||||
CVN_74_John_C__Stennis,
|
CVN_74_John_C__Stennis,
|
||||||
@ -39,6 +40,7 @@ from .theatergroundobject import (
|
|||||||
VehicleGroupGroundObject,
|
VehicleGroupGroundObject,
|
||||||
)
|
)
|
||||||
from ..db import PRICES
|
from ..db import PRICES
|
||||||
|
from ..helipad import Helipad
|
||||||
from ..utils import nautical_miles
|
from ..utils import nautical_miles
|
||||||
from ..weather import Conditions
|
from ..weather import Conditions
|
||||||
|
|
||||||
@ -296,7 +298,7 @@ class ControlPoint(MissionTarget, ABC):
|
|||||||
self.connected_objectives: List[TheaterGroundObject] = []
|
self.connected_objectives: List[TheaterGroundObject] = []
|
||||||
self.base_defenses: List[BaseDefenseGroundObject] = []
|
self.base_defenses: List[BaseDefenseGroundObject] = []
|
||||||
self.preset_locations = PresetLocations()
|
self.preset_locations = PresetLocations()
|
||||||
self.helipads: List[PointWithHeading] = []
|
self.helipads: List[Helipad] = []
|
||||||
|
|
||||||
# TODO: Should be Airbase specific.
|
# TODO: Should be Airbase specific.
|
||||||
self.size = size
|
self.size = size
|
||||||
@ -378,6 +380,29 @@ class ControlPoint(MissionTarget, ABC):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_helipads(self) -> bool:
|
||||||
|
"""
|
||||||
|
Returns true if cp has helipads
|
||||||
|
"""
|
||||||
|
return len(self.helipads) > 0
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_free_helipad(self) -> bool:
|
||||||
|
"""
|
||||||
|
Returns true if cp has a free helipad
|
||||||
|
"""
|
||||||
|
return False in [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:
|
||||||
@ -1084,9 +1109,12 @@ class Fob(ControlPoint):
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def total_aircraft_parking(self) -> int:
|
def total_aircraft_parking(self) -> int:
|
||||||
return 0
|
return len(self.helipads)
|
||||||
|
|
||||||
def can_operate(self, aircraft: FlyingType) -> bool:
|
def can_operate(self, aircraft: FlyingType) -> bool:
|
||||||
|
if aircraft in helicopters.helicopter_map.values():
|
||||||
|
return True
|
||||||
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
|||||||
@ -46,4 +46,4 @@ class MissionTarget:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def strike_targets(self) -> List[Union[MissionTarget, Unit]]:
|
def strike_targets(self) -> List[Union[MissionTarget, Unit]]:
|
||||||
raise NotImplementedError
|
return []
|
||||||
|
|||||||
@ -1110,6 +1110,31 @@ class AircraftConflictGenerator:
|
|||||||
at=self.m.find_group(group_name),
|
at=self.m.find_group(group_name),
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
||||||
|
# If the flight is an helicopter flight, then prioritize dedicated helipads
|
||||||
|
group = None
|
||||||
|
if flight.unit_type in helicopters.helicopter_map.values():
|
||||||
|
helipad = cp.get_free_helipad()
|
||||||
|
if helipad is not None:
|
||||||
|
group = self._generate_at_group(
|
||||||
|
name=name,
|
||||||
|
side=country,
|
||||||
|
unit_type=flight.unit_type,
|
||||||
|
count=flight.count,
|
||||||
|
start_type=flight.start_type,
|
||||||
|
at=helipad.static_unit,
|
||||||
|
)
|
||||||
|
group.points[0].action = PointAction.FromGroundArea
|
||||||
|
group.points[0].type = "From Ground Area"
|
||||||
|
helipad.occupied = True
|
||||||
|
|
||||||
|
for i in range(flight.count - 1):
|
||||||
|
helipad = cp.get_free_helipad()
|
||||||
|
if helipad is not None:
|
||||||
|
helipad.occupied = True
|
||||||
|
group.units[1 + i].position = Point(helipad.x, helipad.y)
|
||||||
|
|
||||||
|
if group is None:
|
||||||
if not isinstance(cp, Airfield):
|
if not isinstance(cp, Airfield):
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
f"Attempted to spawn at airfield for non-airfield {cp}"
|
f"Attempted to spawn at airfield for non-airfield {cp}"
|
||||||
|
|||||||
@ -25,7 +25,11 @@ class ClosestAirfields:
|
|||||||
|
|
||||||
@property
|
@property
|
||||||
def operational_airfields(self) -> Iterator[ControlPoint]:
|
def operational_airfields(self) -> Iterator[ControlPoint]:
|
||||||
return (c for c in self.closest_airfields if c.runway_is_operational())
|
return (
|
||||||
|
c
|
||||||
|
for c in self.closest_airfields
|
||||||
|
if c.runway_is_operational() or c.has_helipads
|
||||||
|
)
|
||||||
|
|
||||||
def airfields_within(self, distance: Distance) -> Iterator[ControlPoint]:
|
def airfields_within(self, distance: Distance) -> Iterator[ControlPoint]:
|
||||||
"""Iterates over all airfields within the given range of the target.
|
"""Iterates over all airfields within the given range of the target.
|
||||||
|
|||||||
@ -142,6 +142,8 @@ class FlightWaypoint:
|
|||||||
PointAction.FromParkingArea: FlightWaypointType.TAKEOFF,
|
PointAction.FromParkingArea: FlightWaypointType.TAKEOFF,
|
||||||
PointAction.FromParkingAreaHot: FlightWaypointType.TAKEOFF,
|
PointAction.FromParkingAreaHot: FlightWaypointType.TAKEOFF,
|
||||||
PointAction.FromRunway: FlightWaypointType.TAKEOFF,
|
PointAction.FromRunway: FlightWaypointType.TAKEOFF,
|
||||||
|
PointAction.FromGroundArea: FlightWaypointType.TAKEOFF,
|
||||||
|
PointAction.FromGroundAreaHot: FlightWaypointType.TAKEOFF,
|
||||||
}[point.action]
|
}[point.action]
|
||||||
if waypoint.waypoint_type == FlightWaypointType.NAV:
|
if waypoint.waypoint_type == FlightWaypointType.NAV:
|
||||||
waypoint.name = "NAV"
|
waypoint.name = "NAV"
|
||||||
|
|||||||
@ -1772,4 +1772,5 @@ class FlightPlanBuilder:
|
|||||||
for flight in self.package.flights:
|
for flight in self.package.flights:
|
||||||
if flight.departure == airfield:
|
if flight.departure == airfield:
|
||||||
return airfield
|
return airfield
|
||||||
|
|
||||||
raise RuntimeError("Could not find any airfield assigned to this package")
|
raise RuntimeError("Could not find any airfield assigned to this package")
|
||||||
|
|||||||
@ -587,6 +587,8 @@ class HelipadGenerator:
|
|||||||
sp.position = pad.position
|
sp.position = pad.position
|
||||||
sg.add_point(sp)
|
sg.add_point(sp)
|
||||||
country.add_static_group(sg)
|
country.add_static_group(sg)
|
||||||
|
helipad.static_unit = sg
|
||||||
|
helipad.occupied = False
|
||||||
|
|
||||||
|
|
||||||
class GroundObjectsGenerator:
|
class GroundObjectsGenerator:
|
||||||
|
|||||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user