Revert "Migrate buildings and TGOs to unit map."

Not registering kills correctly. It was in my limited testing, so need
to dig deeper.

https://github.com/Khopa/dcs_liberation/issues/494

This reverts commit 90697194a1a4ca67b53eb7b4056e4f7f5416ac58.
This commit is contained in:
Dan Albert 2020-12-04 23:57:58 -08:00
parent ccb41829c9
commit 72ac8ca872
9 changed files with 245 additions and 237 deletions

View File

@ -6,22 +6,14 @@ import os
import threading import threading
import time import time
from collections import defaultdict from collections import defaultdict
from dataclasses import dataclass, field from dataclasses import dataclass
from typing import ( from typing import Any, Callable, Dict, List, Type, TYPE_CHECKING
Any,
Callable,
Dict,
Iterator,
List,
Type,
TYPE_CHECKING,
)
from dcs.unittype import FlyingType, UnitType from dcs.unittype import FlyingType, UnitType
from game import db from game import db
from game.theater import Airfield, ControlPoint from game.theater import Airfield, ControlPoint, TheaterGroundObject
from game.unitmap import Building, FrontLineUnit, GroundObjectUnit, UnitMap from game.unitmap import UnitMap
from gen.flights.flight import Flight from gen.flights.flight import Flight
if TYPE_CHECKING: if TYPE_CHECKING:
@ -30,6 +22,12 @@ if TYPE_CHECKING:
DEBRIEFING_LOG_EXTENSION = "log" DEBRIEFING_LOG_EXTENSION = "log"
@dataclass(frozen=True)
class DebriefingDeadUnitInfo:
player_unit: bool
type: Type[UnitType]
@dataclass(frozen=True) @dataclass(frozen=True)
class DebriefingDeadAircraftInfo: class DebriefingDeadAircraftInfo:
#: The Flight that resulted in the generated unit. #: The Flight that resulted in the generated unit.
@ -40,6 +38,27 @@ class DebriefingDeadAircraftInfo:
return self.flight.departure.captured 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) @dataclass(frozen=True)
class AirLosses: class AirLosses:
losses: List[DebriefingDeadAircraftInfo] losses: List[DebriefingDeadAircraftInfo]
@ -61,12 +80,18 @@ class AirLosses:
return flight.count - losses return flight.count - losses
@dataclass @dataclass(frozen=True)
class GroundLosses: class FrontLineLosses:
front_line: List[FrontLineUnit] = field(default_factory=list) losses: List[DebriefingDeadFrontLineUnitInfo]
ground_objects: List[GroundObjectUnit] = field(default_factory=list)
buildings: List[Building] = field(default_factory=list) def by_type(self, player: bool) -> Dict[Type[UnitType], int]:
airfields: List[Airfield] = field(default_factory=list) 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(frozen=True) @dataclass(frozen=True)
@ -106,51 +131,80 @@ class Debriefing:
self.game = game self.game = game
self.unit_map = unit_map 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.player_country_id = db.country_id_from_name(game.player_country)
self.enemy_country_id = db.country_id_from_name(game.enemy_country) self.enemy_country_id = db.country_id_from_name(game.enemy_country)
self.air_losses = self.dead_aircraft() self.air_losses = self.dead_aircraft()
self.ground_losses = self.dead_ground_units() 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] = []
@property for unit_name in self.state_data.killed_ground_units:
def front_line_losses(self) -> Iterator[FrontLineUnit]: for cp in game.theater.controlpoints:
yield from self.ground_losses.front_line if cp.captured:
country = self.player_country_id
else:
country = self.enemy_country_id
player_unit = (country == self.player_country_id)
@property for ground_object in cp.ground_objects:
def ground_object_losses(self) -> Iterator[GroundObjectUnit]: # TODO: This seems to destroy an arbitrary building?
yield from self.ground_losses.ground_objects 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 self.player_dead_units = [a for a in self.dead_units if a.player_unit]
def building_losses(self) -> Iterator[Building]: self.enemy_dead_units = [a for a in self.dead_units if not a.player_unit]
yield from self.ground_losses.buildings 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 self.player_dead_units_dict: Dict[Type[UnitType], int] = defaultdict(int)
def damaged_runways(self) -> Iterator[Airfield]: for a in self.player_dead_units:
yield from self.ground_losses.airfields self.player_dead_units_dict[a.type] += 1
def casualty_count(self, control_point: ControlPoint) -> int: self.enemy_dead_units_dict: Dict[Type[UnitType], int] = defaultdict(int)
return len( for a in self.enemy_dead_units:
[x for x in self.front_line_losses if x.origin == control_point] self.enemy_dead_units_dict[a.type] += 1
)
def front_line_losses_by_type( self.player_dead_buildings_dict: Dict[str, int] = defaultdict(int)
self, player: bool) -> Dict[Type[UnitType], int]: for b in self.player_dead_buildings:
losses_by_type: Dict[Type[UnitType], int] = defaultdict(int) self.player_dead_buildings_dict[b.ground_object.dcs_identifier] += 1
for loss in self.ground_losses.front_line:
if loss.origin.captured != player:
continue
losses_by_type[loss.unit_type] += 1 self.enemy_dead_buildings_dict: Dict[str, int] = defaultdict(int)
return losses_by_type for b in self.enemy_dead_buildings:
self.enemy_dead_buildings_dict[b.ground_object.dcs_identifier] += 1
def building_losses_by_type(self, player: bool) -> Dict[str, int]: logging.info("--------------------------------")
losses_by_type: Dict[str, int] = defaultdict(int) logging.info("Debriefing pre process results :")
for loss in self.ground_losses.buildings: logging.info("--------------------------------")
if loss.ground_object.control_point.captured != player: logging.info(self.air_losses)
continue logging.info(self.front_line_losses)
logging.info(self.player_dead_units_dict)
losses_by_type[loss.ground_object.dcs_identifier] += 1 logging.info(self.enemy_dead_units_dict)
return losses_by_type logging.info(self.player_dead_buildings_dict)
logging.info(self.enemy_dead_buildings_dict)
def dead_aircraft(self) -> AirLosses: def dead_aircraft(self) -> AirLosses:
losses = [] losses = []
@ -162,38 +216,30 @@ class Debriefing:
losses.append(DebriefingDeadAircraftInfo(flight)) losses.append(DebriefingDeadAircraftInfo(flight))
return AirLosses(losses) return AirLosses(losses)
def dead_ground_units(self) -> GroundLosses: def dead_front_line_units(self) -> FrontLineLosses:
losses = GroundLosses() losses = []
for unit_name in self.state_data.killed_ground_units: for unit_name in self.state_data.killed_ground_units:
front_line_unit = self.unit_map.front_line_unit(unit_name) unit = self.unit_map.front_line_unit(unit_name)
if front_line_unit is not None: if unit is None:
losses.front_line.append(front_line_unit) # Killed "ground units" might also be runways or TGO units, so
# no need to log an error.
continue continue
losses.append(
DebriefingDeadFrontLineUnitInfo(unit.unit_type, unit.origin))
return FrontLineLosses(losses)
ground_object_unit = self.unit_map.ground_object_unit(unit_name) def find_damaged_runways(self) -> List[Airfield]:
if ground_object_unit is not None: losses = []
losses.ground_objects.append(ground_object_unit) for name in self.state_data.killed_ground_units:
airfield = self.unit_map.airfield(name)
if airfield is None:
continue 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 return losses
def _is_airfield(self, unit_name: str) -> bool:
return self.unit_map.airfield(unit_name) is not None
@property @property
def base_capture_events(self): def base_capture_events(self):
"""Keeps only the last instance of a base capture event for each base ID.""" """Keeps only the last instance of a base capture event for each base ID."""

View File

@ -2,20 +2,21 @@ from __future__ import annotations
import logging import logging
import math import math
from typing import Dict, List, TYPE_CHECKING, Type from collections import defaultdict
from typing import Dict, List, Optional, TYPE_CHECKING, Type
from dcs.mapping import Point from dcs.mapping import Point
from dcs.task import Task from dcs.task import Task
from dcs.unittype import UnitType from dcs.unittype import UnitType
from game import persistency from game import db, persistency
from game.debriefing import AirLosses, Debriefing from game.debriefing import AirLosses, Debriefing
from game.infos.information import Information from game.infos.information import Information
from game.operation.operation import Operation
from game.theater import ControlPoint from game.theater import ControlPoint
from gen import AirTaskingOrder from gen import AirTaskingOrder
from gen.ground_forces.combat_stance import CombatStance from gen.ground_forces.combat_stance import CombatStance
from ..unitmap import UnitMap from ..unitmap import UnitMap
from game.operation.operation import Operation
if TYPE_CHECKING: if TYPE_CHECKING:
from ..game import Game from ..game import Game
@ -129,10 +130,12 @@ class Event:
cp.base.aircraft[aircraft] -= 1 cp.base.aircraft[aircraft] -= 1
@staticmethod @staticmethod
def commit_front_line_losses(debriefing: Debriefing) -> None: def commit_front_line_losses(debriefing: Debriefing) -> Dict[int, int]:
for loss in debriefing.front_line_losses: killed_unit_count_by_cp: Dict[int, int] = defaultdict(int)
for loss in debriefing.front_line_losses.losses:
unit_type = loss.unit_type unit_type = loss.unit_type
control_point = loss.origin control_point = loss.control_point
killed_unit_count_by_cp[control_point.id] += 1
available = control_point.base.total_units_of_type(unit_type) available = control_point.base.total_units_of_type(unit_type)
if available <= 0: if available <= 0:
logging.error( logging.error(
@ -142,41 +145,64 @@ class Event:
logging.info(f"{unit_type} destroyed from {control_point}") logging.info(f"{unit_type} destroyed from {control_point}")
control_point.base.armor[unit_type] -= 1 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): def commit(self, debriefing: Debriefing):
logging.info("Committing mission results") logging.info("Committing mission results")
for damaged_runway in debriefing.damaged_runways:
damaged_runway.damage_runway()
self.commit_air_losses(debriefing) self.commit_air_losses(debriefing)
self.commit_front_line_losses(debriefing) killed_unit_count_by_cp = self.commit_front_line_losses(debriefing)
self.commit_ground_object_losses(debriefing)
self.commit_building_losses(debriefing) # ------------------------------
self.commit_damaged_runways(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)
# ------------------------------ # ------------------------------
# Captured bases # Captured bases
@ -231,8 +257,8 @@ class Event:
delta = 0.0 delta = 0.0
player_won = True player_won = True
ally_casualties = debriefing.casualty_count(cp) ally_casualties = killed_unit_count_by_cp[cp.id]
enemy_casualties = debriefing.casualty_count(enemy_cp) enemy_casualties = killed_unit_count_by_cp[enemy_cp.id]
ally_units_alive = cp.base.total_armor ally_units_alive = cp.base.total_armor
enemy_units_alive = enemy_cp.base.total_armor enemy_units_alive = enemy_cp.base.total_armor

View File

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

View File

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

View File

@ -136,10 +136,6 @@ class TheaterGroundObject(MissionTarget):
] ]
yield from super().mission_types(for_player) 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): class BuildingGroundObject(TheaterGroundObject):
def __init__(self, name: str, category: str, group_id: int, object_id: int, def __init__(self, name: str, category: str, group_id: int, object_id: int,

View File

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

View File

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

View File

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