mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
155 lines
4.9 KiB
Python
155 lines
4.9 KiB
Python
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from datetime import datetime, timedelta
|
|
from typing import Iterator, TYPE_CHECKING, Type
|
|
|
|
from dcs import Point
|
|
from dcs.task import Targets
|
|
|
|
from game.flightplan import HoldZoneGeometry
|
|
from game.flightplan.waypointactions.engagetargets import EngageTargets
|
|
from game.flightplan.waypointoptions.formation import Formation
|
|
from game.utils import Heading, nautical_miles
|
|
from .ibuilder import IBuilder
|
|
from .loiter import LoiterFlightPlan, LoiterLayout
|
|
from .waypointbuilder import WaypointBuilder
|
|
|
|
if TYPE_CHECKING:
|
|
from ..flightwaypoint import FlightWaypoint
|
|
|
|
|
|
@dataclass(frozen=True)
|
|
class SweepLayout(LoiterLayout):
|
|
nav_to: list[FlightWaypoint]
|
|
sweep_start: FlightWaypoint
|
|
sweep_end: FlightWaypoint
|
|
nav_from: list[FlightWaypoint]
|
|
|
|
def iter_waypoints(self) -> Iterator[FlightWaypoint]:
|
|
yield self.departure
|
|
yield self.hold
|
|
yield from self.nav_to
|
|
yield self.sweep_start
|
|
yield self.sweep_end
|
|
yield from self.nav_from
|
|
yield self.arrival
|
|
if self.divert is not None:
|
|
yield self.divert
|
|
yield self.bullseye
|
|
|
|
|
|
class SweepFlightPlan(LoiterFlightPlan[SweepLayout]):
|
|
@staticmethod
|
|
def builder_type() -> Type[Builder]:
|
|
return Builder
|
|
|
|
@property
|
|
def combat_speed_waypoints(self) -> set[FlightWaypoint]:
|
|
return {self.layout.sweep_end}
|
|
|
|
@property
|
|
def tot_waypoint(self) -> FlightWaypoint:
|
|
return self.layout.sweep_end
|
|
|
|
def default_tot_offset(self) -> timedelta:
|
|
return -timedelta(minutes=5)
|
|
|
|
@property
|
|
def sweep_start_time(self) -> datetime:
|
|
travel_time = self.total_time_between_waypoints(
|
|
self.layout.sweep_start, self.layout.sweep_end
|
|
)
|
|
return self.sweep_end_time - travel_time
|
|
|
|
@property
|
|
def sweep_end_time(self) -> datetime:
|
|
return self.tot
|
|
|
|
def tot_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None:
|
|
if waypoint == self.layout.sweep_start:
|
|
return self.sweep_start_time
|
|
if waypoint == self.layout.sweep_end:
|
|
return self.sweep_end_time
|
|
return None
|
|
|
|
def depart_time_for_waypoint(self, waypoint: FlightWaypoint) -> datetime | None:
|
|
if waypoint == self.layout.hold:
|
|
return self.push_time
|
|
return None
|
|
|
|
@property
|
|
def push_time(self) -> datetime:
|
|
return self.sweep_end_time - self.travel_time_between_waypoints(
|
|
self.layout.hold, self.layout.sweep_end
|
|
)
|
|
|
|
@property
|
|
def mission_begin_on_station_time(self) -> datetime | None:
|
|
return None
|
|
|
|
@property
|
|
def mission_departure_time(self) -> datetime:
|
|
return self.sweep_end_time
|
|
|
|
def add_waypoint_actions(self) -> None:
|
|
super().add_waypoint_actions()
|
|
self.layout.sweep_start.set_option(Formation.LINE_ABREAST_OPEN)
|
|
self.layout.sweep_start.add_action(
|
|
EngageTargets(
|
|
nautical_miles(50),
|
|
[
|
|
Targets.All.Air.Planes.Fighters,
|
|
Targets.All.Air.Planes.MultiroleFighters,
|
|
],
|
|
)
|
|
)
|
|
|
|
|
|
class Builder(IBuilder[SweepFlightPlan, SweepLayout]):
|
|
def layout(self) -> SweepLayout:
|
|
assert self.package.waypoints is not None
|
|
target = self.package.target.position
|
|
heading = Heading.from_degrees(
|
|
self.package.waypoints.join.heading_between_point(target)
|
|
)
|
|
start_pos = target.point_from_heading(
|
|
heading.degrees, -self.doctrine.sweep_distance.meters
|
|
)
|
|
|
|
builder = WaypointBuilder(self.flight, self.coalition)
|
|
start, end = builder.sweep(start_pos, target, self.doctrine.ingress_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_from=builder.nav_path(
|
|
end.position,
|
|
self.flight.arrival.position,
|
|
self.doctrine.ingress_altitude,
|
|
),
|
|
sweep_start=start,
|
|
sweep_end=end,
|
|
arrival=builder.land(self.flight.arrival),
|
|
divert=builder.divert(self.flight.divert),
|
|
bullseye=builder.bullseye(),
|
|
)
|
|
|
|
def _hold_point(self) -> Point:
|
|
assert self.package.waypoints is not None
|
|
origin = self.flight.departure.position
|
|
target = self.package.target.position
|
|
join = self.package.waypoints.join
|
|
ip = self.package.waypoints.ingress
|
|
return HoldZoneGeometry(
|
|
target, origin, ip, join, self.coalition, self.theater
|
|
).find_best_hold_point()
|
|
|
|
def build(self, dump_debug_info: bool = False) -> SweepFlightPlan:
|
|
return SweepFlightPlan(self.flight, self.layout())
|