mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +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 ..helipad import Helipad
|
||||
from ..scenery_group import SceneryGroup
|
||||
from pyproj import CRS, Transformer
|
||||
from shapely import geometry, ops
|
||||
@ -549,7 +550,7 @@ class MizCampaignLoader:
|
||||
for group in self.helipads:
|
||||
closest, distance = self.objective_info(group)
|
||||
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:
|
||||
|
||||
@ -10,6 +10,7 @@ from enum import Enum
|
||||
from functools import total_ordering
|
||||
from typing import Any, Dict, Iterator, List, Optional, Set, TYPE_CHECKING, Type, Union
|
||||
|
||||
from dcs import helicopters
|
||||
from dcs.mapping import Point
|
||||
from dcs.ships import (
|
||||
CVN_74_John_C__Stennis,
|
||||
@ -39,6 +40,7 @@ from .theatergroundobject import (
|
||||
VehicleGroupGroundObject,
|
||||
)
|
||||
from ..db import PRICES
|
||||
from ..helipad import Helipad
|
||||
from ..utils import nautical_miles
|
||||
from ..weather import Conditions
|
||||
|
||||
@ -296,7 +298,7 @@ class ControlPoint(MissionTarget, ABC):
|
||||
self.connected_objectives: List[TheaterGroundObject] = []
|
||||
self.base_defenses: List[BaseDefenseGroundObject] = []
|
||||
self.preset_locations = PresetLocations()
|
||||
self.helipads: List[PointWithHeading] = []
|
||||
self.helipads: List[Helipad] = []
|
||||
|
||||
# TODO: Should be Airbase specific.
|
||||
self.size = size
|
||||
@ -378,6 +380,29 @@ class ControlPoint(MissionTarget, ABC):
|
||||
return True
|
||||
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:
|
||||
"""Returns True if this control point is capable of recruiting ground units."""
|
||||
if not self.can_deploy_ground_units:
|
||||
@ -1084,10 +1109,13 @@ class Fob(ControlPoint):
|
||||
|
||||
@property
|
||||
def total_aircraft_parking(self) -> int:
|
||||
return 0
|
||||
return len(self.helipads)
|
||||
|
||||
def can_operate(self, aircraft: FlyingType) -> bool:
|
||||
return False
|
||||
if aircraft in helicopters.helicopter_map.values():
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@property
|
||||
def heading(self) -> int:
|
||||
|
||||
@ -46,4 +46,4 @@ class MissionTarget:
|
||||
|
||||
@property
|
||||
def strike_targets(self) -> List[Union[MissionTarget, Unit]]:
|
||||
raise NotImplementedError
|
||||
return []
|
||||
|
||||
@ -1110,18 +1110,43 @@ class AircraftConflictGenerator:
|
||||
at=self.m.find_group(group_name),
|
||||
)
|
||||
else:
|
||||
if not isinstance(cp, Airfield):
|
||||
raise RuntimeError(
|
||||
f"Attempted to spawn at airfield for non-airfield {cp}"
|
||||
|
||||
# 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):
|
||||
raise RuntimeError(
|
||||
f"Attempted to spawn at airfield for non-airfield {cp}"
|
||||
)
|
||||
group = self._generate_at_airport(
|
||||
name=name,
|
||||
side=country,
|
||||
unit_type=flight.unit_type,
|
||||
count=flight.count,
|
||||
start_type=flight.start_type,
|
||||
airport=cp.airport,
|
||||
)
|
||||
group = self._generate_at_airport(
|
||||
name=name,
|
||||
side=country,
|
||||
unit_type=flight.unit_type,
|
||||
count=flight.count,
|
||||
start_type=flight.start_type,
|
||||
airport=cp.airport,
|
||||
)
|
||||
except Exception as e:
|
||||
# Generated when there is no place on Runway or on Parking Slots
|
||||
logging.error(e)
|
||||
|
||||
@ -25,7 +25,11 @@ class ClosestAirfields:
|
||||
|
||||
@property
|
||||
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]:
|
||||
"""Iterates over all airfields within the given range of the target.
|
||||
|
||||
@ -142,6 +142,8 @@ class FlightWaypoint:
|
||||
PointAction.FromParkingArea: FlightWaypointType.TAKEOFF,
|
||||
PointAction.FromParkingAreaHot: FlightWaypointType.TAKEOFF,
|
||||
PointAction.FromRunway: FlightWaypointType.TAKEOFF,
|
||||
PointAction.FromGroundArea: FlightWaypointType.TAKEOFF,
|
||||
PointAction.FromGroundAreaHot: FlightWaypointType.TAKEOFF,
|
||||
}[point.action]
|
||||
if waypoint.waypoint_type == FlightWaypointType.NAV:
|
||||
waypoint.name = "NAV"
|
||||
|
||||
@ -1772,4 +1772,5 @@ class FlightPlanBuilder:
|
||||
for flight in self.package.flights:
|
||||
if flight.departure == airfield:
|
||||
return airfield
|
||||
|
||||
raise RuntimeError("Could not find any airfield assigned to this package")
|
||||
|
||||
@ -587,6 +587,8 @@ class HelipadGenerator:
|
||||
sp.position = pad.position
|
||||
sg.add_point(sp)
|
||||
country.add_static_group(sg)
|
||||
helipad.static_unit = sg
|
||||
helipad.occupied = False
|
||||
|
||||
|
||||
class GroundObjectsGenerator:
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user