mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Add frozen combat modelling.
This doesn't do anything yet, but sets up the data model handling for frozen combat. The next step is to show combat in the map view, since that will be helpful when debugging the step after that one: resolving frozen combat. This would benefit from caching the Shapely data for SAM threat zones. Right now it's generating them once per tick and the stuttering is visible at max speed. https://github.com/dcs-liberation/dcs_liberation/issues/1680
This commit is contained in:
@@ -11,7 +11,6 @@ from .flightstate import FlightState, Uninitialized
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.sim.aircraftengagementzones import AircraftEngagementZones
|
||||
from game.squadrons import Squadron, Pilot
|
||||
from game.theater import ControlPoint, MissionTarget
|
||||
from game.transfers import TransferOrder
|
||||
@@ -151,10 +150,5 @@ class Flight:
|
||||
def on_game_tick(self, time: datetime, duration: timedelta) -> None:
|
||||
self.state.on_game_tick(time, duration)
|
||||
|
||||
def check_for_combat(
|
||||
self, enemy_aircraft_coverage: AircraftEngagementZones
|
||||
) -> None:
|
||||
self.state.check_for_combat(enemy_aircraft_coverage)
|
||||
|
||||
def should_halt_sim(self) -> bool:
|
||||
return self.state.should_halt_sim()
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
from .completed import Completed
|
||||
from .flightstate import FlightState
|
||||
from .incombat import InCombat
|
||||
from .inflight import InFlight
|
||||
from .navigating import Navigating
|
||||
from .startup import StartUp
|
||||
from .takeoff import Takeoff
|
||||
from .taxi import Taxi
|
||||
|
||||
@@ -9,7 +9,6 @@ from game.ato.starttype import StartType
|
||||
if TYPE_CHECKING:
|
||||
from game.ato.flight import Flight
|
||||
from game.settings import Settings
|
||||
from game.sim.aircraftengagementzones import AircraftEngagementZones
|
||||
from game.threatzones import ThreatPoly
|
||||
|
||||
|
||||
@@ -22,10 +21,17 @@ class FlightState(ABC):
|
||||
def on_game_tick(self, time: datetime, duration: timedelta) -> None:
|
||||
...
|
||||
|
||||
def check_for_combat(
|
||||
self, enemy_aircraft_coverage: AircraftEngagementZones
|
||||
) -> None:
|
||||
pass
|
||||
@property
|
||||
def vulnerable_to_intercept(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def vulnerable_to_sam(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def will_join_air_combat(self) -> bool:
|
||||
return False
|
||||
|
||||
def should_halt_sim(self) -> bool:
|
||||
return False
|
||||
|
||||
@@ -10,18 +10,18 @@ from .inflight import InFlight
|
||||
from ..starttype import StartType
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game.sim.aircraftengagementzones import AircraftEngagementZones
|
||||
from game.sim.combat import FrozenCombat
|
||||
|
||||
|
||||
class InCombat(InFlight):
|
||||
def __init__(self, previous_state: InFlight, description: str) -> None:
|
||||
def __init__(self, previous_state: InFlight, combat: FrozenCombat) -> None:
|
||||
super().__init__(
|
||||
previous_state.flight,
|
||||
previous_state.settings,
|
||||
previous_state.waypoint_index,
|
||||
)
|
||||
self.previous_state = previous_state
|
||||
self._description = description
|
||||
self.combat = combat
|
||||
|
||||
def estimate_position(self) -> Point:
|
||||
return self.previous_state.estimate_position()
|
||||
@@ -35,6 +35,10 @@ class InCombat(InFlight):
|
||||
def on_game_tick(self, time: datetime, duration: timedelta) -> None:
|
||||
raise RuntimeError("Cannot simulate combat")
|
||||
|
||||
@property
|
||||
def is_at_ip(self) -> bool:
|
||||
return False
|
||||
|
||||
@property
|
||||
def is_waiting_for_start(self) -> bool:
|
||||
return False
|
||||
@@ -42,10 +46,17 @@ class InCombat(InFlight):
|
||||
def should_halt_sim(self) -> bool:
|
||||
return True
|
||||
|
||||
def check_for_combat(
|
||||
self, enemy_aircraft_coverage: AircraftEngagementZones
|
||||
) -> None:
|
||||
pass
|
||||
@property
|
||||
def vulnerable_to_intercept(self) -> bool:
|
||||
# Interception results in the interceptor joining the existing combat rather
|
||||
# than creating a new combat.
|
||||
return False
|
||||
|
||||
@property
|
||||
def vulnerable_to_sam(self) -> bool:
|
||||
# SAM contact results in the SAM joining the existing combat rather than
|
||||
# creating a new combat.
|
||||
return False
|
||||
|
||||
@property
|
||||
def spawn_type(self) -> StartType:
|
||||
@@ -53,4 +64,4 @@ class InCombat(InFlight):
|
||||
|
||||
@property
|
||||
def description(self) -> str:
|
||||
return self._description
|
||||
return self.combat.describe()
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
from abc import ABC, abstractmethod
|
||||
from datetime import datetime, timedelta
|
||||
from typing import TYPE_CHECKING
|
||||
@@ -18,7 +17,6 @@ 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
|
||||
|
||||
|
||||
class InFlight(FlightState, ABC):
|
||||
@@ -95,11 +93,8 @@ class InFlight(FlightState, ABC):
|
||||
if self.elapsed_time > self.total_time_to_next_waypoint:
|
||||
self.advance_to_next_waypoint()
|
||||
|
||||
def check_for_combat(
|
||||
self, enemy_aircraft_coverage: AircraftEngagementZones
|
||||
) -> None:
|
||||
from game.ato.flightstate.incombat import InCombat
|
||||
|
||||
@property
|
||||
def is_at_ip(self) -> bool:
|
||||
contact_types = {
|
||||
FlightWaypointType.INGRESS_BAI,
|
||||
FlightWaypointType.INGRESS_CAS,
|
||||
@@ -109,30 +104,19 @@ class InFlight(FlightState, ABC):
|
||||
FlightWaypointType.INGRESS_SEAD,
|
||||
FlightWaypointType.INGRESS_STRIKE,
|
||||
}
|
||||
return self.current_waypoint.waypoint_type in contact_types
|
||||
|
||||
if self.current_waypoint.waypoint_type in contact_types:
|
||||
logging.info(
|
||||
f"Interrupting simulation because {self.flight} has reached its "
|
||||
"ingress point"
|
||||
)
|
||||
self.flight.set_state(InCombat(self, "At IP"))
|
||||
@property
|
||||
def vulnerable_to_intercept(self) -> bool:
|
||||
return True
|
||||
|
||||
threat_zone = self.flight.squadron.coalition.opponent.threat_zone
|
||||
if threat_zone.threatened_by_air_defense(self.estimate_position()):
|
||||
logging.info(
|
||||
f"Interrupting simulation because {self.flight} has encountered enemy "
|
||||
"air defenses"
|
||||
)
|
||||
self.flight.set_state(InCombat(self, "In combat with enemy air defenses"))
|
||||
@property
|
||||
def vulnerable_to_sam(self) -> bool:
|
||||
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"
|
||||
)
|
||||
self.flight.set_state(
|
||||
InCombat(self, "In combat with enemy air-to-air patrol")
|
||||
)
|
||||
@property
|
||||
def will_join_air_combat(self) -> bool:
|
||||
return self.flight.flight_type.is_air_to_air
|
||||
|
||||
@property
|
||||
def is_waiting_for_start(self) -> bool:
|
||||
|
||||
@@ -4,12 +4,12 @@ from datetime import timedelta
|
||||
from typing import Optional, TYPE_CHECKING
|
||||
|
||||
from dcs import Point
|
||||
from shapely.geometry import LineString, Point as ShapelyPoint
|
||||
from shapely.geometry import LineString
|
||||
|
||||
from game.ato import FlightType
|
||||
from game.ato.flightstate import InFlight
|
||||
from game.threatzones import ThreatPoly
|
||||
from game.utils import Distance, Speed
|
||||
from game.utils import Distance, Speed, dcs_to_shapely_point
|
||||
from gen.flights.flightplan import PatrollingFlightPlan
|
||||
|
||||
if TYPE_CHECKING:
|
||||
@@ -24,8 +24,8 @@ class RaceTrack(InFlight):
|
||||
super().__init__(flight, settings, waypoint_index)
|
||||
self.commit_region = LineString(
|
||||
[
|
||||
ShapelyPoint(self.current_waypoint.x, self.current_waypoint.y),
|
||||
ShapelyPoint(self.next_waypoint.x, self.next_waypoint.y),
|
||||
dcs_to_shapely_point(self.current_waypoint.position),
|
||||
dcs_to_shapely_point(self.next_waypoint.position),
|
||||
]
|
||||
).buffer(flight.flight_plan.engagement_distance.meters)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user