diff --git a/game/debriefing.py b/game/debriefing.py
index dd6a53b8..8d8fcb89 100644
--- a/game/debriefing.py
+++ b/game/debriefing.py
@@ -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."""
diff --git a/game/event/event.py b/game/event/event.py
index 706da279..eb2e53b7 100644
--- a/game/event/event.py
+++ b/game/event/event.py
@@ -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
diff --git a/game/operation/operation.py b/game/operation/operation.py
index a63f1f85..d2c46f58 100644
--- a/game/operation/operation.py
+++ b/game/operation/operation.py
@@ -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()
diff --git a/game/theater/base.py b/game/theater/base.py
index ba8a72f8..14b96ce2 100644
--- a/game/theater/base.py
+++ b/game/theater/base.py
@@ -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
diff --git a/game/theater/theatergroundobject.py b/game/theater/theatergroundobject.py
index be5c0a18..796c2aa9 100644
--- a/game/theater/theatergroundobject.py
+++ b/game/theater/theatergroundobject.py
@@ -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,
diff --git a/game/unitmap.py b/game/unitmap.py
index 9c6e20e6..b97fba8e 100644
--- a/game/unitmap.py
+++ b/game/unitmap.py
@@ -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)
diff --git a/gen/groundobjectsgen.py b/gen/groundobjectsgen.py
index e2c30846..26ae027e 100644
--- a/gen/groundobjectsgen.py
+++ b/gen/groundobjectsgen.py
@@ -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()
diff --git a/qt_ui/windows/QDebriefingWindow.py b/qt_ui/windows/QDebriefingWindow.py
index 4b52d585..6ef9ef81 100644
--- a/qt_ui/windows/QDebriefingWindow.py
+++ b/qt_ui/windows/QDebriefingWindow.py
@@ -41,13 +41,6 @@ class QDebriefingWindow(QDialog):
self.layout.addWidget(header)
self.layout.addStretch()
- # Result
- #if self.gameEvent.is_successfull(self.debriefing):
- # title = QLabel("Operation end !")
- # title.setProperty("style", "title-success")
- #else:
- # title = QLabel("Operation end !")
- # title.setProperty("style", "title-danger")
title = QLabel("Casualty report")
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)
diff --git a/qt_ui/windows/QWaitingForMissionResultWindow.py b/qt_ui/windows/QWaitingForMissionResultWindow.py
index f780091c..5551dda0 100644
--- a/qt_ui/windows/QWaitingForMissionResultWindow.py
+++ b/qt_ui/windows/QWaitingForMissionResultWindow.py
@@ -138,15 +138,21 @@ class QWaitingForMissionResultWindow(QDialog):
updateLayout.addWidget(
QLabel("Front line units destroyed"), 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("Other ground units destroyed"), 2, 0)
- updateLayout.addWidget(QLabel(str(len(debriefing.dead_units))), 2, 1)
-
- updateLayout.addWidget(QLabel("Base Capture Events"), 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("Buildings destroyed"), 3, 0)
+ updateLayout.addWidget(
+ QLabel(str(len(list(debriefing.building_losses)))), 3, 1)
+
+ updateLayout.addWidget(QLabel("Base Capture Events"), 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())):