Fix ground-seeking AirLift

This commit is contained in:
Raffson 2024-02-18 00:17:05 +01:00
parent d901df4fa0
commit 781d611f17
No known key found for this signature in database
GPG Key ID: B0402B2C9B764D99
3 changed files with 94 additions and 8 deletions

View File

@ -51,6 +51,7 @@
* **[Capture Logic]** Release all parking slots when an airbase is captured * **[Capture Logic]** Release all parking slots when an airbase is captured
* **[Modding]** Swedish Military Assets Pack air defence presets are now correctly removed from the faction when the mod is disabled. * **[Modding]** Swedish Military Assets Pack air defence presets are now correctly removed from the faction when the mod is disabled.
* **[Mission Generation]** Naval aircraft not always returning to carrier * **[Mission Generation]** Naval aircraft not always returning to carrier
* **[Mission Generation]** AI AirLift aircraft crashing into terrain due to insufficient waypoints
# Retribution v1.2.1 (hotfix) # Retribution v1.2.1 (hotfix)

View File

@ -1,5 +1,6 @@
from __future__ import annotations from __future__ import annotations
import random
from collections.abc import Iterator from collections.abc import Iterator
from dataclasses import dataclass from dataclasses import dataclass
from datetime import datetime from datetime import datetime
@ -7,7 +8,7 @@ from typing import Optional
from typing import TYPE_CHECKING, Type from typing import TYPE_CHECKING, Type
from game.theater.missiontarget import MissionTarget from game.theater.missiontarget import MissionTarget
from game.utils import feet from game.utils import feet, Distance
from ._common_ctld import generate_random_ctld_point from ._common_ctld import generate_random_ctld_point
from .ibuilder import IBuilder from .ibuilder import IBuilder
from .planningerror import PlanningError from .planningerror import PlanningError
@ -23,13 +24,17 @@ if TYPE_CHECKING:
@dataclass @dataclass
class AirliftLayout(StandardLayout): class AirliftLayout(StandardLayout):
pickup_ascent: FlightWaypoint | None
pickup_descent: FlightWaypoint | None
# There will not be a pickup waypoint when the pickup airfield is the departure # There will not be a pickup waypoint when the pickup airfield is the departure
# airfield for cargo planes, as the cargo is pre-loaded. Helicopters will still pick # airfield for cargo planes, as the cargo is pre-loaded. Helicopters will still pick
# up the cargo near the airfield. # up the cargo near the airfield.
pickup: FlightWaypoint | None pickup: FlightWaypoint | None
# pickup_zone will be used for player flights to create the CTLD stuff # pickup_zone will be used for player flights to create the CTLD stuff
ctld_pickup_zone: FlightWaypoint | None ctld_pickup_zone: FlightWaypoint | None
drop_off_ascent: FlightWaypoint | None
nav_to_drop_off: list[FlightWaypoint] nav_to_drop_off: list[FlightWaypoint]
drop_off_descent: FlightWaypoint | None
# There will not be a drop-off waypoint when the drop-off airfield and the arrival # There will not be a drop-off waypoint when the drop-off airfield and the arrival
# airfield is the same for a cargo plane, as planes will land to unload and we don't # airfield is the same for a cargo plane, as planes will land to unload and we don't
# want a double landing. Helicopters will still drop their cargo near the airfield # want a double landing. Helicopters will still drop their cargo near the airfield
@ -37,6 +42,8 @@ class AirliftLayout(StandardLayout):
drop_off: FlightWaypoint | None drop_off: FlightWaypoint | None
# drop_off_zone will be used for player flights to create the CTLD stuff # drop_off_zone will be used for player flights to create the CTLD stuff
ctld_drop_off_zone: FlightWaypoint | None ctld_drop_off_zone: FlightWaypoint | None
return_ascent: FlightWaypoint | None
return_descent: FlightWaypoint | None
def add_waypoint( def add_waypoint(
self, wpt: FlightWaypoint, next_wpt: Optional[FlightWaypoint] self, wpt: FlightWaypoint, next_wpt: Optional[FlightWaypoint]
@ -60,17 +67,29 @@ class AirliftLayout(StandardLayout):
def iter_waypoints(self) -> Iterator[FlightWaypoint]: def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.departure yield self.departure
if self.pickup_ascent is not None:
yield self.pickup_ascent
yield from self.nav_to yield from self.nav_to
if self.pickup_descent is not None:
yield self.pickup_descent
if self.pickup is not None: if self.pickup is not None:
yield self.pickup yield self.pickup
if self.ctld_pickup_zone is not None: if self.ctld_pickup_zone is not None:
yield self.ctld_pickup_zone yield self.ctld_pickup_zone
if self.drop_off_ascent is not None:
yield self.drop_off_ascent
yield from self.nav_to_drop_off yield from self.nav_to_drop_off
if self.drop_off_descent is not None:
yield self.drop_off_descent
if self.drop_off is not None: if self.drop_off is not None:
yield self.drop_off yield self.drop_off
if self.return_ascent is not None:
yield self.return_ascent
if self.ctld_drop_off_zone is not None: if self.ctld_drop_off_zone is not None:
yield self.ctld_drop_off_zone yield self.ctld_drop_off_zone
yield from self.nav_from yield from self.nav_from
if self.return_descent is not None:
yield self.return_descent
yield self.arrival yield self.arrival
if self.divert is not None: if self.divert is not None:
yield self.divert yield self.divert
@ -121,15 +140,47 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
builder = WaypointBuilder(self.flight) builder = WaypointBuilder(self.flight)
pickup_ascent = None
pickup_descent = None
pickup = None pickup = None
drop_off_ascent = None
drop_off_descent = None
drop_off = None drop_off = None
pickup_zone = None pickup_zone = None
drop_off_zone = None drop_off_zone = None
if cargo.origin != self.flight.departure: if cargo.origin != self.flight.departure:
pickup = builder.cargo_stop(cargo.origin) pickup = builder.cargo_stop(cargo.origin)
pickup_ascent = self._create_ascent_or_descent(
builder,
self.flight.departure.position,
cargo.origin.position,
altitude,
altitude_is_agl,
)
pickup_descent = self._create_ascent_or_descent(
builder,
cargo.origin.position,
self.flight.departure.position,
altitude,
altitude_is_agl,
)
if cargo.next_stop != self.flight.arrival: if cargo.next_stop != self.flight.arrival:
drop_off = builder.cargo_stop(cargo.next_stop) drop_off = builder.cargo_stop(cargo.next_stop)
drop_off_ascent = self._create_ascent_or_descent(
builder,
cargo.origin.position,
cargo.next_stop.position,
altitude,
altitude_is_agl,
)
drop_off_descent = self._create_ascent_or_descent(
builder,
cargo.next_stop.position,
cargo.origin.position,
altitude,
altitude_is_agl,
)
if self.flight.is_helo: if self.flight.is_helo:
# Create CTLD Zones for Helo flights # Create CTLD Zones for Helo flights
@ -150,25 +201,50 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
altitude_is_agl, altitude_is_agl,
) )
return_ascent = self._create_ascent_or_descent(
builder,
cargo.next_stop.position
if cargo.next_stop != self.flight.arrival
else cargo.origin.position,
self.flight.arrival.position,
altitude,
altitude_is_agl,
)
return_descent = self._create_ascent_or_descent(
builder,
self.flight.arrival.position,
cargo.next_stop.position
if cargo.next_stop != self.flight.arrival
else cargo.origin.position,
altitude,
altitude_is_agl,
)
return AirliftLayout( return AirliftLayout(
departure=builder.takeoff(self.flight.departure), departure=builder.takeoff(self.flight.departure),
pickup_ascent=pickup_ascent,
nav_to=nav_to_pickup, nav_to=nav_to_pickup,
pickup_descent=pickup_descent,
pickup=pickup, pickup=pickup,
ctld_pickup_zone=pickup_zone, ctld_pickup_zone=pickup_zone,
drop_off_ascent=drop_off_ascent,
nav_to_drop_off=builder.nav_path( nav_to_drop_off=builder.nav_path(
cargo.origin.position, cargo.origin.position,
cargo.next_stop.position, cargo.next_stop.position,
altitude, altitude,
altitude_is_agl, altitude_is_agl,
), ),
drop_off_descent=drop_off_descent,
drop_off=drop_off, drop_off=drop_off,
ctld_drop_off_zone=drop_off_zone, ctld_drop_off_zone=drop_off_zone,
return_ascent=return_ascent,
nav_from=builder.nav_path( nav_from=builder.nav_path(
cargo.origin.position, cargo.origin.position,
self.flight.arrival.position, self.flight.arrival.position,
altitude, altitude,
altitude_is_agl, altitude_is_agl,
), ),
return_descent=return_descent,
arrival=builder.land(self.flight.arrival), arrival=builder.land(self.flight.arrival),
divert=builder.divert(self.flight.divert), divert=builder.divert(self.flight.divert),
bullseye=builder.bullseye(), bullseye=builder.bullseye(),
@ -188,3 +264,18 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
if cargo and cargo.transport and isinstance(cargo.transport.destination, CTLD): if cargo and cargo.transport and isinstance(cargo.transport.destination, CTLD):
return generate_random_ctld_point(cargo.transport.destination) return generate_random_ctld_point(cargo.transport.destination)
raise RuntimeError("Could not generate CTLD dropoff") raise RuntimeError("Could not generate CTLD dropoff")
@staticmethod
def _create_ascent_or_descent(
builder: WaypointBuilder,
start: Point,
end: Point,
alt: Distance,
agl: bool,
) -> FlightWaypoint:
distance = start.distance_to_point(end)
rdistance = 1000 if agl else min(distance / 10, 20000)
heading = round(start.heading_between_point(end))
rheading = random.randint(heading - 30, heading + 30) % 360
pos = start.point_from_heading(float(rheading), rdistance)
return builder.nav(pos, alt, agl)

View File

@ -15,7 +15,6 @@ from typing import (
from dcs.mapping import Point, Vector2 from dcs.mapping import Point, Vector2
from game.ato.flightplans._common_ctld import generate_random_ctld_point
from game.ato.flightwaypoint import AltitudeReference, FlightWaypoint from game.ato.flightwaypoint import AltitudeReference, FlightWaypoint
from game.ato.flightwaypointtype import FlightWaypointType from game.ato.flightwaypointtype import FlightWaypointType
from game.theater import ( from game.theater import (
@ -25,7 +24,6 @@ from game.theater import (
TheaterGroundObject, TheaterGroundObject,
TheaterUnit, TheaterUnit,
) )
from game.theater.interfaces.CTLD import CTLD
from game.utils import Distance, meters, nautical_miles, feet from game.utils import Distance, meters, nautical_miles, feet
if TYPE_CHECKING: if TYPE_CHECKING:
@ -635,14 +633,10 @@ class WaypointBuilder:
"""Creates a cargo stop waypoint. """Creates a cargo stop waypoint.
This waypoint is used by AirLift as a landing and stopover waypoint This waypoint is used by AirLift as a landing and stopover waypoint
""" """
if isinstance(control_point, CTLD) and control_point.ctld_zones:
pos = generate_random_ctld_point(control_point)
else:
pos = control_point.position
return FlightWaypoint( return FlightWaypoint(
"CARGOSTOP", "CARGOSTOP",
FlightWaypointType.CARGO_STOP, FlightWaypointType.CARGO_STOP,
pos, control_point.position,
meters(0), meters(0),
"RADIO", "RADIO",
description=f"Stop for cargo at {control_point.name}", description=f"Stop for cargo at {control_point.name}",