mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Recovery Tanker for carriers. (#2649)
Implement recovery tankers for carriers. UnitMap gets a little more data to store. Recovery tankers depend on the unit map.
This commit is contained in:
parent
a245ba80c3
commit
9a81121ac1
@ -14,6 +14,7 @@ Saves from 6.0.0 are compatible with 6.1.0
|
|||||||
|
|
||||||
* **[Factions]** Defaulted bluefor modern to use Georgian and Ukrainian liveries for Russian aircraft.
|
* **[Factions]** Defaulted bluefor modern to use Georgian and Ukrainian liveries for Russian aircraft.
|
||||||
* **[Factions]** Added Peru.
|
* **[Factions]** Added Peru.
|
||||||
|
* **[Flight Planning]** Refueling flights planned on aircraft carriers will act as a recovery tanker for the carrier.
|
||||||
* **[Loadouts]** Adjusted F-15E loadouts.
|
* **[Loadouts]** Adjusted F-15E loadouts.
|
||||||
* **[Modding]** Added support for the HMS Ariadne, Achilles, and Castle class.
|
* **[Modding]** Added support for the HMS Ariadne, Achilles, and Castle class.
|
||||||
* **[Modding]** Added HMS Invincible to the game data as a helicopter carrier.
|
* **[Modding]** Added HMS Invincible to the game data as a helicopter carrier.
|
||||||
|
|||||||
@ -3,6 +3,8 @@ from __future__ import annotations
|
|||||||
from typing import Any, TYPE_CHECKING, Type
|
from typing import Any, TYPE_CHECKING, Type
|
||||||
|
|
||||||
from game.ato import FlightType
|
from game.ato import FlightType
|
||||||
|
from game.ato.flightplans.shiprecoverytanker import RecoveryTankerFlightPlan
|
||||||
|
from game.theater.controlpoint import Carrier
|
||||||
from .aewc import AewcFlightPlan
|
from .aewc import AewcFlightPlan
|
||||||
from .airassault import AirAssaultFlightPlan
|
from .airassault import AirAssaultFlightPlan
|
||||||
from .airlift import AirliftFlightPlan
|
from .airlift import AirliftFlightPlan
|
||||||
@ -33,8 +35,13 @@ class FlightPlanBuilderTypes:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def for_flight(flight: Flight) -> Type[IBuilder[Any, Any]]:
|
def for_flight(flight: Flight) -> Type[IBuilder[Any, Any]]:
|
||||||
if flight.flight_type is FlightType.REFUELING:
|
if flight.flight_type is FlightType.REFUELING:
|
||||||
if flight.package.target.is_friendly(flight.squadron.player) or isinstance(
|
target = flight.package.target
|
||||||
flight.package.target, FrontLine
|
if target.is_friendly(flight.squadron.player) and isinstance(
|
||||||
|
target, Carrier
|
||||||
|
):
|
||||||
|
return RecoveryTankerFlightPlan.builder_type()
|
||||||
|
if target.is_friendly(flight.squadron.player) or isinstance(
|
||||||
|
target, FrontLine
|
||||||
):
|
):
|
||||||
return TheaterRefuelingFlightPlan.builder_type()
|
return TheaterRefuelingFlightPlan.builder_type()
|
||||||
return PackageRefuelingFlightPlan.builder_type()
|
return PackageRefuelingFlightPlan.builder_type()
|
||||||
|
|||||||
87
game/ato/flightplans/shiprecoverytanker.py
Normal file
87
game/ato/flightplans/shiprecoverytanker.py
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from datetime import timedelta
|
||||||
|
from typing import Iterator, Type
|
||||||
|
from game.ato.flightplans.standard import StandardFlightPlan, StandardLayout
|
||||||
|
from game.ato.flightplans.ibuilder import IBuilder
|
||||||
|
from game.ato.flightplans.standard import StandardLayout
|
||||||
|
from game.ato.flightplans.waypointbuilder import WaypointBuilder
|
||||||
|
from game.ato.flightwaypoint import FlightWaypoint
|
||||||
|
from game.utils import feet
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class RecoveryTankerLayout(StandardLayout):
|
||||||
|
nav_to: list[FlightWaypoint]
|
||||||
|
recovery_ship: FlightWaypoint
|
||||||
|
nav_from: list[FlightWaypoint]
|
||||||
|
|
||||||
|
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||||
|
yield self.departure
|
||||||
|
yield from self.nav_to
|
||||||
|
yield self.recovery_ship
|
||||||
|
yield from self.nav_from
|
||||||
|
yield self.arrival
|
||||||
|
if self.divert is not None:
|
||||||
|
yield self.divert
|
||||||
|
yield self.bullseye
|
||||||
|
|
||||||
|
|
||||||
|
class RecoveryTankerFlightPlan(StandardFlightPlan[RecoveryTankerLayout]):
|
||||||
|
@staticmethod
|
||||||
|
def builder_type() -> Type[Builder]:
|
||||||
|
return Builder
|
||||||
|
|
||||||
|
@property
|
||||||
|
def tot_waypoint(self) -> FlightWaypoint:
|
||||||
|
return self.layout.recovery_ship
|
||||||
|
|
||||||
|
@property
|
||||||
|
def mission_departure_time(self) -> timedelta:
|
||||||
|
return timedelta(hours=2)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def patrol_start_time(self) -> timedelta:
|
||||||
|
return self.package.time_over_target
|
||||||
|
|
||||||
|
@property
|
||||||
|
def patrol_end_time(self) -> timedelta:
|
||||||
|
return self.tot + self.mission_departure_time
|
||||||
|
|
||||||
|
def tot_for_waypoint(self, waypoint: FlightWaypoint) -> timedelta | None:
|
||||||
|
if waypoint == self.tot_waypoint:
|
||||||
|
return self.tot
|
||||||
|
return None
|
||||||
|
|
||||||
|
def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> timedelta | None:
|
||||||
|
if waypoint == self.tot_waypoint:
|
||||||
|
return self.tot + self.mission_departure_time
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
class Builder(IBuilder[RecoveryTankerFlightPlan, RecoveryTankerLayout]):
|
||||||
|
def layout(self) -> RecoveryTankerLayout:
|
||||||
|
|
||||||
|
# TODO: Propagate the ship position.
|
||||||
|
ship = self.package.target.position
|
||||||
|
|
||||||
|
builder = WaypointBuilder(self.flight, self.coalition)
|
||||||
|
|
||||||
|
recovery = builder.recovery_tanker(ship)
|
||||||
|
|
||||||
|
tanker_type = self.flight.unit_type
|
||||||
|
altitude = tanker_type.preferred_patrol_altitude
|
||||||
|
|
||||||
|
return RecoveryTankerLayout(
|
||||||
|
departure=builder.takeoff(self.flight.departure),
|
||||||
|
nav_to=builder.nav_path(self.flight.departure.position, ship, altitude),
|
||||||
|
nav_from=builder.nav_path(ship, self.flight.arrival.position, altitude),
|
||||||
|
recovery_ship=recovery,
|
||||||
|
arrival=builder.land(self.flight.arrival),
|
||||||
|
divert=builder.divert(self.flight.divert),
|
||||||
|
bullseye=builder.bullseye(),
|
||||||
|
)
|
||||||
|
|
||||||
|
def build(self) -> RecoveryTankerFlightPlan:
|
||||||
|
return RecoveryTankerFlightPlan(self.flight, self.layout())
|
||||||
@ -23,7 +23,7 @@ from game.theater import (
|
|||||||
TheaterGroundObject,
|
TheaterGroundObject,
|
||||||
TheaterUnit,
|
TheaterUnit,
|
||||||
)
|
)
|
||||||
from game.utils import Distance, meters, nautical_miles
|
from game.utils import Distance, feet, meters, nautical_miles
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from game.coalition import Coalition
|
from game.coalition import Coalition
|
||||||
@ -204,6 +204,19 @@ class WaypointBuilder:
|
|||||||
pretty_name="Refuel",
|
pretty_name="Refuel",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def recovery_tanker(self, position: Point) -> FlightWaypoint:
|
||||||
|
alt_type: AltitudeReference = "BARO"
|
||||||
|
|
||||||
|
return FlightWaypoint(
|
||||||
|
"RECOVERY",
|
||||||
|
FlightWaypointType.RECOVERY_TANKER,
|
||||||
|
position,
|
||||||
|
feet(6000),
|
||||||
|
alt_type,
|
||||||
|
description="Recovery tanker for aircraft carriers",
|
||||||
|
pretty_name="Recovery",
|
||||||
|
)
|
||||||
|
|
||||||
def split(self, position: Point) -> FlightWaypoint:
|
def split(self, position: Point) -> FlightWaypoint:
|
||||||
alt_type: AltitudeReference = "BARO"
|
alt_type: AltitudeReference = "BARO"
|
||||||
if self.is_helo:
|
if self.is_helo:
|
||||||
|
|||||||
@ -49,3 +49,4 @@ class FlightWaypointType(IntEnum):
|
|||||||
REFUEL = 29 # Should look for nearby tanker to refuel from.
|
REFUEL = 29 # Should look for nearby tanker to refuel from.
|
||||||
CARGO_STOP = 30 # Stopover landing point using the LandingReFuAr waypoint type
|
CARGO_STOP = 30 # Stopover landing point using the LandingReFuAr waypoint type
|
||||||
INGRESS_AIR_ASSAULT = 31
|
INGRESS_AIR_ASSAULT = 31
|
||||||
|
RECOVERY_TANKER = 32
|
||||||
|
|||||||
@ -24,6 +24,7 @@ from dcs.unitgroup import FlyingGroup
|
|||||||
|
|
||||||
from game.ato import Flight, FlightType
|
from game.ato import Flight, FlightType
|
||||||
from game.ato.flightplans.aewc import AewcFlightPlan
|
from game.ato.flightplans.aewc import AewcFlightPlan
|
||||||
|
from game.ato.flightplans.shiprecoverytanker import RecoveryTankerFlightPlan
|
||||||
from game.ato.flightplans.theaterrefueling import TheaterRefuelingFlightPlan
|
from game.ato.flightplans.theaterrefueling import TheaterRefuelingFlightPlan
|
||||||
|
|
||||||
|
|
||||||
@ -246,7 +247,10 @@ class AircraftBehavior:
|
|||||||
def configure_refueling(self, group: FlyingGroup[Any], flight: Flight) -> None:
|
def configure_refueling(self, group: FlyingGroup[Any], flight: Flight) -> None:
|
||||||
group.task = Refueling.name
|
group.task = Refueling.name
|
||||||
|
|
||||||
if not isinstance(flight.flight_plan, TheaterRefuelingFlightPlan):
|
if not (
|
||||||
|
isinstance(flight.flight_plan, TheaterRefuelingFlightPlan)
|
||||||
|
or isinstance(flight.flight_plan, RecoveryTankerFlightPlan)
|
||||||
|
):
|
||||||
logging.error(
|
logging.error(
|
||||||
f"Cannot configure racetrack refueling tasks for {flight} because it "
|
f"Cannot configure racetrack refueling tasks for {flight} because it "
|
||||||
"does not have an racetrack refueling flight plan."
|
"does not have an racetrack refueling flight plan."
|
||||||
|
|||||||
@ -177,6 +177,7 @@ class AircraftGenerator:
|
|||||||
self.mission_data,
|
self.mission_data,
|
||||||
dynamic_runways,
|
dynamic_runways,
|
||||||
self.use_client,
|
self.use_client,
|
||||||
|
self.unit_map,
|
||||||
).configure()
|
).configure()
|
||||||
)
|
)
|
||||||
return group
|
return group
|
||||||
|
|||||||
@ -10,6 +10,7 @@ from dcs.unit import Skill
|
|||||||
from dcs.unitgroup import FlyingGroup
|
from dcs.unitgroup import FlyingGroup
|
||||||
|
|
||||||
from game.ato import Flight, FlightType
|
from game.ato import Flight, FlightType
|
||||||
|
from game.ato.flightplans.shiprecoverytanker import RecoveryTankerFlightPlan
|
||||||
from game.callsigns import callsign_for_support_unit
|
from game.callsigns import callsign_for_support_unit
|
||||||
from game.data.weapons import Pylon, WeaponType as WeaponTypeEnum
|
from game.data.weapons import Pylon, WeaponType as WeaponTypeEnum
|
||||||
from game.missiongenerator.missiondata import MissionData, AwacsInfo, TankerInfo
|
from game.missiongenerator.missiondata import MissionData, AwacsInfo, TankerInfo
|
||||||
@ -19,6 +20,7 @@ from game.radio.radios import RadioFrequency, RadioRegistry
|
|||||||
from game.radio.tacan import TacanBand, TacanRegistry, TacanUsage
|
from game.radio.tacan import TacanBand, TacanRegistry, TacanUsage
|
||||||
from game.runways import RunwayData
|
from game.runways import RunwayData
|
||||||
from game.squadrons import Pilot
|
from game.squadrons import Pilot
|
||||||
|
from game.unitmap import UnitMap
|
||||||
from .aircraftbehavior import AircraftBehavior
|
from .aircraftbehavior import AircraftBehavior
|
||||||
from .aircraftpainter import AircraftPainter
|
from .aircraftpainter import AircraftPainter
|
||||||
from .flightdata import FlightData
|
from .flightdata import FlightData
|
||||||
@ -44,6 +46,7 @@ class FlightGroupConfigurator:
|
|||||||
mission_data: MissionData,
|
mission_data: MissionData,
|
||||||
dynamic_runways: dict[str, RunwayData],
|
dynamic_runways: dict[str, RunwayData],
|
||||||
use_client: bool,
|
use_client: bool,
|
||||||
|
unit_map: UnitMap,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.flight = flight
|
self.flight = flight
|
||||||
self.group = group
|
self.group = group
|
||||||
@ -56,6 +59,7 @@ class FlightGroupConfigurator:
|
|||||||
self.mission_data = mission_data
|
self.mission_data = mission_data
|
||||||
self.dynamic_runways = dynamic_runways
|
self.dynamic_runways = dynamic_runways
|
||||||
self.use_client = use_client
|
self.use_client = use_client
|
||||||
|
self.unit_map = unit_map
|
||||||
|
|
||||||
def configure(self) -> FlightData:
|
def configure(self) -> FlightData:
|
||||||
AircraftBehavior(self.flight.flight_type).apply_to(self.flight, self.group)
|
AircraftBehavior(self.flight.flight_type).apply_to(self.flight, self.group)
|
||||||
@ -97,6 +101,7 @@ class FlightGroupConfigurator:
|
|||||||
self.time,
|
self.time,
|
||||||
self.game.settings,
|
self.game.settings,
|
||||||
self.mission_data,
|
self.mission_data,
|
||||||
|
self.unit_map,
|
||||||
).create_waypoints()
|
).create_waypoints()
|
||||||
|
|
||||||
return FlightData(
|
return FlightData(
|
||||||
@ -156,7 +161,9 @@ class FlightGroupConfigurator:
|
|||||||
blue=self.flight.departure.captured,
|
blue=self.flight.departure.captured,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
elif isinstance(self.flight.flight_plan, TheaterRefuelingFlightPlan):
|
elif isinstance(
|
||||||
|
self.flight.flight_plan, TheaterRefuelingFlightPlan
|
||||||
|
) or isinstance(self.flight.flight_plan, RecoveryTankerFlightPlan):
|
||||||
tacan = self.tacan_registry.alloc_for_band(TacanBand.Y, TacanUsage.AirToAir)
|
tacan = self.tacan_registry.alloc_for_band(TacanBand.Y, TacanUsage.AirToAir)
|
||||||
self.mission_data.tankers.append(
|
self.mission_data.tankers.append(
|
||||||
TankerInfo(
|
TankerInfo(
|
||||||
|
|||||||
@ -12,6 +12,7 @@ from game.ato import Flight, FlightWaypoint
|
|||||||
from game.ato.flightwaypointtype import FlightWaypointType
|
from game.ato.flightwaypointtype import FlightWaypointType
|
||||||
from game.missiongenerator.missiondata import MissionData
|
from game.missiongenerator.missiondata import MissionData
|
||||||
from game.theater import MissionTarget, TheaterUnit
|
from game.theater import MissionTarget, TheaterUnit
|
||||||
|
from game.unitmap import UnitMap
|
||||||
|
|
||||||
TARGET_WAYPOINTS = (
|
TARGET_WAYPOINTS = (
|
||||||
FlightWaypointType.TARGET_GROUP_LOC,
|
FlightWaypointType.TARGET_GROUP_LOC,
|
||||||
@ -29,6 +30,7 @@ class PydcsWaypointBuilder:
|
|||||||
mission: Mission,
|
mission: Mission,
|
||||||
elapsed_mission_time: timedelta,
|
elapsed_mission_time: timedelta,
|
||||||
mission_data: MissionData,
|
mission_data: MissionData,
|
||||||
|
unit_map: UnitMap,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.waypoint = waypoint
|
self.waypoint = waypoint
|
||||||
self.group = group
|
self.group = group
|
||||||
@ -37,6 +39,7 @@ class PydcsWaypointBuilder:
|
|||||||
self.mission = mission
|
self.mission = mission
|
||||||
self.elapsed_mission_time = elapsed_mission_time
|
self.elapsed_mission_time = elapsed_mission_time
|
||||||
self.mission_data = mission_data
|
self.mission_data = mission_data
|
||||||
|
self.unit_map = unit_map
|
||||||
|
|
||||||
def build(self) -> MovingPoint:
|
def build(self) -> MovingPoint:
|
||||||
waypoint = self.group.add_waypoint(
|
waypoint = self.group.add_waypoint(
|
||||||
|
|||||||
56
game/missiongenerator/aircraft/waypoints/recoverytanker.py
Normal file
56
game/missiongenerator/aircraft/waypoints/recoverytanker.py
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
from dcs.point import MovingPoint
|
||||||
|
from dcs.task import ActivateBeaconCommand, RecoveryTanker
|
||||||
|
|
||||||
|
from game.ato import FlightType
|
||||||
|
from game.missiongenerator.missiondata import TankerInfo
|
||||||
|
from game.utils import feet, knots
|
||||||
|
from .pydcswaypointbuilder import PydcsWaypointBuilder
|
||||||
|
|
||||||
|
|
||||||
|
class RecoveryTankerBuilder(PydcsWaypointBuilder):
|
||||||
|
def add_tasks(self, waypoint: MovingPoint) -> None:
|
||||||
|
if self.flight.flight_type == FlightType.REFUELING:
|
||||||
|
group_id = self._get_carrier_group_id()
|
||||||
|
speed = knots(250).meters_per_second
|
||||||
|
altitude = feet(6000).meters
|
||||||
|
# Last waypoint has index of 1.
|
||||||
|
last_waypoint = 2
|
||||||
|
recovery_tanker = RecoveryTanker(group_id, speed, altitude, last_waypoint)
|
||||||
|
|
||||||
|
waypoint.add_task(recovery_tanker)
|
||||||
|
|
||||||
|
self.configure_tanker_tacan(waypoint)
|
||||||
|
|
||||||
|
def _get_carrier_group_id(self) -> int:
|
||||||
|
name = self.package.target.name
|
||||||
|
carrier_position = self.package.target.position
|
||||||
|
theater_objects = self.unit_map.theater_objects
|
||||||
|
for key, value in theater_objects.items():
|
||||||
|
# Check name and position in case there are multiple of same carrier.
|
||||||
|
if name in key and value.theater_unit.position == carrier_position:
|
||||||
|
theater_mapping = value
|
||||||
|
break
|
||||||
|
assert theater_mapping is not None
|
||||||
|
return theater_mapping.dcs_group_id
|
||||||
|
|
||||||
|
def configure_tanker_tacan(self, waypoint: MovingPoint) -> None:
|
||||||
|
|
||||||
|
if self.flight.unit_type.dcs_unit_type.tacan:
|
||||||
|
tanker_info = self.mission_data.tankers[-1]
|
||||||
|
tacan = tanker_info.tacan
|
||||||
|
tacan_callsign = {
|
||||||
|
"Texaco": "TEX",
|
||||||
|
"Arco": "ARC",
|
||||||
|
"Shell": "SHL",
|
||||||
|
}.get(tanker_info.callsign)
|
||||||
|
|
||||||
|
waypoint.add_task(
|
||||||
|
ActivateBeaconCommand(
|
||||||
|
tacan.number,
|
||||||
|
tacan.band.value,
|
||||||
|
tacan_callsign,
|
||||||
|
bearing=True,
|
||||||
|
unit_id=self.group.units[0].id,
|
||||||
|
aa=True,
|
||||||
|
)
|
||||||
|
)
|
||||||
@ -17,8 +17,12 @@ from game.ato.flightstate import InFlight, WaitingForStart
|
|||||||
from game.ato.flightwaypointtype import FlightWaypointType
|
from game.ato.flightwaypointtype import FlightWaypointType
|
||||||
from game.ato.starttype import StartType
|
from game.ato.starttype import StartType
|
||||||
from game.missiongenerator.aircraft.waypoints.cargostop import CargoStopBuilder
|
from game.missiongenerator.aircraft.waypoints.cargostop import CargoStopBuilder
|
||||||
|
from game.missiongenerator.aircraft.waypoints.recoverytanker import (
|
||||||
|
RecoveryTankerBuilder,
|
||||||
|
)
|
||||||
from game.missiongenerator.missiondata import MissionData
|
from game.missiongenerator.missiondata import MissionData
|
||||||
from game.settings import Settings
|
from game.settings import Settings
|
||||||
|
from game.unitmap import UnitMap
|
||||||
from game.utils import pairwise
|
from game.utils import pairwise
|
||||||
from .baiingress import BaiIngressBuilder
|
from .baiingress import BaiIngressBuilder
|
||||||
from .landingzone import LandingZoneBuilder
|
from .landingzone import LandingZoneBuilder
|
||||||
@ -50,6 +54,7 @@ class WaypointGenerator:
|
|||||||
time: datetime,
|
time: datetime,
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
mission_data: MissionData,
|
mission_data: MissionData,
|
||||||
|
unit_map: UnitMap,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.flight = flight
|
self.flight = flight
|
||||||
self.group = group
|
self.group = group
|
||||||
@ -58,6 +63,7 @@ class WaypointGenerator:
|
|||||||
self.time = time
|
self.time = time
|
||||||
self.settings = settings
|
self.settings = settings
|
||||||
self.mission_data = mission_data
|
self.mission_data = mission_data
|
||||||
|
self.unit_map = unit_map
|
||||||
|
|
||||||
def create_waypoints(self) -> tuple[timedelta, list[FlightWaypoint]]:
|
def create_waypoints(self) -> tuple[timedelta, list[FlightWaypoint]]:
|
||||||
for waypoint in self.flight.points:
|
for waypoint in self.flight.points:
|
||||||
@ -135,6 +141,7 @@ class WaypointGenerator:
|
|||||||
FlightWaypointType.PICKUP_ZONE: LandingZoneBuilder,
|
FlightWaypointType.PICKUP_ZONE: LandingZoneBuilder,
|
||||||
FlightWaypointType.DROPOFF_ZONE: LandingZoneBuilder,
|
FlightWaypointType.DROPOFF_ZONE: LandingZoneBuilder,
|
||||||
FlightWaypointType.REFUEL: RefuelPointBuilder,
|
FlightWaypointType.REFUEL: RefuelPointBuilder,
|
||||||
|
FlightWaypointType.RECOVERY_TANKER: RecoveryTankerBuilder,
|
||||||
FlightWaypointType.CARGO_STOP: CargoStopBuilder,
|
FlightWaypointType.CARGO_STOP: CargoStopBuilder,
|
||||||
}
|
}
|
||||||
builder = builders.get(waypoint.waypoint_type, DefaultWaypointBuilder)
|
builder = builders.get(waypoint.waypoint_type, DefaultWaypointBuilder)
|
||||||
@ -145,6 +152,7 @@ class WaypointGenerator:
|
|||||||
self.mission,
|
self.mission,
|
||||||
self.elapsed_mission_time,
|
self.elapsed_mission_time,
|
||||||
self.mission_data,
|
self.mission_data,
|
||||||
|
self.unit_map,
|
||||||
)
|
)
|
||||||
|
|
||||||
def _estimate_min_fuel_for(self, waypoints: list[FlightWaypoint]) -> None:
|
def _estimate_min_fuel_for(self, waypoints: list[FlightWaypoint]) -> None:
|
||||||
|
|||||||
@ -147,7 +147,7 @@ class GroundObjectGenerator:
|
|||||||
vehicle_unit.position = unit.position
|
vehicle_unit.position = unit.position
|
||||||
vehicle_unit.heading = unit.position.heading.degrees
|
vehicle_unit.heading = unit.position.heading.degrees
|
||||||
vehicle_group.add_unit(vehicle_unit)
|
vehicle_group.add_unit(vehicle_unit)
|
||||||
self._register_theater_unit(unit, vehicle_group.units[-1])
|
self._register_theater_unit(vehicle_group.id, unit, vehicle_group.units[-1])
|
||||||
if vehicle_group is None:
|
if vehicle_group is None:
|
||||||
raise RuntimeError(f"Error creating VehicleGroup for {group_name}")
|
raise RuntimeError(f"Error creating VehicleGroup for {group_name}")
|
||||||
return vehicle_group
|
return vehicle_group
|
||||||
@ -180,7 +180,7 @@ class GroundObjectGenerator:
|
|||||||
ship_unit.position = unit.position
|
ship_unit.position = unit.position
|
||||||
ship_unit.heading = unit.position.heading.degrees
|
ship_unit.heading = unit.position.heading.degrees
|
||||||
ship_group.add_unit(ship_unit)
|
ship_group.add_unit(ship_unit)
|
||||||
self._register_theater_unit(unit, ship_group.units[-1])
|
self._register_theater_unit(ship_group.id, unit, ship_group.units[-1])
|
||||||
if ship_group is None:
|
if ship_group is None:
|
||||||
raise RuntimeError(f"Error creating ShipGroup for {group_name}")
|
raise RuntimeError(f"Error creating ShipGroup for {group_name}")
|
||||||
return ship_group
|
return ship_group
|
||||||
@ -194,7 +194,7 @@ class GroundObjectGenerator:
|
|||||||
heading=unit.position.heading.degrees,
|
heading=unit.position.heading.degrees,
|
||||||
dead=not unit.alive,
|
dead=not unit.alive,
|
||||||
)
|
)
|
||||||
self._register_theater_unit(unit, static_group.units[0])
|
self._register_theater_unit(static_group.id, unit, static_group.units[0])
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def enable_eplrs(group: VehicleGroup, unit_type: Type[VehicleType]) -> None:
|
def enable_eplrs(group: VehicleGroup, unit_type: Type[VehicleType]) -> None:
|
||||||
@ -209,10 +209,11 @@ class GroundObjectGenerator:
|
|||||||
|
|
||||||
def _register_theater_unit(
|
def _register_theater_unit(
|
||||||
self,
|
self,
|
||||||
|
dcs_group_id: int,
|
||||||
theater_unit: TheaterUnit,
|
theater_unit: TheaterUnit,
|
||||||
dcs_unit: Unit,
|
dcs_unit: Unit,
|
||||||
) -> None:
|
) -> None:
|
||||||
self.unit_map.add_theater_unit_mapping(theater_unit, dcs_unit)
|
self.unit_map.add_theater_unit_mapping(dcs_group_id, theater_unit, dcs_unit)
|
||||||
|
|
||||||
def add_trigger_zone_for_scenery(self, scenery: SceneryUnit) -> None:
|
def add_trigger_zone_for_scenery(self, scenery: SceneryUnit) -> None:
|
||||||
# Align the trigger zones to the faction color on the DCS briefing/F10 map.
|
# Align the trigger zones to the faction color on the DCS briefing/F10 map.
|
||||||
|
|||||||
@ -34,6 +34,7 @@ class FrontLineUnit:
|
|||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
class TheaterUnitMapping:
|
class TheaterUnitMapping:
|
||||||
|
dcs_group_id: int
|
||||||
theater_unit: TheaterUnit
|
theater_unit: TheaterUnit
|
||||||
dcs_unit: Unit
|
dcs_unit: Unit
|
||||||
|
|
||||||
@ -104,14 +105,16 @@ class UnitMap:
|
|||||||
return self.front_line_units.get(name, None)
|
return self.front_line_units.get(name, None)
|
||||||
|
|
||||||
def add_theater_unit_mapping(
|
def add_theater_unit_mapping(
|
||||||
self, theater_unit: TheaterUnit, dcs_unit: Unit
|
self, dcs_group_id: int, theater_unit: TheaterUnit, dcs_unit: Unit
|
||||||
) -> None:
|
) -> None:
|
||||||
# Deaths for units at TGOs are recorded in the corresponding GroundUnit within
|
# Deaths for units at TGOs are recorded in the corresponding GroundUnit within
|
||||||
# the GroundGroup, so we have to match the dcs unit with the liberation unit
|
# the GroundGroup, so we have to match the dcs unit with the liberation unit
|
||||||
name = str(dcs_unit.name)
|
name = str(dcs_unit.name)
|
||||||
if name in self.theater_objects:
|
if name in self.theater_objects:
|
||||||
raise RuntimeError(f"Duplicate TGO unit: {name}")
|
raise RuntimeError(f"Duplicate TGO unit: {name}")
|
||||||
self.theater_objects[name] = TheaterUnitMapping(theater_unit, dcs_unit)
|
self.theater_objects[name] = TheaterUnitMapping(
|
||||||
|
dcs_group_id, theater_unit, dcs_unit
|
||||||
|
)
|
||||||
|
|
||||||
def theater_units(self, name: str) -> Optional[TheaterUnitMapping]:
|
def theater_units(self, name: str) -> Optional[TheaterUnitMapping]:
|
||||||
return self.theater_objects.get(name, None)
|
return self.theater_objects.get(name, None)
|
||||||
|
|||||||
@ -32,7 +32,7 @@ pluggy==1.0.0
|
|||||||
pre-commit==2.19.0
|
pre-commit==2.19.0
|
||||||
py==1.11.0
|
py==1.11.0
|
||||||
pydantic==1.9.1
|
pydantic==1.9.1
|
||||||
-e git+https://github.com/pydcs/dcs@f12d70ea844076f95c74ffab92ec3dc9fdee32e4#egg=pydcs
|
-e git+https://github.com/pydcs/dcs@e755b655b7b28e9af3c1fa42263424b568413c04#egg=pydcs
|
||||||
pyinstaller==5.2
|
pyinstaller==5.2
|
||||||
pyinstaller-hooks-contrib==2022.8
|
pyinstaller-hooks-contrib==2022.8
|
||||||
pyparsing==3.0.9
|
pyparsing==3.0.9
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user