Track pilot deaths.

https://github.com/dcs-liberation/dcs_liberation/issues/276
This commit is contained in:
Dan Albert 2021-05-26 18:54:07 -07:00
parent 8b8e018521
commit cd6de191d1
4 changed files with 29 additions and 18 deletions

View File

@ -30,6 +30,7 @@ from game.unitmap import (
FrontLineUnit, FrontLineUnit,
GroundObjectUnit, GroundObjectUnit,
UnitMap, UnitMap,
FlyingUnit,
) )
from gen.flights.flight import Flight from gen.flights.flight import Flight
@ -41,24 +42,24 @@ DEBRIEFING_LOG_EXTENSION = "log"
@dataclass(frozen=True) @dataclass(frozen=True)
class AirLosses: class AirLosses:
player: List[Flight] player: List[FlyingUnit]
enemy: List[Flight] enemy: List[FlyingUnit]
@property @property
def losses(self) -> Iterator[Flight]: def losses(self) -> Iterator[FlyingUnit]:
return itertools.chain(self.player, self.enemy) return itertools.chain(self.player, self.enemy)
def by_type(self, player: bool) -> Dict[Type[FlyingType], int]: def by_type(self, player: bool) -> Dict[Type[FlyingType], int]:
losses_by_type: Dict[Type[FlyingType], int] = defaultdict(int) losses_by_type: Dict[Type[FlyingType], int] = defaultdict(int)
losses = self.player if player else self.enemy losses = self.player if player else self.enemy
for loss in losses: for loss in losses:
losses_by_type[loss.unit_type] += 1 losses_by_type[loss.flight.unit_type] += 1
return losses_by_type return losses_by_type
def surviving_flight_members(self, flight: Flight) -> int: def surviving_flight_members(self, flight: Flight) -> int:
losses = 0 losses = 0
for loss in self.losses: for loss in self.losses:
if loss == flight: if loss.flight == flight:
losses += 1 losses += 1
return flight.count - losses return flight.count - losses
@ -239,14 +240,14 @@ class Debriefing:
player_losses = [] player_losses = []
enemy_losses = [] enemy_losses = []
for unit_name in self.state_data.killed_aircraft: for unit_name in self.state_data.killed_aircraft:
flight = self.unit_map.flight(unit_name) aircraft = self.unit_map.flight(unit_name)
if flight is None: if aircraft is None:
logging.error(f"Could not find Flight matching {unit_name}") logging.error(f"Could not find Flight matching {unit_name}")
continue continue
if flight.departure.captured: if aircraft.flight.departure.captured:
player_losses.append(flight) player_losses.append(aircraft)
else: else:
enemy_losses.append(flight) enemy_losses.append(aircraft)
return AirLosses(player_losses, enemy_losses) return AirLosses(player_losses, enemy_losses)
def dead_ground_units(self) -> GroundLosses: def dead_ground_units(self) -> GroundLosses:

View File

@ -123,8 +123,9 @@ class Event:
@staticmethod @staticmethod
def commit_air_losses(debriefing: Debriefing) -> None: def commit_air_losses(debriefing: Debriefing) -> None:
for loss in debriefing.air_losses.losses: for loss in debriefing.air_losses.losses:
aircraft = loss.unit_type loss.pilot.alive = False
cp = loss.departure aircraft = loss.flight.unit_type
cp = loss.flight.departure
available = cp.base.total_units_of_type(aircraft) available = cp.base.total_units_of_type(aircraft)
if available <= 0: if available <= 0:
logging.error( logging.error(

View File

@ -52,7 +52,7 @@ class Squadron:
player: bool player: bool
def __post_init__(self) -> None: def __post_init__(self) -> None:
self.available_pilots = list(self.pilots) self.available_pilots = list(self.active_pilots)
def claim_available_pilot(self) -> Optional[Pilot]: def claim_available_pilot(self) -> Optional[Pilot]:
if not self.available_pilots: if not self.available_pilots:
@ -78,7 +78,7 @@ class Squadron:
self.available_pilots.extend(new_pilots) self.available_pilots.extend(new_pilots)
def return_all_pilots(self) -> None: def return_all_pilots(self) -> None:
self.available_pilots = list(self.pilots) self.available_pilots = list(self.active_pilots)
@property @property
def faker(self) -> Faker: def faker(self) -> Faker:

View File

@ -7,12 +7,19 @@ from dcs.unitgroup import FlyingGroup, Group, VehicleGroup
from dcs.unittype import VehicleType from dcs.unittype import VehicleType
from game import db from game import db
from game.squadrons import Pilot
from game.theater import Airfield, ControlPoint, TheaterGroundObject from game.theater import Airfield, ControlPoint, TheaterGroundObject
from game.theater.theatergroundobject import BuildingGroundObject, SceneryGroundObject from game.theater.theatergroundobject import BuildingGroundObject, SceneryGroundObject
from game.transfers import CargoShip, Convoy, TransferOrder from game.transfers import CargoShip, Convoy, TransferOrder
from gen.flights.flight import Flight from gen.flights.flight import Flight
@dataclass(frozen=True)
class FlyingUnit:
flight: Flight
pilot: Pilot
@dataclass(frozen=True) @dataclass(frozen=True)
class FrontLineUnit: class FrontLineUnit:
unit_type: Type[VehicleType] unit_type: Type[VehicleType]
@ -45,7 +52,7 @@ class Building:
class UnitMap: class UnitMap:
def __init__(self) -> None: def __init__(self) -> None:
self.aircraft: Dict[str, Flight] = {} self.aircraft: Dict[str, FlyingUnit] = {}
self.airfields: Dict[str, Airfield] = {} self.airfields: Dict[str, Airfield] = {}
self.front_line_units: Dict[str, FrontLineUnit] = {} self.front_line_units: Dict[str, FrontLineUnit] = {}
self.ground_object_units: Dict[str, GroundObjectUnit] = {} self.ground_object_units: Dict[str, GroundObjectUnit] = {}
@ -55,17 +62,19 @@ class UnitMap:
self.airlifts: Dict[str, AirliftUnit] = {} self.airlifts: Dict[str, AirliftUnit] = {}
def add_aircraft(self, group: FlyingGroup, flight: Flight) -> None: def add_aircraft(self, group: FlyingGroup, flight: Flight) -> None:
for unit in group.units: for pilot, unit in zip(flight.pilots, group.units):
# The actual name is a String (the pydcs translatable string), which # The actual name is a String (the pydcs translatable string), which
# doesn't define __eq__. # doesn't define __eq__.
name = str(unit.name) name = str(unit.name)
if name in self.aircraft: if name in self.aircraft:
raise RuntimeError(f"Duplicate unit name: {name}") raise RuntimeError(f"Duplicate unit name: {name}")
self.aircraft[name] = flight if pilot is None:
raise ValueError(f"{name} has no pilot assigned")
self.aircraft[name] = FlyingUnit(flight, pilot)
if flight.cargo is not None: if flight.cargo is not None:
self.add_airlift_units(group, flight.cargo) self.add_airlift_units(group, flight.cargo)
def flight(self, unit_name: str) -> Optional[Flight]: def flight(self, unit_name: str) -> Optional[FlyingUnit]:
return self.aircraft.get(unit_name, None) return self.aircraft.get(unit_name, None)
def add_airfield(self, airfield: Airfield) -> None: def add_airfield(self, airfield: Airfield) -> None: