Allow user to add navigation waypoints where possible

This commit is contained in:
Raffson
2023-08-27 20:54:12 +02:00
parent 819bd92d9a
commit 66d741d0b3
13 changed files with 153 additions and 67 deletions

View File

@@ -3,7 +3,7 @@ from __future__ import annotations
from collections.abc import Iterator
from dataclasses import dataclass
from datetime import timedelta
from typing import TYPE_CHECKING, Type
from typing import TYPE_CHECKING, Type, Optional
from game.theater.missiontarget import MissionTarget
from game.utils import feet
@@ -12,6 +12,7 @@ from .ibuilder import IBuilder
from .planningerror import PlanningError
from .standard import StandardFlightPlan, StandardLayout
from .waypointbuilder import WaypointBuilder
from ..flightwaypointtype import FlightWaypointType
from ...theater.interfaces.CTLD import CTLD
if TYPE_CHECKING:
@@ -21,7 +22,6 @@ if TYPE_CHECKING:
@dataclass
class AirliftLayout(StandardLayout):
nav_to_pickup: list[FlightWaypoint]
# 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
# up the cargo near the airfield.
@@ -36,25 +36,30 @@ class AirliftLayout(StandardLayout):
drop_off: FlightWaypoint | None
# drop_off_zone will be used for player flights to create the CTLD stuff
ctld_drop_off_zone: FlightWaypoint | None
nav_to_home: list[FlightWaypoint]
def add_waypoint(
self, wpt: FlightWaypoint, next_wpt: Optional[FlightWaypoint]
) -> bool:
new_wpt = self.get_midpoint(wpt, next_wpt)
if wpt.waypoint_type in [
FlightWaypointType.PICKUP_ZONE,
FlightWaypointType.CARGO_STOP,
]:
self.nav_to_drop_off.insert(0, new_wpt)
return True
return super().add_waypoint(wpt, next_wpt)
def delete_waypoint(self, waypoint: FlightWaypoint) -> bool:
if super().delete_waypoint(waypoint):
return True
if waypoint in self.nav_to_pickup:
self.nav_to_pickup.remove(waypoint)
return True
elif waypoint in self.nav_to_drop_off:
if waypoint in self.nav_to_drop_off:
self.nav_to_drop_off.remove(waypoint)
return True
elif waypoint in self.nav_to_home:
self.nav_to_home.remove(waypoint)
elif super().delete_waypoint(waypoint):
return True
return False
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.departure
yield from self.nav_to_pickup
yield from self.nav_to
if self.pickup is not None:
yield self.pickup
if self.ctld_pickup_zone is not None:
@@ -64,7 +69,7 @@ class AirliftLayout(StandardLayout):
yield self.drop_off
if self.ctld_drop_off_zone is not None:
yield self.ctld_drop_off_zone
yield from self.nav_to_home
yield from self.nav_from
yield self.arrival
if self.divert is not None:
yield self.divert
@@ -141,7 +146,7 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
return AirliftLayout(
departure=builder.takeoff(self.flight.departure),
nav_to_pickup=nav_to_pickup,
nav_to=nav_to_pickup,
pickup=pickup,
ctld_pickup_zone=pickup_zone,
nav_to_drop_off=builder.nav_path(
@@ -152,7 +157,7 @@ class Builder(IBuilder[AirliftFlightPlan, AirliftLayout]):
),
drop_off=drop_off,
ctld_drop_off_zone=drop_off_zone,
nav_to_home=builder.nav_path(
nav_from=builder.nav_path(
cargo.origin.position,
self.flight.arrival.position,
altitude,

View File

@@ -29,6 +29,10 @@ class CustomFlightPlan(FlightPlan[CustomLayout]):
def builder_type() -> Type[Builder]:
return Builder
@property
def is_custom(self) -> bool:
return True
@property
def tot_waypoint(self) -> FlightWaypoint:
target_types = (

View File

@@ -17,19 +17,9 @@ if TYPE_CHECKING:
@dataclass
class FerryLayout(StandardLayout):
nav_to_destination: list[FlightWaypoint]
def delete_waypoint(self, waypoint: FlightWaypoint) -> bool:
if super().delete_waypoint(waypoint):
return True
if waypoint in self.nav_to_destination:
self.nav_to_destination.remove(waypoint)
return True
return False
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.departure
yield from self.nav_to_destination
yield from self.nav_to
yield self.arrival
if self.divert is not None:
yield self.divert
@@ -76,7 +66,7 @@ class Builder(IBuilder[FerryFlightPlan, FerryLayout]):
builder = WaypointBuilder(self.flight, self.coalition)
return FerryLayout(
departure=builder.takeoff(self.flight.departure),
nav_to_destination=builder.nav_path(
nav_to=builder.nav_path(
self.flight.departure.position,
self.flight.arrival.position,
altitude,
@@ -85,6 +75,7 @@ class Builder(IBuilder[FerryFlightPlan, FerryLayout]):
arrival=builder.land(self.flight.arrival),
divert=builder.divert(self.flight.divert),
bullseye=builder.bullseye(),
nav_from=[],
)
def build(self) -> FerryFlightPlan:

View File

@@ -317,6 +317,10 @@ class FlightPlan(ABC, Generic[LayoutT]):
def is_airassault(self) -> bool:
return False
@property
def is_custom(self) -> bool:
return False
@property
def mission_departure_time(self) -> timedelta:
"""The time that the mission is complete and the flight RTBs."""

View File

@@ -18,24 +18,16 @@ if TYPE_CHECKING:
@dataclass
class FormationLayout(LoiterLayout, ABC):
nav_to: list[FlightWaypoint]
join: Optional[FlightWaypoint]
split: FlightWaypoint
refuel: Optional[FlightWaypoint]
nav_from: list[FlightWaypoint]
def delete_waypoint(self, waypoint: FlightWaypoint) -> bool:
if super().delete_waypoint(waypoint):
return True
if waypoint in self.nav_to:
self.nav_to.remove(waypoint)
return True
elif waypoint in self.nav_from:
self.nav_from.remove(waypoint)
return True
elif waypoint == self.refuel:
if waypoint == self.refuel:
self.refuel = None
return True
elif super().delete_waypoint(waypoint):
return True
return False

View File

@@ -18,21 +18,8 @@ if TYPE_CHECKING:
@dataclass
class PatrollingLayout(StandardLayout):
nav_to: list[FlightWaypoint]
patrol_start: FlightWaypoint
patrol_end: FlightWaypoint
nav_from: list[FlightWaypoint]
def delete_waypoint(self, waypoint: FlightWaypoint) -> bool:
if super().delete_waypoint(waypoint):
return True
if waypoint in self.nav_to:
self.nav_to.remove(waypoint)
return True
elif waypoint in self.nav_from:
self.nav_from.remove(waypoint)
return True
return False
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.departure

View File

@@ -18,12 +18,11 @@ if TYPE_CHECKING:
@dataclass
class RtbLayout(StandardLayout):
abort_location: FlightWaypoint
nav_to_destination: list[FlightWaypoint]
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
yield self.departure
yield self.abort_location
yield from self.nav_to_destination
yield from self.nav_to
yield self.arrival
if self.divert is not None:
yield self.divert
@@ -78,7 +77,7 @@ class Builder(IBuilder[RtbFlightPlan, RtbLayout]):
return RtbLayout(
departure=builder.takeoff(self.flight.departure),
abort_location=abort_point,
nav_to_destination=builder.nav_path(
nav_to=builder.nav_path(
current_position,
self.flight.arrival.position,
altitude,
@@ -87,6 +86,7 @@ class Builder(IBuilder[RtbFlightPlan, RtbLayout]):
arrival=builder.land(self.flight.arrival),
divert=builder.divert(self.flight.divert),
bullseye=builder.bullseye(),
nav_from=[],
)
def build(self) -> RtbFlightPlan:

View File

@@ -1,10 +1,14 @@
from __future__ import annotations
from abc import ABC
from copy import deepcopy
from dataclasses import dataclass
from typing import TYPE_CHECKING, TypeVar
from typing import TYPE_CHECKING, TypeVar, Optional
from game.ato.flightplans.flightplan import FlightPlan, Layout
from .waypointbuilder import WaypointBuilder
from ..flightwaypointtype import FlightWaypointType
from ...utils import feet
if TYPE_CHECKING:
from ..flightwaypoint import FlightWaypoint
@@ -15,11 +19,57 @@ class StandardLayout(Layout, ABC):
arrival: FlightWaypoint
divert: FlightWaypoint | None
bullseye: FlightWaypoint
nav_to: list[FlightWaypoint]
nav_from: list[FlightWaypoint]
def add_waypoint(
self, wpt: FlightWaypoint, next_wpt: Optional[FlightWaypoint]
) -> bool:
new_wpt = self.get_midpoint(wpt, next_wpt)
if wpt.waypoint_type in [FlightWaypointType.TAKEOFF, FlightWaypointType.LOITER]:
self.nav_to.insert(0, new_wpt)
return True
elif wpt.waypoint_type in [
FlightWaypointType.SPLIT,
FlightWaypointType.REFUEL,
FlightWaypointType.PATROL,
FlightWaypointType.EGRESS,
]:
self.nav_from.insert(0, new_wpt)
return True
elif wpt.waypoint_type is FlightWaypointType.NAV:
if wpt in self.nav_to:
index = self.nav_to.index(wpt) + 1
self.nav_to.insert(index, new_wpt)
return True
elif wpt in self.nav_from:
index = self.nav_from.index(wpt) + 1
self.nav_from.insert(index, new_wpt)
return True
return False
@staticmethod
def get_midpoint(
wpt: FlightWaypoint, next_wpt: Optional[FlightWaypoint]
) -> FlightWaypoint:
new_pos = deepcopy(wpt.position)
next_alt = feet(20000)
if next_wpt:
new_pos = wpt.position.lerp(next_wpt.position, 0.5)
next_alt = next_wpt.alt
new_wpt = WaypointBuilder.nav(new_pos, max(wpt.alt, next_alt))
return new_wpt
def delete_waypoint(self, waypoint: FlightWaypoint) -> bool:
if waypoint is self.divert:
self.divert = None
return True
elif waypoint in self.nav_to:
self.nav_to.remove(waypoint)
return True
elif waypoint in self.nav_from:
self.nav_from.remove(waypoint)
return True
return False

View File

@@ -32,6 +32,14 @@ class TarCapLayout(PatrollingLayout):
yield self.divert
yield self.bullseye
def delete_waypoint(self, waypoint: FlightWaypoint) -> bool:
if waypoint == self.refuel:
self.refuel = None
return True
elif super().delete_waypoint(waypoint):
return True
return False
class TarCapFlightPlan(PatrollingFlightPlan[TarCapLayout]):
@property