Account for time elapsed when leaving combat.

This commit is contained in:
Dan Albert 2022-03-07 23:23:52 -08:00
parent e36c62b30e
commit f63a107c11
8 changed files with 57 additions and 16 deletions

View File

@ -19,6 +19,7 @@ class FlightState(ABC):
def __init__(self, flight: Flight, settings: Settings) -> None: def __init__(self, flight: Flight, settings: Settings) -> None:
self.flight = flight self.flight = flight
self.settings = settings self.settings = settings
self.avoid_further_combat = False
@property @property
def alive(self) -> bool: def alive(self) -> bool:

View File

@ -24,9 +24,16 @@ class InCombat(InFlight):
self.previous_state = previous_state self.previous_state = previous_state
self.combat = combat self.combat = combat
def exit_combat(self) -> None: def exit_combat(
# TODO: Account for time passed while frozen. self,
events: GameUpdateEvents,
time: datetime,
elapsed_time: timedelta,
avoid_further_combat: bool = False,
) -> None:
self.flight.set_state(self.previous_state) self.flight.set_state(self.previous_state)
self.previous_state.avoid_further_combat = avoid_further_combat
self.previous_state.on_game_tick(events, time, elapsed_time)
@property @property
def in_combat(self) -> bool: def in_combat(self) -> bool:

View File

@ -49,7 +49,7 @@ class AircraftSimulation:
still_active = [] still_active = []
for combat in self.combats: for combat in self.combats:
if combat.on_game_tick(duration, self.results, events): if combat.on_game_tick(time, duration, self.results, events):
events.end_combat(combat) events.end_combat(combat)
else: else:
still_active.append(combat) still_active.append(combat)

View File

@ -2,7 +2,7 @@ from __future__ import annotations
import logging import logging
import random import random
from datetime import timedelta from datetime import datetime, timedelta
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from shapely.ops import unary_union from shapely.ops import unary_union
@ -61,7 +61,13 @@ class AirCombat(JoinableCombat):
def describe(self) -> str: def describe(self) -> str:
return f"in air-to-air combat" return f"in air-to-air combat"
def resolve(self, results: SimulationResults, events: GameUpdateEvents) -> None: def resolve(
self,
results: SimulationResults,
events: GameUpdateEvents,
time: datetime,
elapsed_time: timedelta,
) -> None:
blue = [] blue = []
red = [] red = []
for flight in self.flights: for flight in self.flights:
@ -95,4 +101,4 @@ class AirCombat(JoinableCombat):
if random.random() >= 0.5: if random.random() >= 0.5:
flight.kill(results, events) flight.kill(results, events)
else: else:
flight.state.exit_combat() flight.state.exit_combat(events, time, elapsed_time)

View File

@ -2,11 +2,12 @@ from __future__ import annotations
import logging import logging
from collections.abc import Iterator from collections.abc import Iterator
from datetime import timedelta from datetime import datetime, timedelta
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from .frozencombat import FrozenCombat from .frozencombat import FrozenCombat
from .. import GameUpdateEvents from .. import GameUpdateEvents
from ...ato.flightstate import InCombat
if TYPE_CHECKING: if TYPE_CHECKING:
from game.ato import Flight from game.ato import Flight
@ -27,8 +28,18 @@ class AtIp(FrozenCombat):
def iter_flights(self) -> Iterator[Flight]: def iter_flights(self) -> Iterator[Flight]:
yield self.flight yield self.flight
def resolve(self, results: SimulationResults, events: GameUpdateEvents) -> None: def resolve(
self,
results: SimulationResults,
events: GameUpdateEvents,
time: datetime,
elapsed_time: timedelta,
) -> None:
logging.debug( logging.debug(
f"{self.flight} attack on {self.flight.package.target} auto-resolved with " f"{self.flight} attack on {self.flight.package.target} auto-resolved with "
"mission failure but no losses" "mission failure but no losses"
) )
assert isinstance(self.flight.state, InCombat)
self.flight.state.exit_combat(
events, time, elapsed_time, avoid_further_combat=True
)

View File

@ -95,7 +95,7 @@ class CombatInitiator:
if not flight.state.in_flight: if not flight.state.in_flight:
return None return None
if flight.state.is_at_ip: if flight.state.is_at_ip and not flight.state.avoid_further_combat:
return AtIp(timedelta(minutes=1), flight) return AtIp(timedelta(minutes=1), flight)
position = flight.state.estimate_position() position = flight.state.estimate_position()

View File

@ -3,7 +3,7 @@ from __future__ import annotations
import logging import logging
import random import random
from collections.abc import Iterator from collections.abc import Iterator
from datetime import timedelta from datetime import datetime, timedelta
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from game.ato.flightstate import InCombat from game.ato.flightstate import InCombat
@ -37,7 +37,13 @@ class DefendingSam(FrozenCombat):
def iter_flights(self) -> Iterator[Flight]: def iter_flights(self) -> Iterator[Flight]:
yield self.flight yield self.flight
def resolve(self, results: SimulationResults, events: GameUpdateEvents) -> None: def resolve(
self,
results: SimulationResults,
events: GameUpdateEvents,
time: datetime,
elapsed_time: timedelta,
) -> None:
assert isinstance(self.flight.state, InCombat) assert isinstance(self.flight.state, InCombat)
if random.random() >= 0.5: if random.random() >= 0.5:
logging.debug(f"Air defense combat auto-resolved with {self.flight} lost") logging.debug(f"Air defense combat auto-resolved with {self.flight} lost")
@ -46,4 +52,4 @@ class DefendingSam(FrozenCombat):
logging.debug( logging.debug(
f"Air defense combat auto-resolved with {self.flight} surviving" f"Air defense combat auto-resolved with {self.flight} surviving"
) )
self.flight.state.exit_combat() self.flight.state.exit_combat(events, time, elapsed_time)

View File

@ -3,7 +3,7 @@ from __future__ import annotations
import uuid import uuid
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from collections.abc import Iterator from collections.abc import Iterator
from datetime import timedelta from datetime import datetime, timedelta
from typing import TYPE_CHECKING from typing import TYPE_CHECKING
from game.ato.flightstate import InCombat, InFlight from game.ato.flightstate import InCombat, InFlight
@ -21,16 +21,26 @@ class FrozenCombat(ABC):
self.elapsed_time = timedelta() self.elapsed_time = timedelta()
def on_game_tick( def on_game_tick(
self, duration: timedelta, results: SimulationResults, events: GameUpdateEvents self,
time: datetime,
duration: timedelta,
results: SimulationResults,
events: GameUpdateEvents,
) -> bool: ) -> bool:
self.elapsed_time += duration self.elapsed_time += duration
if self.elapsed_time >= self.freeze_duration: if self.elapsed_time >= self.freeze_duration:
self.resolve(results, events) self.resolve(results, events, time, self.elapsed_time)
return True return True
return False return False
@abstractmethod @abstractmethod
def resolve(self, results: SimulationResults, events: GameUpdateEvents) -> None: def resolve(
self,
results: SimulationResults,
events: GameUpdateEvents,
time: datetime,
elapsed_time: timedelta,
) -> None:
... ...
@abstractmethod @abstractmethod