mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Halt sim on A2A contact.
https://github.com/dcs-liberation/dcs_liberation/issues/1681
This commit is contained in:
@@ -8,14 +8,16 @@ from dcs import Point
|
||||
|
||||
from game.ato.flightstate import Completed
|
||||
from game.ato.flightstate.flightstate import FlightState
|
||||
from game.ato.flightwaypoint import FlightWaypoint
|
||||
from game.ato.flightwaypointtype import FlightWaypointType
|
||||
from game.ato.starttype import StartType
|
||||
from game.utils import Distance, Speed, meters
|
||||
from gen.flights.flightplan import LoiterFlightPlan, PatrollingFlightPlan
|
||||
from gen.flights.flightplan import LoiterFlightPlan
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.ato.flight import Flight
|
||||
from game.settings import Settings
|
||||
from game.sim.aircraftengagementzones import AircraftEngagementZones
|
||||
|
||||
|
||||
def lerp(v0: float, v1: float, t: float) -> float:
|
||||
@@ -23,27 +25,32 @@ def lerp(v0: float, v1: float, t: float) -> float:
|
||||
|
||||
|
||||
class InFlight(FlightState):
|
||||
def __init__(self, flight: Flight, settings: Settings) -> None:
|
||||
def __init__(self, flight: Flight, settings: Settings, waypoint_index: int) -> None:
|
||||
super().__init__(flight, settings)
|
||||
self.waypoints = flight.flight_plan.iter_waypoints()
|
||||
# TODO: Error checking for stupid flight plans with fewer than two waypoints.
|
||||
self.current_waypoint = next(self.waypoints)
|
||||
self.next_waypoint = next(self.waypoints)
|
||||
self.passed_waypoints = {self.current_waypoint}
|
||||
self.total_time_to_next_waypoint = self._total_time()
|
||||
waypoints = self.flight.flight_plan.waypoints
|
||||
self.waypoint_index = waypoint_index
|
||||
self.current_waypoint = waypoints[self.waypoint_index]
|
||||
# TODO: Error checking for flight plans without landing waypoints.
|
||||
self.next_waypoint = waypoints[self.waypoint_index + 1]
|
||||
self.total_time_to_next_waypoint = self.travel_time_between_waypoints()
|
||||
self.elapsed_time = timedelta()
|
||||
|
||||
def _total_time(self) -> timedelta:
|
||||
if isinstance(self.flight.flight_plan, PatrollingFlightPlan):
|
||||
# Racetracks should remain at the first waypoint until the patrol ends so
|
||||
# that the waypoint generation doesn't need to reverse the orbit direction.
|
||||
if self.current_waypoint == self.flight.flight_plan.patrol_start:
|
||||
return self.flight.flight_plan.patrol_duration
|
||||
def has_passed_waypoint(self, waypoint: FlightWaypoint) -> bool:
|
||||
index = self.flight.flight_plan.waypoints.index(waypoint)
|
||||
return index <= self.waypoint_index
|
||||
|
||||
# Loiter time is already built into travel_time_between_waypoints.
|
||||
return self.flight.flight_plan.travel_time_between_waypoints(
|
||||
def travel_time_between_waypoints(self) -> timedelta:
|
||||
travel_time = self.flight.flight_plan.travel_time_between_waypoints(
|
||||
self.current_waypoint, self.next_waypoint
|
||||
)
|
||||
if self.current_waypoint.waypoint_type is FlightWaypointType.LOITER:
|
||||
# Loiter time is already built into travel_time_between_waypoints. If we're
|
||||
# at a loiter point but still a regular InFlight (Loiter overrides this
|
||||
# method) that means we're traveling from the loiter point but no longer
|
||||
# loitering.
|
||||
assert isinstance(self.flight.flight_plan, LoiterFlightPlan)
|
||||
travel_time -= self.flight.flight_plan.hold_duration
|
||||
return travel_time
|
||||
|
||||
def progress(self) -> float:
|
||||
return (
|
||||
@@ -52,19 +59,6 @@ class InFlight(FlightState):
|
||||
)
|
||||
|
||||
def estimate_position(self) -> Point:
|
||||
# TODO: Make Loiter and RaceTrack distinct FlightStates.
|
||||
if isinstance(self.flight.flight_plan, PatrollingFlightPlan):
|
||||
# Prevent spawning racetracks in the middle of a leg. For simplicity we
|
||||
# always start the aircraft at the beginning of the racetrack.
|
||||
if self.current_waypoint == self.flight.flight_plan.patrol_start:
|
||||
return self.current_waypoint.position
|
||||
elif isinstance(self.flight.flight_plan, LoiterFlightPlan):
|
||||
if (
|
||||
self.current_waypoint == self.flight.flight_plan.hold
|
||||
and self.elapsed_time < self.flight.flight_plan.hold_duration
|
||||
):
|
||||
return self.current_waypoint.position
|
||||
|
||||
x0 = self.current_waypoint.position.x
|
||||
y0 = self.current_waypoint.position.y
|
||||
x1 = self.next_waypoint.position.x
|
||||
@@ -73,7 +67,6 @@ class InFlight(FlightState):
|
||||
return Point(lerp(x0, x1, progress), lerp(y0, y1, progress))
|
||||
|
||||
def estimate_altitude(self) -> tuple[Distance, str]:
|
||||
# TODO: Should count progress as 0 until departing a hold.
|
||||
return (
|
||||
meters(
|
||||
lerp(
|
||||
@@ -86,27 +79,32 @@ class InFlight(FlightState):
|
||||
)
|
||||
|
||||
def estimate_speed(self) -> Speed:
|
||||
# TODO: Patrol/loiter speeds may be different.
|
||||
return self.flight.flight_plan.speed_between_waypoints(
|
||||
self.current_waypoint, self.next_waypoint
|
||||
)
|
||||
|
||||
def update_waypoints(self) -> None:
|
||||
self.current_waypoint = self.next_waypoint
|
||||
self.passed_waypoints.add(self.current_waypoint)
|
||||
try:
|
||||
self.next_waypoint = next(self.waypoints)
|
||||
except StopIteration:
|
||||
self.flight.set_state(Completed(self.flight, self.settings))
|
||||
self.total_time_to_next_waypoint = self._total_time()
|
||||
self.elapsed_time = timedelta()
|
||||
def next_waypoint_state(self) -> FlightState:
|
||||
from game.ato.flightstate.loiter import Loiter
|
||||
from game.ato.flightstate.racetrack import RaceTrack
|
||||
|
||||
new_index = self.waypoint_index + 1
|
||||
if self.next_waypoint.waypoint_type is FlightWaypointType.LANDING_POINT:
|
||||
return Completed(self.flight, self.settings)
|
||||
if self.next_waypoint.waypoint_type is FlightWaypointType.PATROL_TRACK:
|
||||
return RaceTrack(self.flight, self.settings, new_index)
|
||||
if self.next_waypoint.waypoint_type is FlightWaypointType.LOITER:
|
||||
return Loiter(self.flight, self.settings, new_index)
|
||||
return InFlight(self.flight, self.settings, new_index)
|
||||
|
||||
def advance_to_next_waypoint(self) -> None:
|
||||
self.flight.set_state(self.next_waypoint_state())
|
||||
|
||||
def on_game_tick(self, time: datetime, duration: timedelta) -> None:
|
||||
self.elapsed_time += duration
|
||||
if self.elapsed_time > self.total_time_to_next_waypoint:
|
||||
self.update_waypoints()
|
||||
self.advance_to_next_waypoint()
|
||||
|
||||
def should_halt_sim(self) -> bool:
|
||||
def should_halt_sim(self, enemy_aircraft_coverage: AircraftEngagementZones) -> bool:
|
||||
contact_types = {
|
||||
FlightWaypointType.INGRESS_BAI,
|
||||
FlightWaypointType.INGRESS_CAS,
|
||||
@@ -116,7 +114,7 @@ class InFlight(FlightState):
|
||||
FlightWaypointType.INGRESS_SEAD,
|
||||
FlightWaypointType.INGRESS_STRIKE,
|
||||
}
|
||||
# TODO: Check against enemy threats.
|
||||
|
||||
if self.current_waypoint.waypoint_type in contact_types:
|
||||
logging.info(
|
||||
f"Interrupting simulation because {self.flight} has reached its "
|
||||
@@ -132,6 +130,13 @@ class InFlight(FlightState):
|
||||
)
|
||||
return True
|
||||
|
||||
if enemy_aircraft_coverage.covers(self.estimate_position()):
|
||||
logging.info(
|
||||
f"Interrupting simulation because {self.flight} has encountered enemy "
|
||||
"air-to-air patrol"
|
||||
)
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
@property
|
||||
|
||||
Reference in New Issue
Block a user