Cleanup and refine airlift and airassault waypoints

- Drop Off and Pickup now correctly worded
- Helo waypoints now represent LandingZones for pickup and dropoff
This commit is contained in:
RndName 2022-11-01 21:01:48 +01:00
parent a47cb865fb
commit b4b9bbf476
7 changed files with 89 additions and 33 deletions

View File

@ -4,8 +4,7 @@ from dataclasses import dataclass
from datetime import timedelta
from typing import Iterator, TYPE_CHECKING, Type
from game.ato.flightplans.airlift import AirliftLayout
from game.ato.flightplans.standard import StandardFlightPlan
from game.ato.flightplans.standard import StandardFlightPlan, StandardLayout
from game.theater.controlpoint import ControlPointType
from game.theater.missiontarget import MissionTarget
from game.utils import Distance, feet, meters
@ -17,13 +16,18 @@ if TYPE_CHECKING:
@dataclass(frozen=True)
class AirAssaultLayout(AirliftLayout):
class AirAssaultLayout(StandardLayout):
nav_to_pickup: list[FlightWaypoint]
pickup: FlightWaypoint | None
nav_to_drop_off: list[FlightWaypoint]
drop_off: FlightWaypoint
target: FlightWaypoint
nav_to_home: list[FlightWaypoint]
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.departure
yield from self.nav_to_pickup
if self.pickup:
if self.pickup is not None:
yield self.pickup
yield from self.nav_to_drop_off
yield self.drop_off
@ -81,19 +85,27 @@ class Builder(IBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
pickup_position = self.flight.departure.position
else:
# Create a special pickup zone for Helos from Airbase / FOB
pickup = builder.pickup(
pickup = builder.cargo_pickup(
MissionTarget(
"Pickup Zone",
self.flight.departure.position.random_point_within(1200, 600),
)
),
self.flight.is_helo,
)
pickup_position = pickup.position
assault_area = builder.assault_area(self.package.target)
heading = self.package.target.position.heading_between_point(pickup_position)
# Once there is a plane which is capable of AirDrop Paratrooper
# we can make use of the AIRDROP Wayppoint type.
# This would also need a special Waypointbuilder.
# Currently AirAssault can only be used by Helos so we just create
# the drop_off Landing Zone
drop_off_zone = MissionTarget(
"Dropoff zone",
self.package.target.position.point_from_heading(heading, 1200),
)
drop_off = builder.cargo_dropoff(drop_off_zone, self.flight.is_helo)
return AirAssaultLayout(
departure=builder.takeoff(self.flight.departure),
@ -110,8 +122,7 @@ class Builder(IBuilder[AirAssaultFlightPlan, AirAssaultLayout]):
altitude,
altitude_is_agl,
),
drop_off=builder.drop_off(drop_off_zone),
refuel=None,
drop_off=drop_off,
target=assault_area,
nav_to_home=builder.nav_path(
drop_off_zone.position,

View File

@ -21,7 +21,7 @@ class AirliftLayout(StandardLayout):
nav_to_pickup: list[FlightWaypoint]
pickup: FlightWaypoint | None
nav_to_drop_off: list[FlightWaypoint]
drop_off: FlightWaypoint
drop_off: FlightWaypoint | None
refuel: FlightWaypoint | None
nav_to_home: list[FlightWaypoint]
@ -31,6 +31,7 @@ class AirliftLayout(StandardLayout):
if self.pickup is not None:
yield self.pickup
yield from self.nav_to_drop_off
if self.drop_off is not None:
yield self.drop_off
if self.refuel is not None:
yield self.refuel
@ -48,7 +49,7 @@ class AirliftFlightPlan(StandardFlightPlan[AirliftLayout]):
@property
def tot_waypoint(self) -> FlightWaypoint:
return self.layout.drop_off
return self.layout.drop_off or self.layout.arrival
def tot_for_waypoint(self, waypoint: FlightWaypoint) -> timedelta | None:
# TOT planning isn't really useful for transports. They're behind the front
@ -78,12 +79,13 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
pickup = None
refuel = None
drop_off = None
if self.flight.is_helo:
# Create a pickupzone where the cargo will be spawned
pickup_zone = MissionTarget(
"Pickup Zone", cargo.origin.position.random_point_within(1000, 200)
)
pickup = builder.pickup(pickup_zone)
pickup = builder.cargo_pickup(pickup_zone, True)
# If The cargo is at the departure controlpoint, the pickup waypoint should
# only be created for client flights
pickup.only_for_player = cargo.origin == self.flight.departure
@ -93,15 +95,16 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
"Dropoff zone",
cargo.next_stop.position.random_point_within(1000, 200),
)
drop_off = builder.drop_off(drop_off_zone)
drop_off = builder.cargo_dropoff(drop_off_zone, True)
# Add an additional stopover point so that the flight can refuel
# Add an additional refuel waypoint
refuel = builder.land_refuel(cargo.next_stop)
else:
# Fixed Wing will get stopover points for pickup and dropoff
# Fixed Wing will get landing&refuel waypoints for pickup and dropoff
if cargo.origin != self.flight.departure:
pickup = builder.land_refuel(cargo.origin)
drop_off = builder.land_refuel(cargo.next_stop)
pickup = builder.cargo_pickup(cargo.origin, False)
if cargo.next_stop != self.flight.arrival:
drop_off = builder.cargo_dropoff(cargo.next_stop, False)
nav_to_pickup = builder.nav_path(
self.flight.departure.position,
@ -114,7 +117,7 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
# Normal Landing Waypoint
arrival = builder.land(self.flight.arrival)
else:
# The AI Needs another Stopover point to actually fly back to the original
# The AI Needs another landing&refuel point to actually fly back to the original
# base. Otherwise the Cargo drop will be the new Landing Waypoint and the
# AI will end its mission there instead of flying back.
# https://forum.dcs.world/topic/211775-landing-to-refuel-and-rearm-the-landingrefuar-waypoint/

View File

@ -526,40 +526,65 @@ class WaypointBuilder:
)
@staticmethod
def pickup(pick_up: MissionTarget) -> FlightWaypoint:
def cargo_pickup(pick_up: MissionTarget, is_helo: bool) -> FlightWaypoint:
"""Creates a cargo pickup waypoint.
Args:
control_point: Pick up location.
"""
control_point = pick_up if isinstance(pick_up, ControlPoint) else None
if is_helo:
return FlightWaypoint(
"PICKUP",
FlightWaypointType.PICKUP,
FlightWaypointType.PICKUP_ZONE,
pick_up.position,
meters(0),
"RADIO",
description=f"Pick up cargo from {pick_up.name}",
pretty_name="Pick up location",
pretty_name="Pick-up zone",
control_point=control_point,
)
return FlightWaypoint(
"PICKUP",
FlightWaypointType.LAND_REFUEL,
pick_up.position,
meters(0),
"RADIO",
description=f"Pick up cargo from {pick_up.name}",
pretty_name="Cargo pick-up",
control_point=control_point,
)
@staticmethod
def drop_off(drop_off: MissionTarget) -> FlightWaypoint:
def cargo_dropoff(drop_off: MissionTarget, is_helo: bool) -> FlightWaypoint:
"""Creates a cargo drop-off waypoint.
This waypoint is used by AirLift and AirAssault to drop cargo or troops
at the given location
Args:
control_point: Drop-off location.
is_helo: Differentiate behaviour between plane and helo
"""
control_point = drop_off if isinstance(drop_off, ControlPoint) else None
if is_helo:
return FlightWaypoint(
"DROP OFF",
FlightWaypointType.DROP_OFF,
"DROPOFF",
FlightWaypointType.DROPOFF_ZONE,
drop_off.position,
meters(0),
"RADIO",
description=f"Drop off cargo at {drop_off.name}",
pretty_name="Drop off location",
pretty_name="Drop-off zone",
control_point=control_point,
)
return FlightWaypoint(
"DROPOFF",
FlightWaypointType.LAND_REFUEL,
drop_off.position,
meters(0),
"RADIO",
description=f"Drop off cargo at {drop_off.name}",
pretty_name="Cargo drop-off",
control_point=control_point,
)

View File

@ -43,8 +43,8 @@ class FlightWaypointType(IntEnum):
DIVERT = 23
INGRESS_OCA_RUNWAY = 24
INGRESS_OCA_AIRCRAFT = 25
PICKUP = 26
DROP_OFF = 27
PICKUP_ZONE = 26 # Pickup Zone for cargo or troops
DROPOFF_ZONE = 27 # Dropoff Zone for cargo or troops
BULLSEYE = 28
REFUEL = 29 # Should look for nearby tanker to refuel from.
CARGO_STOP = 30 # Stopover landing point using the LandingReFuAr waypoint type

View File

@ -0,0 +1,17 @@
from dcs.point import MovingPoint
from dcs.task import Land
from .pydcswaypointbuilder import PydcsWaypointBuilder
class LandingZoneBuilder(PydcsWaypointBuilder):
def build(self) -> MovingPoint:
waypoint = super().build()
# Create a landing task, currently only for Helos!
# Calculate a landing point with a small buffer to prevent AI from landing
# directly at the static ammo depot and exploding
landing_point = waypoint.position.random_point_within(15, 5)
# Use Land Task with 30s duration for helos
waypoint.add_task(Land(landing_point, duration=30))
return waypoint

View File

@ -21,7 +21,7 @@ from game.missiongenerator.missiondata import MissionData
from game.settings import Settings
from game.utils import pairwise
from .baiingress import BaiIngressBuilder
from .cargostop import CargoStopBuilder
from .landingzone import LandingZoneBuilder
from .casingress import CasIngressBuilder
from .deadingress import DeadIngressBuilder
from .default import DefaultWaypointBuilder
@ -118,7 +118,6 @@ class WaypointGenerator:
def builder_for_waypoint(self, waypoint: FlightWaypoint) -> PydcsWaypointBuilder:
builders = {
FlightWaypointType.DROP_OFF: CargoStopBuilder,
FlightWaypointType.INGRESS_BAI: BaiIngressBuilder,
FlightWaypointType.INGRESS_CAS: CasIngressBuilder,
FlightWaypointType.INGRESS_DEAD: DeadIngressBuilder,
@ -133,7 +132,8 @@ class WaypointGenerator:
FlightWaypointType.LOITER: HoldPointBuilder,
FlightWaypointType.PATROL: RaceTrackEndBuilder,
FlightWaypointType.PATROL_TRACK: RaceTrackBuilder,
FlightWaypointType.PICKUP: CargoStopBuilder,
FlightWaypointType.PICKUP_ZONE: LandingZoneBuilder,
FlightWaypointType.DROPOFF_ZONE: LandingZoneBuilder,
FlightWaypointType.REFUEL: RefuelPointBuilder,
FlightWaypointType.CARGO_STOP: CargoStopBuilder,
}

View File

@ -56,8 +56,8 @@ class LogisticsGenerator:
if (
waypoint.waypoint_type
not in [
FlightWaypointType.PICKUP,
FlightWaypointType.DROP_OFF,
FlightWaypointType.PICKUP_ZONE,
FlightWaypointType.DROPOFF_ZONE,
]
or waypoint.only_for_player
and not self.flight.client_count
@ -68,7 +68,7 @@ class LogisticsGenerator:
self.mission.triggers.add_triggerzone(
waypoint.position, ZONE_RADIUS, False, zone_name
)
if waypoint.waypoint_type == FlightWaypointType.PICKUP:
if waypoint.waypoint_type == FlightWaypointType.PICKUP_ZONE:
pickup_point = waypoint.position
logistics_info.pickup_zone = zone_name
else: