mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Separate combat as a distinct flight state.
Will be used later to simulate combat. https://github.com/dcs-liberation/dcs_liberation/issues/1680
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
@@ -11,7 +12,7 @@ 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, LBS_TO_KG, Speed, meters, pairwise
|
||||
from game.utils import Distance, LBS_TO_KG, Speed, pairwise
|
||||
from gen.flights.flightplan import LoiterFlightPlan
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -20,11 +21,7 @@ if TYPE_CHECKING:
|
||||
from game.sim.aircraftengagementzones import AircraftEngagementZones
|
||||
|
||||
|
||||
def lerp(v0: float, v1: float, t: float) -> float:
|
||||
return (1 - t) * v0 + t * v1
|
||||
|
||||
|
||||
class InFlight(FlightState):
|
||||
class InFlight(FlightState, ABC):
|
||||
def __init__(self, flight: Flight, settings: Settings, waypoint_index: int) -> None:
|
||||
super().__init__(flight, settings)
|
||||
waypoints = self.flight.flight_plan.waypoints
|
||||
@@ -52,36 +49,17 @@ class InFlight(FlightState):
|
||||
travel_time -= self.flight.flight_plan.hold_duration
|
||||
return travel_time
|
||||
|
||||
def progress(self) -> float:
|
||||
return (
|
||||
self.elapsed_time.total_seconds()
|
||||
/ self.total_time_to_next_waypoint.total_seconds()
|
||||
)
|
||||
|
||||
@abstractmethod
|
||||
def estimate_position(self) -> Point:
|
||||
x0 = self.current_waypoint.position.x
|
||||
y0 = self.current_waypoint.position.y
|
||||
x1 = self.next_waypoint.position.x
|
||||
y1 = self.next_waypoint.position.y
|
||||
progress = self.progress()
|
||||
return Point(lerp(x0, x1, progress), lerp(y0, y1, progress))
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def estimate_altitude(self) -> tuple[Distance, str]:
|
||||
return (
|
||||
meters(
|
||||
lerp(
|
||||
self.current_waypoint.alt.meters,
|
||||
self.next_waypoint.alt.meters,
|
||||
self.progress(),
|
||||
)
|
||||
),
|
||||
self.current_waypoint.alt_type,
|
||||
)
|
||||
...
|
||||
|
||||
@abstractmethod
|
||||
def estimate_speed(self) -> Speed:
|
||||
return self.flight.flight_plan.speed_between_waypoints(
|
||||
self.current_waypoint, self.next_waypoint
|
||||
)
|
||||
...
|
||||
|
||||
def estimate_fuel_at_current_waypoint(self) -> float:
|
||||
initial_fuel = super().estimate_fuel()
|
||||
@@ -95,21 +73,10 @@ class InFlight(FlightState):
|
||||
initial_fuel -= consumption * LBS_TO_KG
|
||||
return initial_fuel
|
||||
|
||||
def estimate_fuel(self) -> float:
|
||||
initial_fuel = self.estimate_fuel_at_current_waypoint()
|
||||
ppm = self.flight.flight_plan.fuel_rate_to_between_points(
|
||||
self.current_waypoint, self.next_waypoint
|
||||
)
|
||||
if ppm is None:
|
||||
return initial_fuel
|
||||
position = self.estimate_position()
|
||||
distance = meters(self.current_waypoint.position.distance_to_point(position))
|
||||
consumption = distance.nautical_miles * ppm * LBS_TO_KG
|
||||
return initial_fuel - consumption
|
||||
|
||||
def next_waypoint_state(self) -> FlightState:
|
||||
from game.ato.flightstate.loiter import Loiter
|
||||
from game.ato.flightstate.racetrack import RaceTrack
|
||||
from .loiter import Loiter
|
||||
from .racetrack import RaceTrack
|
||||
from .navigating import Navigating
|
||||
|
||||
new_index = self.waypoint_index + 1
|
||||
if self.next_waypoint.waypoint_type is FlightWaypointType.LANDING_POINT:
|
||||
@@ -118,7 +85,7 @@ class InFlight(FlightState):
|
||||
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)
|
||||
return Navigating(self.flight, self.settings, new_index)
|
||||
|
||||
def advance_to_next_waypoint(self) -> None:
|
||||
self.flight.set_state(self.next_waypoint_state())
|
||||
@@ -128,7 +95,11 @@ class InFlight(FlightState):
|
||||
if self.elapsed_time > self.total_time_to_next_waypoint:
|
||||
self.advance_to_next_waypoint()
|
||||
|
||||
def should_halt_sim(self, enemy_aircraft_coverage: AircraftEngagementZones) -> bool:
|
||||
def check_for_combat(
|
||||
self, enemy_aircraft_coverage: AircraftEngagementZones
|
||||
) -> None:
|
||||
from game.ato.flightstate.incombat import InCombat
|
||||
|
||||
contact_types = {
|
||||
FlightWaypointType.INGRESS_BAI,
|
||||
FlightWaypointType.INGRESS_CAS,
|
||||
@@ -144,7 +115,7 @@ class InFlight(FlightState):
|
||||
f"Interrupting simulation because {self.flight} has reached its "
|
||||
"ingress point"
|
||||
)
|
||||
return True
|
||||
self.flight.set_state(InCombat(self, "At IP"))
|
||||
|
||||
threat_zone = self.flight.squadron.coalition.opponent.threat_zone
|
||||
if threat_zone.threatened_by_air_defense(self.estimate_position()):
|
||||
@@ -152,16 +123,16 @@ class InFlight(FlightState):
|
||||
f"Interrupting simulation because {self.flight} has encountered enemy "
|
||||
"air defenses"
|
||||
)
|
||||
return True
|
||||
self.flight.set_state(InCombat(self, "In combat with enemy air defenses"))
|
||||
|
||||
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
|
||||
self.flight.set_state(
|
||||
InCombat(self, "In combat with enemy air-to-air patrol")
|
||||
)
|
||||
|
||||
@property
|
||||
def is_waiting_for_start(self) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user