diff --git a/game/debriefing.py b/game/debriefing.py index 12975d1c..2bf879c6 100644 --- a/game/debriefing.py +++ b/game/debriefing.py @@ -1,5 +1,6 @@ from __future__ import annotations +import itertools import json import logging import os @@ -31,42 +32,42 @@ DEBRIEFING_LOG_EXTENSION = "log" @dataclass(frozen=True) -class DebriefingDeadAircraftInfo: - #: The Flight that resulted in the generated unit. - flight: Flight +class AirLosses: + player: List[Flight] + enemy: List[Flight] @property - def player_unit(self) -> bool: - return self.flight.departure.captured - - -@dataclass(frozen=True) -class AirLosses: - losses: List[DebriefingDeadAircraftInfo] + def losses(self) -> Iterator[Flight]: + return itertools.chain(self.player, self.enemy) def by_type(self, player: bool) -> Dict[Type[FlyingType], int]: losses_by_type: Dict[Type[FlyingType], int] = defaultdict(int) - for loss in self.losses: - if loss.flight.departure.captured != player: - continue - - losses_by_type[loss.flight.unit_type] += 1 + losses = self.player if player else self.enemy + for loss in losses: + losses_by_type[loss.unit_type] += 1 return losses_by_type def surviving_flight_members(self, flight: Flight) -> int: losses = 0 for loss in self.losses: - if loss.flight == flight: + if loss == flight: losses += 1 return flight.count - losses @dataclass class GroundLosses: - front_line: List[FrontLineUnit] = field(default_factory=list) - ground_objects: List[GroundObjectUnit] = field(default_factory=list) - buildings: List[Building] = field(default_factory=list) - airfields: List[Airfield] = field(default_factory=list) + player_front_line: List[FrontLineUnit] = field(default_factory=list) + enemy_front_line: List[FrontLineUnit] = field(default_factory=list) + + player_ground_objects: List[GroundObjectUnit] = field(default_factory=list) + enemy_ground_objects: List[GroundObjectUnit] = field(default_factory=list) + + player_buildings: List[Building] = field(default_factory=list) + enemy_buildings: List[Building] = field(default_factory=list) + + player_airfields: List[Airfield] = field(default_factory=list) + enemy_airfields: List[Airfield] = field(default_factory=list) @dataclass(frozen=True) @@ -115,19 +116,23 @@ class Debriefing: @property def front_line_losses(self) -> Iterator[FrontLineUnit]: - yield from self.ground_losses.front_line + yield from self.ground_losses.player_front_line + yield from self.ground_losses.enemy_front_line @property def ground_object_losses(self) -> Iterator[GroundObjectUnit]: - yield from self.ground_losses.ground_objects + yield from self.ground_losses.player_ground_objects + yield from self.ground_losses.enemy_ground_objects @property def building_losses(self) -> Iterator[Building]: - yield from self.ground_losses.buildings + yield from self.ground_losses.player_buildings + yield from self.ground_losses.enemy_buildings @property def damaged_runways(self) -> Iterator[Airfield]: - yield from self.ground_losses.airfields + yield from self.ground_losses.player_airfields + yield from self.ground_losses.enemy_airfields def casualty_count(self, control_point: ControlPoint) -> int: return len( @@ -137,16 +142,21 @@ class Debriefing: def front_line_losses_by_type( self, player: bool) -> Dict[Type[UnitType], int]: losses_by_type: Dict[Type[UnitType], int] = defaultdict(int) - for loss in self.ground_losses.front_line: - if loss.origin.captured != player: - continue - + if player: + losses = self.ground_losses.player_front_line + else: + losses = self.ground_losses.enemy_front_line + for loss in losses: losses_by_type[loss.unit_type] += 1 return losses_by_type def building_losses_by_type(self, player: bool) -> Dict[str, int]: losses_by_type: Dict[str, int] = defaultdict(int) - for loss in self.ground_losses.buildings: + if player: + losses = self.ground_losses.player_buildings + else: + losses = self.ground_losses.enemy_buildings + for loss in losses: if loss.ground_object.control_point.captured != player: continue @@ -154,36 +164,52 @@ class Debriefing: return losses_by_type def dead_aircraft(self) -> AirLosses: - losses = [] + player_losses = [] + enemy_losses = [] for unit_name in self.state_data.killed_aircraft: flight = self.unit_map.flight(unit_name) if flight is None: logging.error(f"Could not find Flight matching {unit_name}") continue - losses.append(DebriefingDeadAircraftInfo(flight)) - return AirLosses(losses) + if flight.departure.captured: + player_losses.append(flight) + else: + enemy_losses.append(flight) + return AirLosses(player_losses, enemy_losses) def dead_ground_units(self) -> GroundLosses: losses = GroundLosses() for unit_name in self.state_data.killed_ground_units: front_line_unit = self.unit_map.front_line_unit(unit_name) if front_line_unit is not None: - losses.front_line.append(front_line_unit) + if front_line_unit.origin.captured: + losses.player_front_line.append(front_line_unit) + else: + losses.enemy_front_line.append(front_line_unit) continue ground_object_unit = self.unit_map.ground_object_unit(unit_name) if ground_object_unit is not None: - losses.ground_objects.append(ground_object_unit) + if ground_object_unit.ground_object.control_point.captured: + losses.player_ground_objects.append(ground_object_unit) + else: + losses.enemy_ground_objects.append(ground_object_unit) continue building = self.unit_map.building_or_fortification(unit_name) if building is not None: - losses.buildings.append(building) + if building.ground_object.control_point.captured: + losses.player_buildings.append(building) + else: + losses.enemy_buildings.append(building) continue airfield = self.unit_map.airfield(unit_name) if airfield is not None: - losses.airfields.append(airfield) + if airfield.captured: + losses.player_airfields.append(airfield) + else: + losses.enemy_airfields.append(airfield) continue # Only logging as debug because we don't currently track infantry diff --git a/game/event/event.py b/game/event/event.py index f94ab408..4ecd5329 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -116,8 +116,8 @@ class Event: @staticmethod def commit_air_losses(debriefing: Debriefing) -> None: for loss in debriefing.air_losses.losses: - aircraft = loss.flight.unit_type - cp = loss.flight.departure + aircraft = loss.unit_type + cp = loss.departure available = cp.base.total_units_of_type(aircraft) if available <= 0: logging.error( diff --git a/qt_ui/windows/QLiberationWindow.py b/qt_ui/windows/QLiberationWindow.py index 9bcf9479..99fcf7c2 100644 --- a/qt_ui/windows/QLiberationWindow.py +++ b/qt_ui/windows/QLiberationWindow.py @@ -26,7 +26,7 @@ from qt_ui.uiconstants import URLS from qt_ui.widgets.QTopPanel import QTopPanel from qt_ui.widgets.ato import QAirTaskingOrderPanel from qt_ui.widgets.map.QLiberationMap import QLiberationMap -from qt_ui.windows.GameUpdateSignal import DebriefingSignal, GameUpdateSignal +from qt_ui.windows.GameUpdateSignal import GameUpdateSignal from qt_ui.windows.QDebriefingWindow import QDebriefingWindow from qt_ui.windows.infos.QInfoPanel import QInfoPanel from qt_ui.windows.newgame.QNewGameWizard import NewGameWizard diff --git a/qt_ui/windows/QWaitingForMissionResultWindow.py b/qt_ui/windows/QWaitingForMissionResultWindow.py index 5e9a99df..e101389c 100644 --- a/qt_ui/windows/QWaitingForMissionResultWindow.py +++ b/qt_ui/windows/QWaitingForMissionResultWindow.py @@ -135,7 +135,7 @@ class QWaitingForMissionResultWindow(QDialog): updateLayout.addWidget(QLabel("Aircraft destroyed"), 0, 0) updateLayout.addWidget( - QLabel(str(len(debriefing.air_losses.losses))), 0, 1) + QLabel(str(len(list(debriefing.air_losses.losses)))), 0, 1) updateLayout.addWidget( QLabel("Front line units destroyed"), 1, 0)