mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Merge remote-tracking branch 'remotes/dcs-retribution/dcs-retribution/dev' into pretense-generator
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
import uuid
|
||||
from collections.abc import Iterator
|
||||
from datetime import datetime, timedelta
|
||||
@@ -9,6 +10,7 @@ from dcs import Point
|
||||
from dcs.planes import C_101CC, C_101EB, Su_33, FA_18C_hornet
|
||||
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.theater import ControlPoint, MissionTarget
|
||||
from pydcs_extensions.hercules.hercules import Hercules
|
||||
from .flightmembers import FlightMembers
|
||||
from .flightroster import FlightRoster
|
||||
@@ -33,7 +35,6 @@ if TYPE_CHECKING:
|
||||
from game.sim.gameupdateevents import GameUpdateEvents
|
||||
from game.sim.simulationresults import SimulationResults
|
||||
from game.squadrons import Squadron, Pilot
|
||||
from game.theater import ControlPoint
|
||||
from game.transfers import TransferOrder
|
||||
from game.data.weapons import WeaponType
|
||||
from .flightmember import FlightMember
|
||||
@@ -88,6 +89,7 @@ class Flight(
|
||||
|
||||
self.initialize_fuel()
|
||||
self.use_same_loadout_for_all_members = True
|
||||
self.use_same_livery_for_all_members = True
|
||||
|
||||
# Only used by transport missions.
|
||||
self.cargo = cargo
|
||||
@@ -123,6 +125,11 @@ class Flight(
|
||||
)
|
||||
)
|
||||
|
||||
# altitude offset for planes
|
||||
offset_factor = self.coalition.game.settings.max_plane_altitude_offset
|
||||
offset_factor = random.randint(0, offset_factor)
|
||||
self.plane_altitude_offset = 1000 * offset_factor * random.choice([-1, 1])
|
||||
|
||||
@property
|
||||
def available_callsigns(self) -> List[str]:
|
||||
callsigns = set()
|
||||
@@ -218,6 +225,13 @@ class Flight(
|
||||
def points(self) -> List[FlightWaypoint]:
|
||||
return self.flight_plan.waypoints[1:]
|
||||
|
||||
@property
|
||||
def custom_targets(self) -> List[MissionTarget]:
|
||||
return [
|
||||
MissionTarget(wpt.name, wpt.position)
|
||||
for wpt in self.flight_plan.layout.custom_waypoints
|
||||
]
|
||||
|
||||
def position(self) -> Point:
|
||||
return self.state.estimate_position()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import TYPE_CHECKING, Any
|
||||
from typing import TYPE_CHECKING, Any, Optional
|
||||
|
||||
from game.ato.loadouts import Loadout
|
||||
from game.lasercodes import LaserCode
|
||||
@@ -17,6 +17,7 @@ class FlightMember:
|
||||
self.tgp_laser_code: LaserCode | None = None
|
||||
self.weapon_laser_code: LaserCode | None = None
|
||||
self.properties: dict[str, bool | float | int] = {}
|
||||
self.livery: Optional[str] = None
|
||||
|
||||
def __setstate__(self, state: dict[str, Any]) -> None:
|
||||
if "tgp_laser_code" not in state:
|
||||
|
||||
@@ -95,6 +95,13 @@ class FlightMembers(IFlightRoster):
|
||||
# across all flight members.
|
||||
member.loadout = loadout
|
||||
|
||||
def use_same_livery_for_all_members(self) -> None:
|
||||
if not self.members:
|
||||
return
|
||||
livery = self.members[0].livery
|
||||
for member in self.members[1:]:
|
||||
member.livery = livery
|
||||
|
||||
def use_distinct_loadouts_for_each_member(self) -> None:
|
||||
for member in self.members:
|
||||
member.loadout = member.loadout.clone()
|
||||
|
||||
@@ -6,7 +6,7 @@ from typing import Type
|
||||
from game.ato.flightplans.ibuilder import IBuilder
|
||||
from game.ato.flightplans.patrolling import PatrollingFlightPlan, PatrollingLayout
|
||||
from game.ato.flightplans.waypointbuilder import WaypointBuilder
|
||||
from game.utils import Distance, Heading, Speed, feet, knots, meters, nautical_miles
|
||||
from game.utils import Distance, Heading, Speed, knots, meters, nautical_miles
|
||||
|
||||
|
||||
class AewcFlightPlan(PatrollingFlightPlan[PatrollingLayout]):
|
||||
@@ -70,10 +70,7 @@ class Builder(IBuilder[AewcFlightPlan, PatrollingLayout]):
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
if self.flight.unit_type.patrol_altitude is not None:
|
||||
altitude = self.flight.unit_type.patrol_altitude
|
||||
else:
|
||||
altitude = feet(25000)
|
||||
altitude = builder.get_patrol_altitude
|
||||
|
||||
racetrack = builder.race_track(racetrack_start, racetrack_end, altitude)
|
||||
|
||||
@@ -90,6 +87,7 @@ class Builder(IBuilder[AewcFlightPlan, PatrollingLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> AewcFlightPlan:
|
||||
|
||||
@@ -49,6 +49,7 @@ class AirAssaultLayout(FormationAttackLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class AirAssaultFlightPlan(FormationAttackFlightPlan, UiZoneDisplay):
|
||||
@@ -111,12 +112,11 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
|
||||
)
|
||||
assert self.package.waypoints is not None
|
||||
|
||||
heli_alt = feet(self.coalition.game.settings.heli_cruise_alt_agl)
|
||||
altitude = heli_alt if self.flight.is_helo else self.doctrine.ingress_altitude
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
altitude = builder.get_cruise_altitude
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
|
||||
if self.flight.is_hercules or self.flight.departure.cptype in [
|
||||
ControlPointType.AIRCRAFT_CARRIER_GROUP,
|
||||
ControlPointType.LHA_GROUP,
|
||||
@@ -133,13 +133,21 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
|
||||
self._generate_ctld_pickup(),
|
||||
)
|
||||
)
|
||||
pickup.alt = heli_alt
|
||||
pickup.alt = altitude
|
||||
pickup_position = pickup.position
|
||||
|
||||
ingress = builder.ingress(
|
||||
FlightWaypointType.INGRESS_AIR_ASSAULT,
|
||||
self.package.waypoints.ingress,
|
||||
self.package.target,
|
||||
ingress = (
|
||||
builder.ingress(
|
||||
FlightWaypointType.INGRESS_AIR_ASSAULT,
|
||||
self.package.waypoints.ingress,
|
||||
self.package.target,
|
||||
)
|
||||
if not self.flight.is_hercules
|
||||
else builder.ingress(
|
||||
FlightWaypointType.INGRESS_AIR_ASSAULT,
|
||||
self.package.waypoints.initial,
|
||||
self.package.target,
|
||||
)
|
||||
)
|
||||
|
||||
assault_area = builder.assault_area(self.package.target)
|
||||
@@ -159,8 +167,6 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
|
||||
drop_pos = tgt.position.point_from_heading(heading, 1200)
|
||||
drop_off_zone = MissionTarget("Dropoff zone", drop_pos)
|
||||
dz = builder.dropoff_zone(drop_off_zone) if self.flight.is_helo else None
|
||||
if dz:
|
||||
dz.alt = heli_alt
|
||||
|
||||
return AirAssaultLayout(
|
||||
departure=builder.takeoff(self.flight.departure),
|
||||
@@ -184,9 +190,10 @@ class Builder(FormationAttackBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
hold=None,
|
||||
join=builder.join(ingress.position),
|
||||
join=builder.join(self.package.waypoints.ingress),
|
||||
split=builder.split(self.flight.arrival.position),
|
||||
refuel=None,
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> AirAssaultFlightPlan:
|
||||
|
||||
@@ -8,7 +8,7 @@ from typing import Optional
|
||||
from typing import TYPE_CHECKING, Type
|
||||
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
from game.utils import feet, Distance
|
||||
from game.utils import Distance
|
||||
from ._common_ctld import generate_random_ctld_point
|
||||
from .ibuilder import IBuilder
|
||||
from .planningerror import PlanningError
|
||||
@@ -92,6 +92,7 @@ class AirliftLayout(StandardLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class AirliftFlightPlan(StandardFlightPlan[AirliftLayout]):
|
||||
@@ -132,12 +133,11 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
|
||||
"Cannot plan transport mission for flight with no cargo."
|
||||
)
|
||||
|
||||
heli_alt = feet(self.coalition.game.settings.heli_cruise_alt_agl)
|
||||
altitude = heli_alt if self.flight.is_helo else self.doctrine.ingress_altitude
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
altitude = builder.get_cruise_altitude
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
|
||||
pickup_ascent = None
|
||||
pickup_descent = None
|
||||
pickup = None
|
||||
@@ -246,6 +246,7 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> AirliftFlightPlan:
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from datetime import timedelta
|
||||
from typing import Type
|
||||
|
||||
from game.theater import FrontLine
|
||||
from game.utils import Distance, Speed, feet
|
||||
from game.utils import Distance, Speed
|
||||
from .capbuilder import CapBuilder
|
||||
from .invalidobjectivelocation import InvalidObjectiveLocation
|
||||
from .patrolling import PatrollingFlightPlan, PatrollingLayout
|
||||
@@ -41,14 +40,9 @@ class Builder(CapBuilder[BarCapFlightPlan, PatrollingLayout]):
|
||||
|
||||
start_pos, end_pos = self.cap_racetrack_for_objective(location, barcap=True)
|
||||
|
||||
preferred_alt = self.flight.unit_type.preferred_patrol_altitude
|
||||
randomized_alt = preferred_alt + feet(random.randint(-2, 1) * 1000)
|
||||
patrol_alt = max(
|
||||
self.doctrine.min_patrol_altitude,
|
||||
min(self.doctrine.max_patrol_altitude, randomized_alt),
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
patrol_alt = builder.get_patrol_altitude
|
||||
|
||||
start, end = builder.race_track(start_pos, end_pos, patrol_alt)
|
||||
|
||||
return PatrollingLayout(
|
||||
@@ -64,6 +58,7 @@ class Builder(CapBuilder[BarCapFlightPlan, PatrollingLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> BarCapFlightPlan:
|
||||
|
||||
@@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, Type
|
||||
|
||||
from game.theater import FrontLine
|
||||
from game.utils import Distance, Speed, kph, dcs_to_shapely_point
|
||||
from game.utils import feet, nautical_miles
|
||||
from game.utils import nautical_miles
|
||||
from .ibuilder import IBuilder
|
||||
from .invalidobjectivelocation import InvalidObjectiveLocation
|
||||
from .patrolling import PatrollingFlightPlan, PatrollingLayout
|
||||
@@ -37,6 +37,7 @@ class CasLayout(PatrollingLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class CasFlightPlan(PatrollingFlightPlan[CasLayout], UiZoneDisplay):
|
||||
@@ -104,11 +105,7 @@ class Builder(IBuilder[CasFlightPlan, CasLayout]):
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
is_helo = self.flight.unit_type.dcs_unit_type.helicopter
|
||||
ingress_egress_altitude = (
|
||||
self.doctrine.ingress_altitude
|
||||
if not is_helo
|
||||
else feet(self.coalition.game.settings.heli_combat_alt_agl)
|
||||
)
|
||||
ingress_egress_altitude = builder.get_combat_altitude
|
||||
use_agl_patrol_altitude = is_helo
|
||||
|
||||
ip_solver = IpSolver(
|
||||
@@ -167,6 +164,7 @@ class Builder(IBuilder[CasFlightPlan, CasLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> CasFlightPlan:
|
||||
|
||||
@@ -17,8 +17,6 @@ if TYPE_CHECKING:
|
||||
|
||||
@dataclass
|
||||
class CustomLayout(Layout):
|
||||
custom_waypoints: list[FlightWaypoint]
|
||||
|
||||
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
||||
yield self.departure
|
||||
yield from self.custom_waypoints
|
||||
|
||||
@@ -11,7 +11,6 @@ from .formationattack import (
|
||||
)
|
||||
from .waypointbuilder import WaypointBuilder
|
||||
from .. import FlightType
|
||||
from ...utils import feet
|
||||
|
||||
|
||||
class EscortFlightPlan(FormationAttackFlightPlan):
|
||||
@@ -43,12 +42,9 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
|
||||
split = builder.split(self._get_split())
|
||||
|
||||
ingress_alt = self.doctrine.ingress_altitude
|
||||
is_helo = builder.flight.is_helo
|
||||
heli_alt = feet(self.coalition.game.settings.heli_combat_alt_agl)
|
||||
initial = builder.escort_hold(
|
||||
target.position if is_helo else self.package.waypoints.initial,
|
||||
min(heli_alt, ingress_alt) if is_helo else ingress_alt,
|
||||
)
|
||||
|
||||
pf = self.package.primary_flight
|
||||
@@ -69,9 +65,6 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
if layout.drop_off:
|
||||
initial = builder.escort_hold(
|
||||
layout.drop_off.position,
|
||||
min(feet(200), ingress_alt)
|
||||
if builder.flight.is_helo
|
||||
else ingress_alt,
|
||||
)
|
||||
|
||||
refuel = self._build_refuel(builder)
|
||||
@@ -80,13 +73,13 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
nav_to = builder.nav_path(
|
||||
hold.position if hold else departure.position,
|
||||
join.position,
|
||||
self.doctrine.ingress_altitude,
|
||||
builder.get_cruise_altitude,
|
||||
)
|
||||
|
||||
nav_from = builder.nav_path(
|
||||
refuel.position if refuel else split.position,
|
||||
self.flight.arrival.position,
|
||||
self.doctrine.ingress_altitude,
|
||||
builder.get_cruise_altitude,
|
||||
)
|
||||
|
||||
return FormationAttackLayout(
|
||||
@@ -103,6 +96,7 @@ class Builder(FormationAttackBuilder[EscortFlightPlan, FormationAttackLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> EscortFlightPlan:
|
||||
|
||||
@@ -24,6 +24,7 @@ class FerryLayout(StandardLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class FerryFlightPlan(StandardFlightPlan[FerryLayout]):
|
||||
@@ -60,14 +61,14 @@ class Builder(IBuilder[FerryFlightPlan, FerryLayout]):
|
||||
f"{self.flight.departure}"
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
altitude = (
|
||||
feet(self.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if altitude_is_agl
|
||||
else self.flight.unit_type.preferred_patrol_altitude
|
||||
else builder.get_patrol_altitude
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
return FerryLayout(
|
||||
departure=builder.takeoff(self.flight.departure),
|
||||
nav_to=builder.nav_path(
|
||||
@@ -80,6 +81,7 @@ class Builder(IBuilder[FerryFlightPlan, FerryLayout]):
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
nav_from=[],
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> FerryFlightPlan:
|
||||
|
||||
@@ -34,6 +34,7 @@ if TYPE_CHECKING:
|
||||
@dataclass
|
||||
class Layout(ABC):
|
||||
departure: FlightWaypoint
|
||||
custom_waypoints: list[FlightWaypoint]
|
||||
|
||||
@property
|
||||
def waypoints(self) -> list[FlightWaypoint]:
|
||||
|
||||
@@ -11,7 +11,7 @@ from dcs import Point
|
||||
|
||||
from game.flightplan import HoldZoneGeometry
|
||||
from game.theater import MissionTarget
|
||||
from game.utils import Speed, meters, nautical_miles, feet
|
||||
from game.utils import Speed, meters, nautical_miles
|
||||
from .flightplan import FlightPlan
|
||||
from .formation import FormationFlightPlan, FormationLayout
|
||||
from .ibuilder import IBuilder
|
||||
@@ -157,6 +157,7 @@ class FormationAttackLayout(FormationLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
FlightPlanT = TypeVar("FlightPlanT", bound=FlightPlan[FormationAttackLayout])
|
||||
@@ -209,14 +210,10 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
if self.flight.flight_type == FlightType.STRIKE:
|
||||
hdg = self.package.target.position.heading_between_point(ingress.position)
|
||||
pos = ingress.position.point_from_heading(hdg, nautical_miles(10).meters)
|
||||
lineup = builder.nav(pos, self.flight.coalition.doctrine.ingress_altitude)
|
||||
lineup = builder.nav(pos, builder.get_combat_altitude)
|
||||
|
||||
is_helo = self.flight.is_helo
|
||||
ingress_egress_altitude = (
|
||||
self.doctrine.ingress_altitude
|
||||
if not is_helo
|
||||
else feet(self.coalition.game.settings.heli_combat_alt_agl)
|
||||
)
|
||||
ingress_egress_altitude = builder.get_combat_altitude
|
||||
use_agl_ingress_egress = is_helo
|
||||
|
||||
return FormationAttackLayout(
|
||||
@@ -244,6 +241,7 @@ class FormationAttackBuilder(IBuilder[FlightPlanT, LayoutT], ABC):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def _build_refuel(self, builder: WaypointBuilder) -> Optional[FlightWaypoint]:
|
||||
|
||||
@@ -25,6 +25,7 @@ class IBuilder(ABC, Generic[FlightPlanT, LayoutT]):
|
||||
def __init__(self, flight: Flight) -> None:
|
||||
self.flight = flight
|
||||
self._flight_plan: FlightPlanT | None = None
|
||||
self.settings = self.flight.coalition.game.settings
|
||||
|
||||
def get_or_build(self) -> FlightPlanT:
|
||||
if self._flight_plan is None:
|
||||
|
||||
@@ -5,7 +5,7 @@ from typing import Type
|
||||
|
||||
from dcs import Point
|
||||
|
||||
from game.utils import Distance, Heading, feet, meters
|
||||
from game.utils import Distance, Heading, meters
|
||||
from .ibuilder import IBuilder
|
||||
from .patrolling import PatrollingLayout
|
||||
from .refuelingflightplan import RefuelingFlightPlan
|
||||
@@ -98,11 +98,7 @@ class Builder(IBuilder[PackageRefuelingFlightPlan, PatrollingLayout]):
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
tanker_type = self.flight.unit_type
|
||||
if tanker_type.patrol_altitude is not None:
|
||||
altitude = tanker_type.patrol_altitude
|
||||
else:
|
||||
altitude = feet(21000)
|
||||
altitude = builder.get_patrol_altitude
|
||||
|
||||
racetrack = builder.race_track(racetrack_start, racetrack_end, altitude)
|
||||
|
||||
@@ -119,6 +115,7 @@ class Builder(IBuilder[PackageRefuelingFlightPlan, PatrollingLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> PackageRefuelingFlightPlan:
|
||||
|
||||
@@ -31,6 +31,7 @@ class PatrollingLayout(StandardLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
LayoutT = TypeVar("LayoutT", bound=PatrollingLayout)
|
||||
|
||||
@@ -27,6 +27,7 @@ class RtbLayout(StandardLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class RtbFlightPlan(StandardFlightPlan[RtbLayout]):
|
||||
@@ -65,13 +66,13 @@ class Builder(IBuilder[RtbFlightPlan, RtbLayout]):
|
||||
current_position = self.flight.state.estimate_position()
|
||||
current_altitude, altitude_reference = self.flight.state.estimate_altitude()
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
altitude_is_agl = self.flight.is_helo
|
||||
altitude = (
|
||||
feet(self.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if altitude_is_agl
|
||||
else self.flight.unit_type.preferred_patrol_altitude
|
||||
else builder.get_patrol_altitude
|
||||
)
|
||||
builder = WaypointBuilder(self.flight)
|
||||
abort_point = builder.nav(
|
||||
current_position, current_altitude, altitude_reference == "RADIO"
|
||||
)
|
||||
@@ -91,6 +92,7 @@ class Builder(IBuilder[RtbFlightPlan, RtbLayout]):
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
nav_from=[],
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> RtbFlightPlan:
|
||||
|
||||
@@ -70,6 +70,9 @@ class StandardLayout(Layout, ABC):
|
||||
elif waypoint in self.nav_from:
|
||||
self.nav_from.remove(waypoint)
|
||||
return True
|
||||
elif waypoint in self.custom_waypoints:
|
||||
self.custom_waypoints.remove(waypoint)
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ from .formationattack import (
|
||||
from .invalidobjectivelocation import InvalidObjectiveLocation
|
||||
from .waypointbuilder import StrikeTarget
|
||||
from ..flightwaypointtype import FlightWaypointType
|
||||
from ...theater.theatergroup import SceneryUnit
|
||||
|
||||
|
||||
class StrikeFlightPlan(FormationAttackFlightPlan):
|
||||
@@ -28,7 +29,10 @@ class Builder(FormationAttackBuilder[StrikeFlightPlan, FormationAttackLayout]):
|
||||
|
||||
targets: list[StrikeTarget] = []
|
||||
for idx, unit in enumerate(location.strike_targets):
|
||||
targets.append(StrikeTarget(f"{unit.type.id} #{idx}", unit))
|
||||
name = unit.type.id
|
||||
if isinstance(unit, SceneryUnit):
|
||||
name = unit.name
|
||||
targets.append(StrikeTarget(f"{name} #{idx}", unit))
|
||||
|
||||
return self._build(FlightWaypointType.INGRESS_STRIKE, targets)
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ class SweepLayout(LoiterLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
|
||||
class SweepFlightPlan(LoiterFlightPlan):
|
||||
@@ -104,26 +105,27 @@ class Builder(IBuilder[SweepFlightPlan, SweepLayout]):
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
start, end = builder.sweep(start_pos, target, self.doctrine.ingress_altitude)
|
||||
altitude = builder.get_patrol_altitude
|
||||
|
||||
start, end = builder.sweep(start_pos, target, altitude)
|
||||
|
||||
hold = builder.hold(self._hold_point())
|
||||
|
||||
return SweepLayout(
|
||||
departure=builder.takeoff(self.flight.departure),
|
||||
hold=hold,
|
||||
nav_to=builder.nav_path(
|
||||
hold.position, start.position, self.doctrine.ingress_altitude
|
||||
),
|
||||
nav_to=builder.nav_path(hold.position, start.position, altitude),
|
||||
nav_from=builder.nav_path(
|
||||
end.position,
|
||||
self.flight.arrival.position,
|
||||
self.doctrine.ingress_altitude,
|
||||
altitude,
|
||||
),
|
||||
sweep_start=start,
|
||||
sweep_end=end,
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def _hold_point(self) -> Point:
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import random
|
||||
from collections.abc import Iterator
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING, Type
|
||||
|
||||
from game.utils import Distance, Speed, feet
|
||||
from game.utils import Distance, Speed
|
||||
from .capbuilder import CapBuilder
|
||||
from .patrolling import PatrollingFlightPlan, PatrollingLayout
|
||||
from .waypointbuilder import WaypointBuilder
|
||||
@@ -31,6 +30,7 @@ class TarCapLayout(PatrollingLayout):
|
||||
if self.divert is not None:
|
||||
yield self.divert
|
||||
yield self.bullseye
|
||||
yield from self.custom_waypoints
|
||||
|
||||
def delete_waypoint(self, waypoint: FlightWaypoint) -> bool:
|
||||
if waypoint == self.refuel:
|
||||
@@ -95,14 +95,9 @@ class Builder(CapBuilder[TarCapFlightPlan, TarCapLayout]):
|
||||
def layout(self) -> TarCapLayout:
|
||||
location = self.package.target
|
||||
|
||||
preferred_alt = self.flight.unit_type.preferred_patrol_altitude
|
||||
randomized_alt = preferred_alt + feet(random.randint(-2, 1) * 1000)
|
||||
patrol_alt = max(
|
||||
self.doctrine.min_patrol_altitude,
|
||||
min(self.doctrine.max_patrol_altitude, randomized_alt),
|
||||
)
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
patrol_alt = builder.get_patrol_altitude
|
||||
|
||||
orbit0p, orbit1p = self.cap_racetrack_for_objective(location, barcap=False)
|
||||
|
||||
start, end = builder.race_track(orbit0p, orbit1p, patrol_alt)
|
||||
@@ -128,6 +123,7 @@ class Builder(CapBuilder[TarCapFlightPlan, TarCapLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> TarCapFlightPlan:
|
||||
|
||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
||||
from datetime import timedelta
|
||||
from typing import Type
|
||||
|
||||
from game.utils import Heading, feet, meters, nautical_miles
|
||||
from game.utils import Heading, meters, nautical_miles
|
||||
from .ibuilder import IBuilder
|
||||
from .patrolling import PatrollingLayout
|
||||
from .refuelingflightplan import RefuelingFlightPlan
|
||||
@@ -58,11 +58,7 @@ class Builder(IBuilder[TheaterRefuelingFlightPlan, PatrollingLayout]):
|
||||
|
||||
builder = WaypointBuilder(self.flight)
|
||||
|
||||
tanker_type = self.flight.unit_type
|
||||
if tanker_type.patrol_altitude is not None:
|
||||
altitude = tanker_type.patrol_altitude
|
||||
else:
|
||||
altitude = feet(21000)
|
||||
altitude = builder.get_patrol_altitude
|
||||
|
||||
racetrack = builder.race_track(racetrack_start, racetrack_end, altitude)
|
||||
|
||||
@@ -79,6 +75,7 @@ class Builder(IBuilder[TheaterRefuelingFlightPlan, PatrollingLayout]):
|
||||
arrival=builder.land(self.flight.arrival),
|
||||
divert=builder.divert(self.flight.divert),
|
||||
bullseye=builder.bullseye(),
|
||||
custom_waypoints=list(),
|
||||
)
|
||||
|
||||
def build(self, dump_debug_info: bool = False) -> TheaterRefuelingFlightPlan:
|
||||
|
||||
@@ -26,6 +26,8 @@ from game.theater import (
|
||||
)
|
||||
from game.utils import Distance, meters, nautical_miles, feet
|
||||
|
||||
AGL_TRANSITION_ALT = 5000
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.transfers import MultiGroupTransport
|
||||
from game.theater.theatergroup import TheaterGroup
|
||||
@@ -51,11 +53,34 @@ class WaypointBuilder:
|
||||
self.navmesh = coalition.nav_mesh
|
||||
self.targets = targets
|
||||
self._bullseye = coalition.bullseye
|
||||
self.settings = self.flight.coalition.game.settings
|
||||
|
||||
@property
|
||||
def is_helo(self) -> bool:
|
||||
return self.flight.is_helo
|
||||
|
||||
@property
|
||||
def get_patrol_altitude(self) -> Distance:
|
||||
return self.get_altitude(self.flight.unit_type.preferred_patrol_altitude)
|
||||
|
||||
@property
|
||||
def get_cruise_altitude(self) -> Distance:
|
||||
return self.get_altitude(self.flight.unit_type.preferred_cruise_altitude)
|
||||
|
||||
@property
|
||||
def get_combat_altitude(self) -> Distance:
|
||||
return self.get_altitude(self.flight.unit_type.preferred_combat_altitude)
|
||||
|
||||
def get_altitude(self, alt: Distance) -> Distance:
|
||||
randomized_alt = feet(round(alt.feet + self.flight.plane_altitude_offset))
|
||||
altitude = max(
|
||||
self.doctrine.min_combat_altitude,
|
||||
min(self.doctrine.max_combat_altitude, randomized_alt),
|
||||
)
|
||||
return (
|
||||
feet(self.settings.heli_combat_alt_agl) if self.flight.is_helo else altitude
|
||||
)
|
||||
|
||||
def takeoff(self, departure: ControlPoint) -> FlightWaypoint:
|
||||
"""Create takeoff waypoint for the given arrival airfield or carrier.
|
||||
|
||||
@@ -72,9 +97,7 @@ class WaypointBuilder:
|
||||
"NAV",
|
||||
FlightWaypointType.NAV,
|
||||
position,
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.rendezvous_altitude,
|
||||
self.get_cruise_altitude,
|
||||
description="Enter theater",
|
||||
pretty_name="Enter theater",
|
||||
)
|
||||
@@ -101,9 +124,7 @@ class WaypointBuilder:
|
||||
"NAV",
|
||||
FlightWaypointType.NAV,
|
||||
position,
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.rendezvous_altitude,
|
||||
self.get_cruise_altitude,
|
||||
description="Exit theater",
|
||||
pretty_name="Exit theater",
|
||||
)
|
||||
@@ -129,14 +150,10 @@ class WaypointBuilder:
|
||||
return None
|
||||
|
||||
position = divert.position
|
||||
altitude_type: AltitudeReference
|
||||
altitude_type: AltitudeReference = "BARO"
|
||||
if isinstance(divert, OffMapSpawn):
|
||||
altitude = (
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.rendezvous_altitude
|
||||
)
|
||||
altitude_type = "BARO"
|
||||
altitude = self.get_cruise_altitude
|
||||
altitude_type = "RADIO" if self.is_helo else altitude_type
|
||||
else:
|
||||
altitude = meters(0)
|
||||
altitude_type = "RADIO"
|
||||
@@ -166,16 +183,15 @@ class WaypointBuilder:
|
||||
|
||||
def hold(self, position: Point) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo:
|
||||
if self.is_helo or self.get_combat_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"HOLD",
|
||||
FlightWaypointType.LOITER,
|
||||
position,
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
# TODO: dedicated altitude setting for holding
|
||||
self.get_cruise_altitude if self.is_helo else self.get_combat_altitude,
|
||||
alt_type,
|
||||
description="Wait until push time",
|
||||
pretty_name="Hold",
|
||||
@@ -183,16 +199,14 @@ class WaypointBuilder:
|
||||
|
||||
def join(self, position: Point) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo:
|
||||
if self.is_helo or self.get_cruise_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"JOIN",
|
||||
FlightWaypointType.JOIN,
|
||||
position,
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
self.get_cruise_altitude,
|
||||
alt_type,
|
||||
description="Rendezvous with package",
|
||||
pretty_name="Join",
|
||||
@@ -200,16 +214,14 @@ class WaypointBuilder:
|
||||
|
||||
def refuel(self, position: Point) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo:
|
||||
if self.is_helo or self.get_cruise_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"REFUEL",
|
||||
FlightWaypointType.REFUEL,
|
||||
position,
|
||||
feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
self.get_cruise_altitude,
|
||||
alt_type,
|
||||
description="Refuel from tanker",
|
||||
pretty_name="Refuel",
|
||||
@@ -217,16 +229,14 @@ class WaypointBuilder:
|
||||
|
||||
def split(self, position: Point) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo:
|
||||
if self.is_helo or self.get_combat_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"SPLIT",
|
||||
FlightWaypointType.SPLIT,
|
||||
position,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
self.get_combat_altitude,
|
||||
alt_type,
|
||||
description="Depart from package",
|
||||
pretty_name="Split",
|
||||
@@ -238,7 +248,7 @@ class WaypointBuilder:
|
||||
position: Point,
|
||||
objective: MissionTarget,
|
||||
) -> FlightWaypoint:
|
||||
alt = self.doctrine.ingress_altitude
|
||||
alt = self.get_combat_altitude
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo or self.flight.is_hercules:
|
||||
alt_type = "RADIO"
|
||||
@@ -247,6 +257,8 @@ class WaypointBuilder:
|
||||
if self.is_helo
|
||||
else feet(1000)
|
||||
)
|
||||
elif alt.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
heading = objective.position.heading_between_point(position)
|
||||
|
||||
@@ -265,16 +277,14 @@ class WaypointBuilder:
|
||||
|
||||
def egress(self, position: Point, target: MissionTarget) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo:
|
||||
if self.is_helo or self.get_combat_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
"EGRESS",
|
||||
FlightWaypointType.EGRESS,
|
||||
position,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
self.get_combat_altitude,
|
||||
alt_type,
|
||||
description=f"EGRESS from {target.name}",
|
||||
pretty_name=f"EGRESS from {target.name}",
|
||||
@@ -312,11 +322,15 @@ class WaypointBuilder:
|
||||
return self._target_area(f"STRIKE {target.name}", target)
|
||||
|
||||
def sead_area(self, target: MissionTarget) -> FlightWaypoint:
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.get_combat_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return self._target_area(
|
||||
f"SEAD on {target.name}",
|
||||
target,
|
||||
altitude=self.doctrine.ingress_altitude,
|
||||
alt_type="BARO",
|
||||
altitude=self.get_combat_altitude,
|
||||
alt_type=alt_type,
|
||||
)
|
||||
|
||||
def dead_area(self, target: MissionTarget) -> FlightWaypoint:
|
||||
@@ -387,11 +401,13 @@ class WaypointBuilder:
|
||||
position: Position of the waypoint.
|
||||
altitude: Altitude of the racetrack.
|
||||
"""
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"RACETRACK START",
|
||||
FlightWaypointType.PATROL_TRACK,
|
||||
position,
|
||||
altitude,
|
||||
"RADIO" if altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="Orbit between this point and the next point",
|
||||
pretty_name="Race-track start",
|
||||
)
|
||||
@@ -404,11 +420,13 @@ class WaypointBuilder:
|
||||
position: Position of the waypoint.
|
||||
altitude: Altitude of the racetrack.
|
||||
"""
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"RACETRACK END",
|
||||
FlightWaypointType.PATROL,
|
||||
position,
|
||||
altitude,
|
||||
"RADIO" if altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="Orbit between this point and the previous point",
|
||||
pretty_name="Race-track end",
|
||||
)
|
||||
@@ -436,42 +454,39 @@ class WaypointBuilder:
|
||||
start: Position of the waypoint.
|
||||
altitude: Altitude of the racetrack.
|
||||
"""
|
||||
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"ORBIT",
|
||||
FlightWaypointType.LOITER,
|
||||
start,
|
||||
altitude,
|
||||
"RADIO" if altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="Anchor and hold at this point",
|
||||
pretty_name="Orbit",
|
||||
)
|
||||
|
||||
def sead_search(self, target: MissionTarget) -> FlightWaypoint:
|
||||
hold = self._sead_search_point(target)
|
||||
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"SEAD Search",
|
||||
FlightWaypointType.NAV,
|
||||
hold,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
alt_type="BARO",
|
||||
self.get_combat_altitude,
|
||||
"RADIO" if self.get_combat_altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="Anchor and search from this point",
|
||||
pretty_name="SEAD Search",
|
||||
)
|
||||
|
||||
def sead_sweep(self, target: MissionTarget) -> FlightWaypoint:
|
||||
hold = self._sead_search_point(target)
|
||||
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"SEAD Sweep",
|
||||
FlightWaypointType.NAV,
|
||||
hold,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
alt_type="BARO",
|
||||
self.get_combat_altitude,
|
||||
"RADIO" if self.get_combat_altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="Anchor and search from this point",
|
||||
pretty_name="SEAD Sweep",
|
||||
)
|
||||
@@ -499,15 +514,16 @@ class WaypointBuilder:
|
||||
)
|
||||
return hold
|
||||
|
||||
def escort_hold(self, start: Point, altitude: Distance) -> FlightWaypoint:
|
||||
def escort_hold(self, start: Point) -> FlightWaypoint:
|
||||
"""Creates custom waypoint for escort flights that need to hold.
|
||||
|
||||
Args:
|
||||
start: Position of the waypoint.
|
||||
altitude: Altitude of the holding pattern.
|
||||
"""
|
||||
altitude = self.get_combat_altitude
|
||||
|
||||
alt_type: Literal["BARO", "RADIO"] = "BARO"
|
||||
if self.is_helo:
|
||||
if self.is_helo or altitude.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
@@ -528,11 +544,13 @@ class WaypointBuilder:
|
||||
position: Position of the waypoint.
|
||||
altitude: Altitude of the sweep in meters.
|
||||
"""
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"SWEEP START",
|
||||
FlightWaypointType.INGRESS_SWEEP,
|
||||
position,
|
||||
altitude,
|
||||
"RADIO" if altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="Proceed to the target and engage enemy aircraft",
|
||||
pretty_name="Sweep start",
|
||||
)
|
||||
@@ -545,11 +563,13 @@ class WaypointBuilder:
|
||||
position: Position of the waypoint.
|
||||
altitude: Altitude of the sweep in meters.
|
||||
"""
|
||||
baro: AltitudeReference = "BARO"
|
||||
return FlightWaypoint(
|
||||
"SWEEP END",
|
||||
FlightWaypointType.EGRESS,
|
||||
position,
|
||||
altitude,
|
||||
"RADIO" if altitude.feet <= AGL_TRANSITION_ALT else baro,
|
||||
description="End of sweep",
|
||||
pretty_name="Sweep end",
|
||||
)
|
||||
@@ -578,7 +598,7 @@ class WaypointBuilder:
|
||||
target: The mission target.
|
||||
"""
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if self.is_helo:
|
||||
if self.is_helo or self.get_combat_altitude.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
# This would preferably be no points at all, and instead the Escort task
|
||||
@@ -592,9 +612,7 @@ class WaypointBuilder:
|
||||
"TARGET",
|
||||
FlightWaypointType.TARGET_GROUP_LOC,
|
||||
target.position,
|
||||
feet(self.flight.coalition.game.settings.heli_combat_alt_agl)
|
||||
if self.is_helo
|
||||
else self.doctrine.ingress_altitude,
|
||||
self.get_combat_altitude,
|
||||
alt_type,
|
||||
description="Escort the package",
|
||||
pretty_name="Target area",
|
||||
@@ -616,17 +634,19 @@ class WaypointBuilder:
|
||||
pretty_name="Pick-up zone",
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def dropoff_zone(drop_off: MissionTarget) -> FlightWaypoint:
|
||||
def dropoff_zone(self, drop_off: MissionTarget) -> FlightWaypoint:
|
||||
"""Creates a dropoff landing zone waypoint
|
||||
This waypoint is used to generate the Trigger Zone used for AirAssault and
|
||||
AirLift using the CTLD plugin (see LogisticsGenerator)
|
||||
"""
|
||||
heli_alt = feet(self.flight.coalition.game.settings.heli_cruise_alt_agl)
|
||||
altitude = heli_alt if self.flight.is_helo else meters(0)
|
||||
|
||||
return FlightWaypoint(
|
||||
"DROPOFFZONE",
|
||||
FlightWaypointType.DROPOFF_ZONE,
|
||||
drop_off.position,
|
||||
meters(0),
|
||||
altitude,
|
||||
"RADIO",
|
||||
description=f"Drop off cargo at {drop_off.name}",
|
||||
pretty_name="Drop-off zone",
|
||||
@@ -660,7 +680,7 @@ class WaypointBuilder:
|
||||
altitude_is_agl: True for altitude is AGL. False if altitude is MSL.
|
||||
"""
|
||||
alt_type: AltitudeReference = "BARO"
|
||||
if altitude_is_agl:
|
||||
if altitude_is_agl or altitude.feet <= AGL_TRANSITION_ALT:
|
||||
alt_type = "RADIO"
|
||||
|
||||
return FlightWaypoint(
|
||||
|
||||
@@ -137,11 +137,15 @@ class Loadout:
|
||||
continue
|
||||
name = payload["name"]
|
||||
pylons = payload["pylons"]
|
||||
yield Loadout(
|
||||
name,
|
||||
{p["num"]: Weapon.with_clsid(p["CLSID"]) for p in pylons.values()},
|
||||
date=None,
|
||||
)
|
||||
try:
|
||||
yield Loadout(
|
||||
name,
|
||||
{p["num"]: Weapon.with_clsid(p["CLSID"]) for p in pylons.values()},
|
||||
date=None,
|
||||
)
|
||||
except KeyError:
|
||||
# invalid loadout
|
||||
continue
|
||||
|
||||
@staticmethod
|
||||
def valid_payload(pylons: Dict[int, Dict[str, str]]) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user