Migrate buildings and TGOs to unit map.

Fixes https://github.com/Khopa/dcs_liberation/issues/485.
This commit is contained in:
Dan Albert 2020-12-04 00:35:05 -08:00
parent 13f4baa34e
commit 90697194a1
9 changed files with 238 additions and 246 deletions

View File

@ -6,14 +6,22 @@ import os
import threading
import time
from collections import defaultdict
from dataclasses import dataclass
from typing import Any, Callable, Dict, List, Type, TYPE_CHECKING
from dataclasses import dataclass, field
from typing import (
Any,
Callable,
Dict,
Iterator,
List,
Type,
TYPE_CHECKING,
)
from dcs.unittype import FlyingType, UnitType
from game import db
from game.theater import Airfield, ControlPoint, TheaterGroundObject
from game.unitmap import UnitMap
from game.theater import Airfield, ControlPoint
from game.unitmap import Building, FrontLineUnit, GroundObjectUnit, UnitMap
from gen.flights.flight import Flight
if TYPE_CHECKING:
@ -22,12 +30,6 @@ if TYPE_CHECKING:
DEBRIEFING_LOG_EXTENSION = "log"
@dataclass(frozen=True)
class DebriefingDeadUnitInfo:
player_unit: bool
type: Type[UnitType]
@dataclass(frozen=True)
class DebriefingDeadAircraftInfo:
#: The Flight that resulted in the generated unit.
@ -38,27 +40,6 @@ class DebriefingDeadAircraftInfo:
return self.flight.departure.captured
@dataclass(frozen=True)
class DebriefingDeadFrontLineUnitInfo:
#: The Flight that resulted in the generated unit.
unit_type: Type[UnitType]
control_point: ControlPoint
@property
def player_unit(self) -> bool:
return self.control_point.captured
@dataclass(frozen=True)
class DebriefingDeadBuildingInfo:
#: The ground object this building was present at.
ground_object: TheaterGroundObject
@property
def player_unit(self) -> bool:
return self.ground_object.control_point.captured
@dataclass(frozen=True)
class AirLosses:
losses: List[DebriefingDeadAircraftInfo]
@ -80,18 +61,12 @@ class AirLosses:
return flight.count - losses
@dataclass(frozen=True)
class FrontLineLosses:
losses: List[DebriefingDeadFrontLineUnitInfo]
def by_type(self, player: bool) -> Dict[Type[UnitType], int]:
losses_by_type: Dict[Type[UnitType], int] = defaultdict(int)
for loss in self.losses:
if loss.control_point.captured != player:
continue
losses_by_type[loss.unit_type] += 1
return losses_by_type
@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)
@dataclass(frozen=True)
@ -131,80 +106,51 @@ class Debriefing:
self.game = game
self.unit_map = unit_map
logging.info("--------------------------------")
logging.info("Starting Debriefing preprocessing")
logging.info("--------------------------------")
logging.info(self.state_data)
logging.info("--------------------------------")
self.player_country_id = db.country_id_from_name(game.player_country)
self.enemy_country_id = db.country_id_from_name(game.enemy_country)
self.air_losses = self.dead_aircraft()
self.front_line_losses = self.dead_front_line_units()
self.dead_units = []
self.damaged_runways = self.find_damaged_runways()
self.dead_aaa_groups: List[DebriefingDeadUnitInfo] = []
self.dead_buildings: List[DebriefingDeadBuildingInfo] = []
self.ground_losses = self.dead_ground_units()
for unit_name in self.state_data.killed_ground_units:
for cp in game.theater.controlpoints:
if cp.captured:
country = self.player_country_id
else:
country = self.enemy_country_id
player_unit = (country == self.player_country_id)
@property
def front_line_losses(self) -> Iterator[FrontLineUnit]:
yield from self.ground_losses.front_line
for ground_object in cp.ground_objects:
# TODO: This seems to destroy an arbitrary building?
if ground_object.is_same_group(unit_name):
self.dead_buildings.append(
DebriefingDeadBuildingInfo(ground_object))
elif ground_object.dcs_identifier in ["AA", "CARRIER",
"LHA"]:
for g in ground_object.groups:
for u in g.units:
if u.name != unit_name:
continue
unit_type = db.unit_type_from_name(u.type)
if unit_type is None:
logging.error(
f"Could not determine type of %s",
unit_name)
continue
self.dead_units.append(DebriefingDeadUnitInfo(
player_unit, unit_type))
@property
def ground_object_losses(self) -> Iterator[GroundObjectUnit]:
yield from self.ground_losses.ground_objects
self.player_dead_units = [a for a in self.dead_units if a.player_unit]
self.enemy_dead_units = [a for a in self.dead_units if not a.player_unit]
self.player_dead_buildings = [a for a in self.dead_buildings if a.player_unit]
self.enemy_dead_buildings = [a for a in self.dead_buildings if not a.player_unit]
@property
def building_losses(self) -> Iterator[Building]:
yield from self.ground_losses.buildings
self.player_dead_units_dict: Dict[Type[UnitType], int] = defaultdict(int)
for a in self.player_dead_units:
self.player_dead_units_dict[a.type] += 1
@property
def damaged_runways(self) -> Iterator[Airfield]:
yield from self.ground_losses.airfields
self.enemy_dead_units_dict: Dict[Type[UnitType], int] = defaultdict(int)
for a in self.enemy_dead_units:
self.enemy_dead_units_dict[a.type] += 1
def casualty_count(self, control_point: ControlPoint) -> int:
return len(
[x for x in self.front_line_losses if x.origin == control_point]
)
self.player_dead_buildings_dict: Dict[str, int] = defaultdict(int)
for b in self.player_dead_buildings:
self.player_dead_buildings_dict[b.ground_object.dcs_identifier] += 1
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
self.enemy_dead_buildings_dict: Dict[str, int] = defaultdict(int)
for b in self.enemy_dead_buildings:
self.enemy_dead_buildings_dict[b.ground_object.dcs_identifier] += 1
losses_by_type[loss.unit_type] += 1
return losses_by_type
logging.info("--------------------------------")
logging.info("Debriefing pre process results :")
logging.info("--------------------------------")
logging.info(self.air_losses)
logging.info(self.front_line_losses)
logging.info(self.player_dead_units_dict)
logging.info(self.enemy_dead_units_dict)
logging.info(self.player_dead_buildings_dict)
logging.info(self.enemy_dead_buildings_dict)
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 loss.ground_object.control_point.captured != player:
continue
losses_by_type[loss.ground_object.dcs_identifier] += 1
return losses_by_type
def dead_aircraft(self) -> AirLosses:
losses = []
@ -216,30 +162,38 @@ class Debriefing:
losses.append(DebriefingDeadAircraftInfo(flight))
return AirLosses(losses)
def dead_front_line_units(self) -> FrontLineLosses:
losses = []
def dead_ground_units(self) -> GroundLosses:
losses = GroundLosses()
for unit_name in self.state_data.killed_ground_units:
unit = self.unit_map.front_line_unit(unit_name)
if unit is None:
# Killed "ground units" might also be runways or TGO units, so
# no need to log an error.
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)
continue
losses.append(
DebriefingDeadFrontLineUnitInfo(unit.unit_type, unit.origin))
return FrontLineLosses(losses)
def find_damaged_runways(self) -> List[Airfield]:
losses = []
for name in self.state_data.killed_ground_units:
airfield = self.unit_map.airfield(name)
if airfield is None:
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)
continue
losses.append(airfield)
building = self.unit_map.building(unit_name)
if building is not None:
losses.buildings.append(building)
continue
airfield = self.unit_map.airfield(unit_name)
if airfield is not None:
losses.airfields.append(airfield)
continue
# Only logging as debug because we don't currently track infantry
# deaths, so we expect to see quite a few unclaimed dead ground
# units. We should start tracking those and covert this to a
# warning.
logging.debug(f"Death of untracked ground unit {unit_name} will "
"have no effect. This may be normal behavior.")
return losses
def _is_airfield(self, unit_name: str) -> bool:
return self.unit_map.airfield(unit_name) is not None
@property
def base_capture_events(self):
"""Keeps only the last instance of a base capture event for each base ID."""

View File

@ -2,21 +2,20 @@ from __future__ import annotations
import logging
import math
from collections import defaultdict
from typing import Dict, List, Optional, TYPE_CHECKING, Type
from typing import Dict, List, TYPE_CHECKING, Type
from dcs.mapping import Point
from dcs.task import Task
from dcs.unittype import UnitType
from game import db, persistency
from game import persistency
from game.debriefing import AirLosses, Debriefing
from game.infos.information import Information
from game.operation.operation import Operation
from game.theater import ControlPoint
from gen import AirTaskingOrder
from gen.ground_forces.combat_stance import CombatStance
from ..unitmap import UnitMap
from game.operation.operation import Operation
if TYPE_CHECKING:
from ..game import Game
@ -130,12 +129,10 @@ class Event:
cp.base.aircraft[aircraft] -= 1
@staticmethod
def commit_front_line_losses(debriefing: Debriefing) -> Dict[int, int]:
killed_unit_count_by_cp: Dict[int, int] = defaultdict(int)
for loss in debriefing.front_line_losses.losses:
def commit_front_line_losses(debriefing: Debriefing) -> None:
for loss in debriefing.front_line_losses:
unit_type = loss.unit_type
control_point = loss.control_point
killed_unit_count_by_cp[control_point.id] += 1
control_point = loss.origin
available = control_point.base.total_units_of_type(unit_type)
if available <= 0:
logging.error(
@ -145,64 +142,41 @@ class Event:
logging.info(f"{unit_type} destroyed from {control_point}")
control_point.base.armor[unit_type] -= 1
return killed_unit_count_by_cp
@staticmethod
def commit_ground_object_losses(debriefing: Debriefing) -> None:
for loss in debriefing.ground_object_losses:
# TODO: This should be stored in the TGO, not in the pydcs Group.
if not hasattr(loss.group, "units_losts"):
loss.group.units_losts = []
loss.group.units.remove(loss.unit)
loss.group.units_losts.append(loss.unit)
if not loss.ground_object.alive_unit_count:
loss.ground_object.is_dead = True
def commit_building_losses(self, debriefing: Debriefing) -> None:
for loss in debriefing.building_losses:
loss.ground_object.is_dead = True
self.game.informations.append(Information(
"Building destroyed",
f"{loss.ground_object.dcs_identifier} has been destroyed at "
f"location {loss.ground_object.obj_name}", self.game.turn
))
@staticmethod
def commit_damaged_runways(debriefing: Debriefing) -> None:
for damaged_runway in debriefing.damaged_runways:
damaged_runway.damage_runway()
def commit(self, debriefing: Debriefing):
logging.info("Committing mission results")
for damaged_runway in debriefing.damaged_runways:
damaged_runway.damage_runway()
self.commit_air_losses(debriefing)
killed_unit_count_by_cp = self.commit_front_line_losses(debriefing)
# ------------------------------
# Static ground objects
for destroyed_ground_unit_name in debriefing.state_data.killed_ground_units:
for cp in self.game.theater.controlpoints:
if not cp.ground_objects:
continue
# -- Static ground objects
for i, ground_object in enumerate(cp.ground_objects):
if ground_object.is_dead:
continue
if (
(ground_object.group_name == destroyed_ground_unit_name)
or
(ground_object.is_same_group(destroyed_ground_unit_name))
):
logging.info("cp {} killing ground object {}".format(cp, ground_object.group_name))
cp.ground_objects[i].is_dead = True
info = Information("Building destroyed",
ground_object.dcs_identifier + " has been destroyed at location " + ground_object.obj_name,
self.game.turn)
self.game.informations.append(info)
# -- AA Site groups
destroyed_units = 0
info = Information("Units destroyed at " + ground_object.obj_name,
"",
self.game.turn)
for i, ground_object in enumerate(cp.ground_objects):
if ground_object.dcs_identifier in ["AA", "CARRIER", "LHA", "EWR"]:
for g in ground_object.groups:
if not hasattr(g, "units_losts"):
g.units_losts = []
for u in g.units:
if u.name == destroyed_ground_unit_name:
g.units.remove(u)
g.units_losts.append(u)
destroyed_units = destroyed_units + 1
info.text = u.type
ucount = sum([len(g.units) for g in ground_object.groups])
if ucount == 0:
ground_object.is_dead = True
if destroyed_units > 0:
self.game.informations.append(info)
self.commit_front_line_losses(debriefing)
self.commit_ground_object_losses(debriefing)
self.commit_building_losses(debriefing)
self.commit_damaged_runways(debriefing)
# ------------------------------
# Captured bases
@ -257,8 +231,8 @@ class Event:
delta = 0.0
player_won = True
ally_casualties = killed_unit_count_by_cp[cp.id]
enemy_casualties = killed_unit_count_by_cp[enemy_cp.id]
ally_casualties = debriefing.casualty_count(cp)
enemy_casualties = debriefing.casualty_count(enemy_cp)
ally_units_alive = cp.base.total_armor
enemy_units_alive = enemy_cp.base.total_armor

View File

@ -265,7 +265,8 @@ class Operation:
cls.current_mission,
cls.game,
cls.radio_registry,
cls.tacan_registry
cls.tacan_registry,
cls.unit_map
)
cls.groundobjectgen.generate()

View File

@ -23,7 +23,7 @@ class Base:
def __init__(self):
self.aircraft: Dict[Type[FlyingType], int] = {}
self.armor: Dict[VehicleType, int] = {}
self.armor: Dict[Type[VehicleType], int] = {}
self.aa: Dict[AirDefence, int] = {}
self.commision_points: Dict[Type, float] = {}
self.strength = 1

View File

@ -136,6 +136,10 @@ class TheaterGroundObject(MissionTarget):
]
yield from super().mission_types(for_player)
@property
def alive_unit_count(self) -> int:
return sum(len(g.units) for g in self.groups)
class BuildingGroundObject(TheaterGroundObject):
def __init__(self, name: str, category: str, group_id: int, object_id: int,

View File

@ -2,25 +2,41 @@
from dataclasses import dataclass
from typing import Dict, Optional, Type
from dcs.unitgroup import FlyingGroup, Group
from dcs.unittype import UnitType
from dcs.unit import Unit
from dcs.unitgroup import FlyingGroup, Group, StaticGroup
from dcs.unittype import VehicleType
from game import db
from game.theater import Airfield, ControlPoint
from game.theater import Airfield, ControlPoint, TheaterGroundObject
from game.theater.theatergroundobject import BuildingGroundObject
from gen.flights.flight import Flight
@dataclass
@dataclass(frozen=True)
class FrontLineUnit:
unit_type: Type[UnitType]
unit_type: Type[VehicleType]
origin: ControlPoint
@dataclass(frozen=True)
class GroundObjectUnit:
ground_object: TheaterGroundObject
group: Group
unit: Unit
@dataclass(frozen=True)
class Building:
ground_object: BuildingGroundObject
class UnitMap:
def __init__(self) -> None:
self.aircraft: Dict[str, Flight] = {}
self.airfields: Dict[str, Airfield] = {}
self.front_line_units: Dict[str, FrontLineUnit] = {}
self.ground_object_units: Dict[str, GroundObjectUnit] = {}
self.buildings: Dict[str, Building] = {}
def add_aircraft(self, group: FlyingGroup, flight: Flight) -> None:
for unit in group.units:
@ -52,7 +68,36 @@ class UnitMap:
unit_type = db.unit_type_from_name(unit.type)
if unit_type is None:
raise RuntimeError(f"Unknown unit type: {unit.type}")
if not issubclass(unit_type, VehicleType):
raise RuntimeError(
f"{name} is a {unit_type.__name__}, expected a VehicleType")
self.front_line_units[name] = FrontLineUnit(unit_type, origin)
def front_line_unit(self, name: str) -> Optional[FrontLineUnit]:
return self.front_line_units.get(name, None)
def add_ground_object_units(self, ground_object: TheaterGroundObject,
group: Group) -> None:
for unit in group.units:
# The actual name is a String (the pydcs translatable string), which
# doesn't define __eq__.
name = str(unit.name)
if name in self.ground_object_units:
raise RuntimeError(f"Duplicate TGO unit: {name}")
self.ground_object_units[name] = GroundObjectUnit(ground_object,
group, unit)
def ground_object_unit(self, name: str) -> Optional[GroundObjectUnit]:
return self.ground_object_units.get(name, None)
def add_building(self, ground_object: BuildingGroundObject,
building: StaticGroup) -> None:
# The actual name is a String (the pydcs translatable string), which
# doesn't define __eq__.
name = str(building.name)
if name in self.buildings:
raise RuntimeError(f"Duplicate TGO unit: {name}")
self.buildings[name] = Building(ground_object)
def building(self, name: str) -> Optional[Building]:
return self.buildings.get(name, None)

View File

@ -9,7 +9,7 @@ from __future__ import annotations
import logging
import random
from typing import Dict, Iterator, Optional, TYPE_CHECKING
from typing import Dict, Iterator, Optional, TYPE_CHECKING, Type
from dcs import Mission
from dcs.country import Country
@ -33,7 +33,7 @@ from game.theater.theatergroundobject import (
GenericCarrierGroundObject,
LhaGroundObject, ShipGroundObject,
)
from .conflictgen import Conflict
from game.unitmap import UnitMap
from .radios import RadioFrequency, RadioRegistry
from .runways import RunwayData
from .tacan import TacanBand, TacanChannel, TacanRegistry
@ -52,11 +52,12 @@ class GenericGroundObjectGenerator:
Currently used only for SAM and missile (V1/V2) sites.
"""
def __init__(self, ground_object: TheaterGroundObject, country: Country,
game: Game, mission: Mission) -> None:
game: Game, mission: Mission, unit_map: UnitMap) -> None:
self.ground_object = ground_object
self.country = country
self.game = game
self.m = mission
self.unit_map = unit_map
def generate(self) -> None:
if self.game.position_culled(self.ground_object.position):
@ -89,9 +90,10 @@ class GenericGroundObjectGenerator:
self.enable_eplrs(vg, unit_type)
self.set_alarm_state(vg)
self._register_unit_group(vg)
@staticmethod
def enable_eplrs(group: Group, unit_type: UnitType) -> None:
def enable_eplrs(group: Group, unit_type: Type[UnitType]) -> None:
if hasattr(unit_type, 'eplrs'):
if unit_type.eplrs:
group.points[0].tasks.append(EPLRS(group.id))
@ -102,6 +104,9 @@ class GenericGroundObjectGenerator:
else:
group.points[0].tasks.append(OptAlarmState(1))
def _register_unit_group(self, group: Group) -> None:
self.unit_map.add_ground_object_units(self.ground_object, group)
class BuildingSiteGenerator(GenericGroundObjectGenerator):
"""Generator for building sites.
@ -133,16 +138,17 @@ class BuildingSiteGenerator(GenericGroundObjectGenerator):
def generate_vehicle_group(self, unit_type: UnitType) -> None:
if not self.ground_object.is_dead:
self.m.vehicle_group(
group = self.m.vehicle_group(
country=self.country,
name=self.ground_object.group_name,
_type=unit_type,
position=self.ground_object.position,
heading=self.ground_object.heading,
)
self._register_unit_group(group)
def generate_static(self, static_type: StaticType) -> None:
self.m.static_group(
group = self.m.static_group(
country=self.country,
name=self.ground_object.group_name,
_type=static_type,
@ -150,6 +156,11 @@ class BuildingSiteGenerator(GenericGroundObjectGenerator):
heading=self.ground_object.heading,
dead=self.ground_object.is_dead,
)
self._register_building(group)
def _register_building(self, building: StaticGroup) -> None:
assert isinstance(self.ground_object, BuildingGroundObject)
self.unit_map.add_building(self.ground_object, building)
class GenericCarrierGenerator(GenericGroundObjectGenerator):
@ -161,8 +172,8 @@ class GenericCarrierGenerator(GenericGroundObjectGenerator):
control_point: ControlPoint, country: Country, game: Game,
mission: Mission, radio_registry: RadioRegistry,
tacan_registry: TacanRegistry, icls_alloc: Iterator[int],
runways: Dict[str, RunwayData]) -> None:
super().__init__(ground_object, country, game, mission)
runways: Dict[str, RunwayData], unit_map: UnitMap) -> None:
super().__init__(ground_object, country, game, mission, unit_map)
self.ground_object = ground_object
self.control_point = control_point
self.radio_registry = radio_registry
@ -190,8 +201,9 @@ class GenericCarrierGenerator(GenericGroundObjectGenerator):
brc = self.steam_into_wind(ship_group)
self.activate_beacons(ship_group, tacan, tacan_callsign, icls)
self.add_runway_data(brc or 0, atc, tacan, tacan_callsign, icls)
self._register_unit_group(ship_group)
def get_carrier_type(self, group: Group) -> UnitType:
def get_carrier_type(self, group: Group) -> Type[UnitType]:
unit_type = unit_type_from_name(group.units[0].type)
if unit_type is None:
raise RuntimeError(
@ -328,8 +340,9 @@ class ShipObjectGenerator(GenericGroundObjectGenerator):
self.generate_group(group, unit_type)
def generate_group(self, group_def: Group, unit_type: UnitType):
group = self.m.ship_group(self.country, group_def.name, unit_type,
def generate_group(self, group_def: Group,
first_unit_type: Type[UnitType]) -> None:
group = self.m.ship_group(self.country, group_def.name, first_unit_type,
position=group_def.position,
heading=group_def.units[0].heading)
group.units[0].name = self.m.string(group_def.units[0].name)
@ -343,6 +356,7 @@ class ShipObjectGenerator(GenericGroundObjectGenerator):
ship.heading = unit.heading
group.add_unit(ship)
self.set_alarm_state(group)
self._register_unit_group(group)
class GroundObjectsGenerator:
@ -355,11 +369,13 @@ class GroundObjectsGenerator:
"""
def __init__(self, mission: Mission, game: Game,
radio_registry: RadioRegistry, tacan_registry: TacanRegistry):
radio_registry: RadioRegistry, tacan_registry: TacanRegistry,
unit_map: UnitMap) -> None:
self.m = mission
self.game = game
self.radio_registry = radio_registry
self.tacan_registry = tacan_registry
self.unit_map = unit_map
self.icls_alloc = iter(range(1, 21))
self.runways: Dict[str, RunwayData] = {}
@ -373,25 +389,26 @@ class GroundObjectsGenerator:
for ground_object in cp.ground_objects:
if isinstance(ground_object, BuildingGroundObject):
generator = BuildingSiteGenerator(ground_object, country,
self.game, self.m)
generator = BuildingSiteGenerator(
ground_object, country, self.game, self.m,
self.unit_map)
elif isinstance(ground_object, CarrierGroundObject):
generator = CarrierGenerator(ground_object, cp, country,
self.game, self.m,
self.radio_registry,
self.tacan_registry,
self.icls_alloc, self.runways)
generator = CarrierGenerator(
ground_object, cp, country, self.game, self.m,
self.radio_registry, self.tacan_registry,
self.icls_alloc, self.runways, self.unit_map)
elif isinstance(ground_object, LhaGroundObject):
generator = CarrierGenerator(ground_object, cp, country,
self.game, self.m,
self.radio_registry,
self.tacan_registry,
self.icls_alloc, self.runways)
generator = CarrierGenerator(
ground_object, cp, country, self.game, self.m,
self.radio_registry, self.tacan_registry,
self.icls_alloc, self.runways, self.unit_map)
elif isinstance(ground_object, ShipGroundObject):
generator = ShipObjectGenerator(ground_object, country,
self.game, self.m)
generator = ShipObjectGenerator(
ground_object, country, self.game, self.m,
self.unit_map)
else:
generator = GenericGroundObjectGenerator(ground_object,
country, self.game,
self.m)
generator = GenericGroundObjectGenerator(
ground_object, country, self.game, self.m,
self.unit_map)
generator.generate()

View File

@ -41,13 +41,6 @@ class QDebriefingWindow(QDialog):
self.layout.addWidget(header)
self.layout.addStretch()
# Result
#if self.gameEvent.is_successfull(self.debriefing):
# title = QLabel("<b>Operation end !</b>")
# title.setProperty("style", "title-success")
#else:
# title = QLabel("<b>Operation end !</b>")
# title.setProperty("style", "title-danger")
title = QLabel("<b>Casualty report</b>")
self.layout.addWidget(title)
@ -68,7 +61,7 @@ class QDebriefingWindow(QDialog):
logging.exception(
f"Issue adding {unit_type} to debriefing information")
front_line_losses = self.debriefing.front_line_losses.by_type(
front_line_losses = self.debriefing.front_line_losses_by_type(
player=True
)
for unit_type, count in front_line_losses.items():
@ -81,9 +74,10 @@ class QDebriefingWindow(QDialog):
logging.exception(
f"Issue adding {unit_type} to debriefing information")
for building, count in self.debriefing.player_dead_buildings_dict.items():
building_losses = self.debriefing.building_losses_by_type(player=True)
for building, count in building_losses.items():
try:
lostUnitsLayout.addWidget(QLabel(building, row, 0))
lostUnitsLayout.addWidget(QLabel(building), row, 0)
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
row += 1
except AttributeError:
@ -97,12 +91,6 @@ class QDebriefingWindow(QDialog):
enemylostUnitsLayout = QGridLayout()
enemylostUnits.setLayout(enemylostUnitsLayout)
#row = 0
#if self.debriefing.destroyed_objects:
# enemylostUnitsLayout.addWidget(QLabel("Ground assets"), row, 0)
# enemylostUnitsLayout.addWidget(QLabel("{}".format(len(self.debriefing.destroyed_objects))), row, 1)
# row += 1
enemy_air_losses = self.debriefing.air_losses.by_type(player=False)
for unit_type, count in enemy_air_losses.items():
try:
@ -114,7 +102,7 @@ class QDebriefingWindow(QDialog):
logging.exception(
f"Issue adding {unit_type} to debriefing information")
front_line_losses = self.debriefing.front_line_losses.by_type(
front_line_losses = self.debriefing.front_line_losses_by_type(
player=False
)
for unit_type, count in front_line_losses.items():
@ -124,7 +112,8 @@ class QDebriefingWindow(QDialog):
enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
row += 1
for building, count in self.debriefing.enemy_dead_buildings_dict.items():
building_losses = self.debriefing.building_losses_by_type(player=False)
for building, count in building_losses.items():
try:
enemylostUnitsLayout.addWidget(QLabel(building), row, 0)
enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
@ -135,6 +124,8 @@ class QDebriefingWindow(QDialog):
self.layout.addWidget(enemylostUnits)
# TODO: Display dead ground object units and runways.
# confirm button
okay = QPushButton("Okay")
okay.clicked.connect(self.close)

View File

@ -138,15 +138,21 @@ class QWaitingForMissionResultWindow(QDialog):
updateLayout.addWidget(
QLabel("<b>Front line units destroyed</b>"), 1, 0)
updateLayout.addWidget(
QLabel(str(len(debriefing.front_line_losses.losses))), 1, 1)
QLabel(str(len(list(debriefing.front_line_losses)))), 1, 1)
updateLayout.addWidget(
QLabel("<b>Other ground units destroyed</b>"), 2, 0)
updateLayout.addWidget(QLabel(str(len(debriefing.dead_units))), 2, 1)
updateLayout.addWidget(QLabel("<b>Base Capture Events</b>"), 3, 0)
updateLayout.addWidget(
QLabel(str(len(debriefing.base_capture_events))), 3, 1)
QLabel(str(len(list(debriefing.ground_object_losses)))), 2, 1)
updateLayout.addWidget(
QLabel("<b>Buildings destroyed</b>"), 3, 0)
updateLayout.addWidget(
QLabel(str(len(list(debriefing.building_losses)))), 3, 1)
updateLayout.addWidget(QLabel("<b>Base Capture Events</b>"), 4, 0)
updateLayout.addWidget(
QLabel(str(len(debriefing.base_capture_events))), 4, 1)
# Clear previous content of the window
for i in reversed(range(self.gridLayout.count())):