mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Add cargo ships to the sim, track kills.
Not targetable yet. https://github.com/Khopa/dcs_liberation/issues/826
This commit is contained in:
parent
ba8fafcc95
commit
7e40d58d04
@ -4,7 +4,7 @@ Saves from 2.5 are not compatible with 3.0.
|
||||
|
||||
## Features/Improvements
|
||||
|
||||
* **[Campaign]** Ground units can now be transferred by road and airlift. See https://github.com/Khopa/dcs_liberation/wiki/Unit-Transfers for more information.
|
||||
* **[Campaign]** Ground units can now be transferred by road, airlift, and cargo ship. See https://github.com/Khopa/dcs_liberation/wiki/Unit-Transfers for more information.
|
||||
* **[Campaign]** Ground units can no longer be sold. To move units to a new location, transfer them.
|
||||
* **[Campaign]** Ground units must now be recruited at a base with a factory and transferred to their destination. When buying units in the UI, the purchase will automatically be fulfilled at the closest factory and a transfer will be created on the next turn. This feature is off by default.
|
||||
* **[UI]** Campaigns generated for an older or newer version of the game will now be marked as incompatible. They can still be played, but bugs may be present.
|
||||
|
||||
@ -22,6 +22,7 @@ from dcs.unittype import FlyingType, UnitType
|
||||
|
||||
from game import db
|
||||
from game.theater import Airfield, ControlPoint
|
||||
from game.transfers import CargoShip
|
||||
from game.unitmap import (
|
||||
AirliftUnit,
|
||||
Building,
|
||||
@ -70,6 +71,9 @@ class GroundLosses:
|
||||
player_convoy: List[ConvoyUnit] = field(default_factory=list)
|
||||
enemy_convoy: List[ConvoyUnit] = field(default_factory=list)
|
||||
|
||||
player_cargo_ships: List[CargoShip] = field(default_factory=list)
|
||||
enemy_cargo_ships: List[CargoShip] = field(default_factory=list)
|
||||
|
||||
player_airlifts: List[AirliftUnit] = field(default_factory=list)
|
||||
enemy_airlifts: List[AirliftUnit] = field(default_factory=list)
|
||||
|
||||
@ -138,6 +142,11 @@ class Debriefing:
|
||||
yield from self.ground_losses.player_convoy
|
||||
yield from self.ground_losses.enemy_convoy
|
||||
|
||||
@property
|
||||
def cargo_ship_losses(self) -> Iterator[CargoShip]:
|
||||
yield from self.ground_losses.player_cargo_ships
|
||||
yield from self.ground_losses.enemy_cargo_ships
|
||||
|
||||
@property
|
||||
def airlift_losses(self) -> Iterator[AirliftUnit]:
|
||||
yield from self.ground_losses.player_airlifts
|
||||
@ -181,6 +190,17 @@ class Debriefing:
|
||||
losses_by_type[loss.unit_type] += 1
|
||||
return losses_by_type
|
||||
|
||||
def cargo_ship_losses_by_type(self, player: bool) -> Dict[Type[UnitType], int]:
|
||||
losses_by_type: Dict[Type[UnitType], int] = defaultdict(int)
|
||||
if player:
|
||||
ships = self.ground_losses.player_cargo_ships
|
||||
else:
|
||||
ships = self.ground_losses.enemy_cargo_ships
|
||||
for ship in ships:
|
||||
for unit_type, count in ship.units.items():
|
||||
losses_by_type[unit_type] += count
|
||||
return losses_by_type
|
||||
|
||||
def airlift_losses_by_type(self, player: bool) -> Dict[Type[UnitType], int]:
|
||||
losses_by_type: Dict[Type[UnitType], int] = defaultdict(int)
|
||||
if player:
|
||||
@ -237,6 +257,14 @@ class Debriefing:
|
||||
losses.enemy_convoy.append(convoy_unit)
|
||||
continue
|
||||
|
||||
cargo_ship = self.unit_map.cargo_ship(unit_name)
|
||||
if cargo_ship is not None:
|
||||
if cargo_ship.player_owned:
|
||||
losses.player_cargo_ships.append(cargo_ship)
|
||||
else:
|
||||
losses.enemy_cargo_ships.append(cargo_ship)
|
||||
continue
|
||||
|
||||
ground_object_unit = self.unit_map.ground_object_unit(unit_name)
|
||||
if ground_object_unit is not None:
|
||||
if ground_object_unit.ground_object.control_point.captured:
|
||||
|
||||
@ -169,6 +169,15 @@ class Event:
|
||||
logging.info(f"{unit_type} destroyed in {convoy_name}")
|
||||
convoy.kill_unit(unit_type)
|
||||
|
||||
@staticmethod
|
||||
def commit_cargo_ship_losses(debriefing: Debriefing) -> None:
|
||||
for ship in debriefing.cargo_ship_losses:
|
||||
logging.info(
|
||||
f"All units destroyed in cargo ship from {ship.origin} to "
|
||||
f"{ship.destination}."
|
||||
)
|
||||
ship.kill_all()
|
||||
|
||||
@staticmethod
|
||||
def commit_airlift_losses(debriefing: Debriefing) -> None:
|
||||
for loss in debriefing.airlift_losses:
|
||||
|
||||
@ -23,7 +23,8 @@ from gen.airsupportgen import AirSupport, AirSupportConflictGenerator
|
||||
from gen.armor import GroundConflictGenerator, JtacInfo
|
||||
from gen.beacons import load_beacons_for_terrain
|
||||
from gen.briefinggen import BriefingGenerator, MissionInfoGenerator
|
||||
from gen.convoys import ConvoyGenerator
|
||||
from gen.cargoshipgen import CargoShipGenerator
|
||||
from gen.convoygen import ConvoyGenerator
|
||||
from gen.environmentgen import EnvironmentGenerator
|
||||
from gen.forcedoptionsgen import ForcedOptionsGenerator
|
||||
from gen.groundobjectsgen import GroundObjectsGenerator
|
||||
@ -304,7 +305,7 @@ class Operation:
|
||||
# Set mission time and weather conditions.
|
||||
EnvironmentGenerator(cls.current_mission, cls.game.conditions).generate()
|
||||
cls._generate_ground_units()
|
||||
cls._generate_convoys()
|
||||
cls._generate_transports()
|
||||
cls._generate_destroyed_units()
|
||||
cls._generate_air_units()
|
||||
cls.assign_channels_to_flights(
|
||||
@ -426,9 +427,10 @@ class Operation:
|
||||
cls.jtacs.extend(ground_conflict_gen.jtacs)
|
||||
|
||||
@classmethod
|
||||
def _generate_convoys(cls) -> None:
|
||||
def _generate_transports(cls) -> None:
|
||||
"""Generates convoys for unit transfers by road."""
|
||||
ConvoyGenerator(cls.current_mission, cls.game, cls.unit_map).generate()
|
||||
CargoShipGenerator(cls.current_mission, cls.game, cls.unit_map).generate()
|
||||
|
||||
@classmethod
|
||||
def reset_naming_ids(cls):
|
||||
|
||||
@ -4,7 +4,7 @@ import logging
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
from functools import singledispatchmethod
|
||||
from typing import Dict, Iterator, List, Optional, TYPE_CHECKING, Type
|
||||
from typing import Dict, Generic, Iterator, List, Optional, TYPE_CHECKING, Type, TypeVar
|
||||
|
||||
from dcs.mapping import Point
|
||||
from dcs.unittype import FlyingType, VehicleType
|
||||
@ -271,6 +271,10 @@ class MultiGroupTransport(MissionTarget, Transport):
|
||||
pass
|
||||
raise KeyError
|
||||
|
||||
def kill_all(self) -> None:
|
||||
for transfer in self.transfers:
|
||||
transfer.kill_all()
|
||||
|
||||
def disband(self) -> None:
|
||||
for transfer in list(self.transfers):
|
||||
self.remove_units(transfer)
|
||||
@ -298,14 +302,6 @@ class MultiGroupTransport(MissionTarget, Transport):
|
||||
def description(self) -> str:
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def route_start(self) -> Point:
|
||||
raise NotImplementedError
|
||||
|
||||
@property
|
||||
def route_end(self) -> Point:
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class Convoy(MultiGroupTransport):
|
||||
def __init__(self, origin: ControlPoint, destination: ControlPoint) -> None:
|
||||
@ -345,12 +341,8 @@ class CargoShip(MultiGroupTransport):
|
||||
yield from super().mission_types(for_player)
|
||||
|
||||
@property
|
||||
def route_start(self) -> Point:
|
||||
return self.origin.shipping_lanes[self.destination][0]
|
||||
|
||||
@property
|
||||
def route_end(self) -> Point:
|
||||
return self.destination.shipping_lanes[self.origin][-1]
|
||||
def route(self) -> List[Point]:
|
||||
return self.origin.shipping_lanes[self.destination]
|
||||
|
||||
def description(self) -> str:
|
||||
return f"On a ship to {self.destination}"
|
||||
@ -359,16 +351,19 @@ class CargoShip(MultiGroupTransport):
|
||||
return None
|
||||
|
||||
|
||||
class TransportMap:
|
||||
TransportType = TypeVar("TransportType", bound=MultiGroupTransport)
|
||||
|
||||
|
||||
class TransportMap(Generic[TransportType]):
|
||||
def __init__(self) -> None:
|
||||
# Dict of origin -> destination -> transport.
|
||||
self.transports: Dict[
|
||||
ControlPoint, Dict[ControlPoint, MultiGroupTransport]
|
||||
ControlPoint, Dict[ControlPoint, TransportType]
|
||||
] = defaultdict(dict)
|
||||
|
||||
def create_transport(
|
||||
self, origin: ControlPoint, destination: ControlPoint
|
||||
) -> MultiGroupTransport:
|
||||
) -> TransportType:
|
||||
raise NotImplementedError
|
||||
|
||||
def transport_exists(self, origin: ControlPoint, destination: ControlPoint) -> bool:
|
||||
@ -376,27 +371,27 @@ class TransportMap:
|
||||
|
||||
def find_transport(
|
||||
self, origin: ControlPoint, destination: ControlPoint
|
||||
) -> Optional[MultiGroupTransport]:
|
||||
) -> Optional[TransportType]:
|
||||
return self.transports[origin].get(destination)
|
||||
|
||||
def find_or_create_transport(
|
||||
self, origin: ControlPoint, destination: ControlPoint
|
||||
) -> MultiGroupTransport:
|
||||
) -> TransportType:
|
||||
transport = self.find_transport(origin, destination)
|
||||
if transport is None:
|
||||
transport = self.create_transport(origin, destination)
|
||||
self.transports[origin][destination] = transport
|
||||
return transport
|
||||
|
||||
def departing_from(self, origin: ControlPoint) -> Iterator[MultiGroupTransport]:
|
||||
def departing_from(self, origin: ControlPoint) -> Iterator[TransportType]:
|
||||
yield from self.transports[origin].values()
|
||||
|
||||
def travelling_to(self, destination: ControlPoint) -> Iterator[MultiGroupTransport]:
|
||||
def travelling_to(self, destination: ControlPoint) -> Iterator[TransportType]:
|
||||
for destination_dict in self.transports.values():
|
||||
if destination in destination_dict:
|
||||
yield destination_dict[destination]
|
||||
|
||||
def disband_transport(self, transport: MultiGroupTransport) -> None:
|
||||
def disband_transport(self, transport: TransportType) -> None:
|
||||
transport.disband()
|
||||
del self.transports[transport.origin][transport.destination]
|
||||
|
||||
@ -416,7 +411,7 @@ class TransportMap:
|
||||
next_stop = self.next_stop_for(transfer)
|
||||
self.find_or_create_transport(transfer.position, next_stop).add_units(transfer)
|
||||
|
||||
def remove(self, transport: MultiGroupTransport, transfer: TransferOrder) -> None:
|
||||
def remove(self, transport: TransportType, transfer: TransferOrder) -> None:
|
||||
transport.remove_units(transfer)
|
||||
if not transport.transfers:
|
||||
self.disband_transport(transport)
|
||||
@ -425,7 +420,7 @@ class TransportMap:
|
||||
for transport in list(self):
|
||||
self.disband_transport(transport)
|
||||
|
||||
def __iter__(self) -> Iterator[MultiGroupTransport]:
|
||||
def __iter__(self) -> Iterator[TransportType]:
|
||||
for destination_dict in self.transports.values():
|
||||
yield from destination_dict.values()
|
||||
|
||||
|
||||
@ -9,7 +9,7 @@ from dcs.unittype import VehicleType
|
||||
from game import db
|
||||
from game.theater import Airfield, ControlPoint, TheaterGroundObject
|
||||
from game.theater.theatergroundobject import BuildingGroundObject
|
||||
from game.transfers import MultiGroupTransport, TransferOrder
|
||||
from game.transfers import CargoShip, Convoy, TransferOrder
|
||||
from gen.flights.flight import Flight
|
||||
|
||||
|
||||
@ -29,7 +29,7 @@ class GroundObjectUnit:
|
||||
@dataclass(frozen=True)
|
||||
class ConvoyUnit:
|
||||
unit_type: Type[VehicleType]
|
||||
convoy: MultiGroupTransport
|
||||
convoy: Convoy
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@ -51,6 +51,7 @@ class UnitMap:
|
||||
self.ground_object_units: Dict[str, GroundObjectUnit] = {}
|
||||
self.buildings: Dict[str, Building] = {}
|
||||
self.convoys: Dict[str, ConvoyUnit] = {}
|
||||
self.cargo_ships: Dict[str, CargoShip] = {}
|
||||
self.airlifts: Dict[str, AirliftUnit] = {}
|
||||
|
||||
def add_aircraft(self, group: FlyingGroup, flight: Flight) -> None:
|
||||
@ -130,7 +131,7 @@ class UnitMap:
|
||||
def ground_object_unit(self, name: str) -> Optional[GroundObjectUnit]:
|
||||
return self.ground_object_units.get(name, None)
|
||||
|
||||
def add_convoy_units(self, group: Group, convoy: MultiGroupTransport) -> None:
|
||||
def add_convoy_units(self, group: Group, convoy: Convoy) -> None:
|
||||
for unit in group.units:
|
||||
# The actual name is a String (the pydcs translatable string), which
|
||||
# doesn't define __eq__.
|
||||
@ -149,6 +150,23 @@ class UnitMap:
|
||||
def convoy_unit(self, name: str) -> Optional[ConvoyUnit]:
|
||||
return self.convoys.get(name, None)
|
||||
|
||||
def add_cargo_ship(self, group: Group, ship: CargoShip) -> None:
|
||||
if len(group.units) > 1:
|
||||
# Cargo ship "groups" are single units. Killing the one ship kills the whole
|
||||
# transfer. If we ever want to add escorts or create multiple cargo ships in
|
||||
# a convoy of ships that logic needs to change.
|
||||
raise ValueError("Expected cargo ship to be a single unit group.")
|
||||
unit = group.units[0]
|
||||
# The actual name is a String (the pydcs translatable string), which
|
||||
# doesn't define __eq__.
|
||||
name = str(unit.name)
|
||||
if name in self.cargo_ships:
|
||||
raise RuntimeError(f"Duplicate cargo ship: {name}")
|
||||
self.cargo_ships[name] = ship
|
||||
|
||||
def cargo_ship(self, name: str) -> Optional[CargoShip]:
|
||||
return self.cargo_ships.get(name, None)
|
||||
|
||||
def add_airlift_units(self, group: FlyingGroup, transfer: TransferOrder) -> None:
|
||||
for transport, cargo_type in zip(group.units, transfer.iter_units()):
|
||||
# The actual name is a String (the pydcs translatable string), which
|
||||
|
||||
47
gen/cargoshipgen.py
Normal file
47
gen/cargoshipgen.py
Normal file
@ -0,0 +1,47 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import itertools
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
from dcs import Mission
|
||||
from dcs.ships import Bulker_Handy_Wind
|
||||
from dcs.unitgroup import ShipGroup
|
||||
|
||||
from game.transfers import CargoShip
|
||||
from game.unitmap import UnitMap
|
||||
from game.utils import knots
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from game import Game
|
||||
|
||||
|
||||
class CargoShipGenerator:
|
||||
def __init__(self, mission: Mission, game: Game, unit_map: UnitMap) -> None:
|
||||
self.mission = mission
|
||||
self.game = game
|
||||
self.unit_map = unit_map
|
||||
self.count = itertools.count()
|
||||
|
||||
def generate(self) -> None:
|
||||
# Reset the count to make generation deterministic.
|
||||
for ship in self.game.transfers.cargo_ships:
|
||||
self.generate_cargo_ship(ship)
|
||||
|
||||
def generate_cargo_ship(self, ship: CargoShip) -> ShipGroup:
|
||||
country = self.mission.country(
|
||||
self.game.player_country if ship.player_owned else self.game.enemy_country
|
||||
)
|
||||
waypoints = ship.route
|
||||
group = self.mission.ship_group(
|
||||
country,
|
||||
ship.name,
|
||||
Bulker_Handy_Wind,
|
||||
position=waypoints[0],
|
||||
group_size=1,
|
||||
)
|
||||
for waypoint in waypoints[1:]:
|
||||
# 12 knots is very slow but it's also nearly the max allowed by DCS for this
|
||||
# type of ship.
|
||||
group.add_waypoint(waypoint, speed=knots(12).kph)
|
||||
self.unit_map.add_cargo_ship(group, ship)
|
||||
return group
|
||||
@ -10,7 +10,7 @@ from dcs.unit import Vehicle
|
||||
from dcs.unitgroup import VehicleGroup
|
||||
from dcs.unittype import VehicleType
|
||||
|
||||
from game.transfers import MultiGroupTransport
|
||||
from game.transfers import Convoy
|
||||
from game.unitmap import UnitMap
|
||||
from game.utils import kph
|
||||
|
||||
@ -30,7 +30,7 @@ class ConvoyGenerator:
|
||||
for convoy in self.game.transfers.convoys:
|
||||
self.generate_convoy(convoy)
|
||||
|
||||
def generate_convoy(self, convoy: MultiGroupTransport) -> VehicleGroup:
|
||||
def generate_convoy(self, convoy: Convoy) -> VehicleGroup:
|
||||
group = self._create_mixed_unit_group(
|
||||
convoy.name,
|
||||
convoy.route_start,
|
||||
@ -1,4 +1,5 @@
|
||||
import logging
|
||||
from typing import Callable, Dict, TypeVar
|
||||
|
||||
from PySide2.QtGui import QIcon, QPixmap
|
||||
from PySide2.QtWidgets import (
|
||||
@ -14,6 +15,57 @@ from game import db
|
||||
from game.debriefing import Debriefing
|
||||
|
||||
|
||||
T = TypeVar("T")
|
||||
|
||||
|
||||
class LossGrid(QGridLayout):
|
||||
def __init__(self, debriefing: Debriefing, player: bool) -> None:
|
||||
super().__init__()
|
||||
|
||||
if player:
|
||||
country = debriefing.player_country
|
||||
else:
|
||||
country = debriefing.enemy_country
|
||||
|
||||
self.add_loss_rows(
|
||||
debriefing.air_losses.by_type(player),
|
||||
lambda u: db.unit_get_expanded_info(country, u, "name"),
|
||||
)
|
||||
self.add_loss_rows(
|
||||
debriefing.front_line_losses_by_type(player),
|
||||
lambda u: db.unit_type_name(u),
|
||||
)
|
||||
self.add_loss_rows(
|
||||
debriefing.convoy_losses_by_type(player),
|
||||
lambda u: f"{db.unit_type_name(u)} from convoy",
|
||||
)
|
||||
self.add_loss_rows(
|
||||
debriefing.cargo_ship_losses_by_type(player),
|
||||
lambda u: f"{db.unit_type_name(u)} from cargo ship",
|
||||
)
|
||||
self.add_loss_rows(
|
||||
debriefing.airlift_losses_by_type(player),
|
||||
lambda u: f"{db.unit_type_name(u)} from airlift",
|
||||
)
|
||||
self.add_loss_rows(
|
||||
debriefing.building_losses_by_type(player),
|
||||
lambda u: u,
|
||||
)
|
||||
|
||||
# TODO: Display dead ground object units and runways.
|
||||
|
||||
def add_loss_rows(self, losses: Dict[T, int], make_name: Callable[[T], str]):
|
||||
for unit_type, count in losses.items():
|
||||
row = self.rowCount()
|
||||
try:
|
||||
name = make_name(unit_type)
|
||||
except AttributeError:
|
||||
logging.exception(f"Could not make unit name for {unit_type}")
|
||||
name = unit_type.id
|
||||
self.addWidget(QLabel(name), row, 0)
|
||||
self.addWidget(QLabel(str(count)), row, 1)
|
||||
|
||||
|
||||
class QDebriefingWindow(QDialog):
|
||||
def __init__(self, debriefing: Debriefing):
|
||||
super(QDebriefingWindow, self).__init__()
|
||||
@ -24,155 +76,27 @@ class QDebriefingWindow(QDialog):
|
||||
self.setMinimumSize(300, 200)
|
||||
self.setWindowIcon(QIcon("./resources/icon.png"))
|
||||
|
||||
self.initUI()
|
||||
|
||||
def initUI(self):
|
||||
|
||||
self.layout = QVBoxLayout()
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
header = QLabel(self)
|
||||
header.setGeometry(0, 0, 655, 106)
|
||||
pixmap = QPixmap("./resources/ui/debriefing.png")
|
||||
header.setPixmap(pixmap)
|
||||
self.layout.addWidget(header)
|
||||
self.layout.addStretch()
|
||||
layout.addWidget(header)
|
||||
layout.addStretch()
|
||||
|
||||
title = QLabel("<b>Casualty report</b>")
|
||||
self.layout.addWidget(title)
|
||||
layout.addWidget(title)
|
||||
|
||||
# Player lost units
|
||||
lostUnits = QGroupBox(f"{self.debriefing.player_country}'s lost units:")
|
||||
lostUnitsLayout = QGridLayout()
|
||||
lostUnits.setLayout(lostUnitsLayout)
|
||||
player_lost_units = QGroupBox(f"{self.debriefing.player_country}'s lost units:")
|
||||
player_lost_units.setLayout(LossGrid(debriefing, player=True))
|
||||
layout.addWidget(player_lost_units)
|
||||
|
||||
row = 0
|
||||
player_air_losses = self.debriefing.air_losses.by_type(player=True)
|
||||
for unit_type, count in player_air_losses.items():
|
||||
try:
|
||||
lostUnitsLayout.addWidget(
|
||||
QLabel(
|
||||
db.unit_get_expanded_info(
|
||||
self.debriefing.player_country, unit_type, "name"
|
||||
)
|
||||
),
|
||||
row,
|
||||
0,
|
||||
)
|
||||
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
||||
row += 1
|
||||
except AttributeError:
|
||||
logging.exception(f"Issue adding {unit_type} to debriefing information")
|
||||
enemy_lost_units = QGroupBox(f"{self.debriefing.enemy_country}'s lost units:")
|
||||
enemy_lost_units.setLayout(LossGrid(debriefing, player=False))
|
||||
layout.addWidget(enemy_lost_units)
|
||||
|
||||
front_line_losses = self.debriefing.front_line_losses_by_type(player=True)
|
||||
for unit_type, count in front_line_losses.items():
|
||||
try:
|
||||
lostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0)
|
||||
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
||||
row += 1
|
||||
except AttributeError:
|
||||
logging.exception(f"Issue adding {unit_type} to debriefing information")
|
||||
|
||||
convoy_losses = self.debriefing.convoy_losses_by_type(player=True)
|
||||
for unit_type, count in convoy_losses.items():
|
||||
try:
|
||||
lostUnitsLayout.addWidget(
|
||||
QLabel(f"{db.unit_type_name(unit_type)} from convoy"), row, 0
|
||||
)
|
||||
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
||||
row += 1
|
||||
except AttributeError:
|
||||
logging.exception(f"Issue adding {unit_type} to debriefing information")
|
||||
|
||||
airlift_losses = self.debriefing.airlift_losses_by_type(player=True)
|
||||
for unit_type, count in airlift_losses.items():
|
||||
try:
|
||||
lostUnitsLayout.addWidget(
|
||||
QLabel(f"{db.unit_type_name(unit_type)} from airlift"), row, 0
|
||||
)
|
||||
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
||||
row += 1
|
||||
except AttributeError:
|
||||
logging.exception(f"Issue adding {unit_type} to debriefing information")
|
||||
|
||||
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(str(count)), row, 1)
|
||||
row += 1
|
||||
except AttributeError:
|
||||
logging.exception(f"Issue adding {building} to debriefing information")
|
||||
|
||||
self.layout.addWidget(lostUnits)
|
||||
|
||||
# Enemy lost units
|
||||
enemylostUnits = QGroupBox(f"{self.debriefing.enemy_country}'s lost units:")
|
||||
enemylostUnitsLayout = QGridLayout()
|
||||
enemylostUnits.setLayout(enemylostUnitsLayout)
|
||||
|
||||
enemy_air_losses = self.debriefing.air_losses.by_type(player=False)
|
||||
for unit_type, count in enemy_air_losses.items():
|
||||
try:
|
||||
enemylostUnitsLayout.addWidget(
|
||||
QLabel(
|
||||
db.unit_get_expanded_info(
|
||||
self.debriefing.enemy_country, unit_type, "name"
|
||||
)
|
||||
),
|
||||
row,
|
||||
0,
|
||||
)
|
||||
enemylostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
||||
row += 1
|
||||
except AttributeError:
|
||||
logging.exception(f"Issue adding {unit_type} to debriefing information")
|
||||
|
||||
front_line_losses = self.debriefing.front_line_losses_by_type(player=False)
|
||||
for unit_type, count in front_line_losses.items():
|
||||
if count == 0:
|
||||
continue
|
||||
enemylostUnitsLayout.addWidget(QLabel(db.unit_type_name(unit_type)), row, 0)
|
||||
enemylostUnitsLayout.addWidget(QLabel("{}".format(count)), row, 1)
|
||||
row += 1
|
||||
|
||||
convoy_losses = self.debriefing.convoy_losses_by_type(player=False)
|
||||
for unit_type, count in convoy_losses.items():
|
||||
try:
|
||||
lostUnitsLayout.addWidget(
|
||||
QLabel(f"{db.unit_type_name(unit_type)} from convoy"), row, 0
|
||||
)
|
||||
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
||||
row += 1
|
||||
except AttributeError:
|
||||
logging.exception(f"Issue adding {unit_type} to debriefing information")
|
||||
|
||||
airlift_losses = self.debriefing.airlift_losses_by_type(player=False)
|
||||
for unit_type, count in airlift_losses.items():
|
||||
try:
|
||||
lostUnitsLayout.addWidget(
|
||||
QLabel(f"{db.unit_type_name(unit_type)} from airlift"), row, 0
|
||||
)
|
||||
lostUnitsLayout.addWidget(QLabel(str(count)), row, 1)
|
||||
row += 1
|
||||
except AttributeError:
|
||||
logging.exception(f"Issue adding {unit_type} to debriefing information")
|
||||
|
||||
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)
|
||||
row += 1
|
||||
except AttributeError:
|
||||
logging.exception(f"Issue adding {building} to debriefing information")
|
||||
|
||||
self.layout.addWidget(enemylostUnits)
|
||||
|
||||
# TODO: Display dead ground object units and runways.
|
||||
|
||||
# confirm button
|
||||
okay = QPushButton("Okay")
|
||||
okay.clicked.connect(self.close)
|
||||
self.layout.addWidget(okay)
|
||||
|
||||
self.setLayout(self.layout)
|
||||
layout.addWidget(okay)
|
||||
|
||||
@ -4,6 +4,7 @@ import json
|
||||
import os
|
||||
import timeit
|
||||
from datetime import timedelta
|
||||
from typing import Sized
|
||||
|
||||
from PySide2 import QtCore
|
||||
from PySide2.QtCore import QObject, Qt, Signal
|
||||
@ -132,38 +133,48 @@ class QWaitingForMissionResultWindow(QDialog):
|
||||
self.layout.addLayout(self.gridLayout, 1, 0)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
@staticmethod
|
||||
def add_update_row(description: str, count: Sized, layout: QGridLayout) -> None:
|
||||
row = layout.rowCount()
|
||||
layout.addWidget(QLabel(f"<b>{description}</b>"), row, 0)
|
||||
layout.addWidget(QLabel(f"{len(count)}"), row, 1)
|
||||
|
||||
def updateLayout(self, debriefing: Debriefing) -> None:
|
||||
updateBox = QGroupBox("Mission status")
|
||||
updateLayout = QGridLayout()
|
||||
updateBox.setLayout(updateLayout)
|
||||
update_layout = QGridLayout()
|
||||
updateBox.setLayout(update_layout)
|
||||
self.debriefing = debriefing
|
||||
|
||||
updateLayout.addWidget(QLabel("<b>Aircraft destroyed</b>"), 0, 0)
|
||||
updateLayout.addWidget(
|
||||
QLabel(str(len(list(debriefing.air_losses.losses)))), 0, 1
|
||||
self.add_update_row(
|
||||
"Aircraft destroyed", list(debriefing.air_losses.losses), update_layout
|
||||
)
|
||||
|
||||
updateLayout.addWidget(QLabel("<b>Front line units destroyed</b>"), 1, 0)
|
||||
updateLayout.addWidget(
|
||||
QLabel(str(len(list(debriefing.front_line_losses)))), 1, 1
|
||||
self.add_update_row(
|
||||
"Front line units destroyed",
|
||||
list(debriefing.front_line_losses),
|
||||
update_layout,
|
||||
)
|
||||
|
||||
updateLayout.addWidget(QLabel("<b>Convoy units destroyed</b>"), 2, 0)
|
||||
updateLayout.addWidget(QLabel(str(len(list(debriefing.convoy_losses)))), 2, 1)
|
||||
|
||||
updateLayout.addWidget(QLabel("<b>Airlift cargo destroyed</b>"), 3, 0)
|
||||
updateLayout.addWidget(QLabel(str(len(list(debriefing.airlift_losses)))), 3, 1)
|
||||
|
||||
updateLayout.addWidget(QLabel("<b>Other ground units destroyed</b>"), 4, 0)
|
||||
updateLayout.addWidget(
|
||||
QLabel(str(len(list(debriefing.ground_object_losses)))), 4, 1
|
||||
self.add_update_row(
|
||||
"Convoy units destroyed", list(debriefing.convoy_losses), update_layout
|
||||
)
|
||||
self.add_update_row(
|
||||
"Shipping cargo destroyed",
|
||||
list(debriefing.cargo_ship_losses),
|
||||
update_layout,
|
||||
)
|
||||
self.add_update_row(
|
||||
"Airlift cargo destroyed", list(debriefing.airlift_losses), update_layout
|
||||
)
|
||||
self.add_update_row(
|
||||
"Ground units lost at objective areas",
|
||||
list(debriefing.ground_object_losses),
|
||||
update_layout,
|
||||
)
|
||||
self.add_update_row(
|
||||
"Buildings destroyed", list(debriefing.building_losses), update_layout
|
||||
)
|
||||
self.add_update_row(
|
||||
"Base capture events", list(debriefing.base_capture_events), update_layout
|
||||
)
|
||||
|
||||
updateLayout.addWidget(QLabel("<b>Buildings destroyed</b>"), 5, 0)
|
||||
updateLayout.addWidget(QLabel(str(len(list(debriefing.building_losses)))), 5, 1)
|
||||
|
||||
updateLayout.addWidget(QLabel("<b>Base Capture Events</b>"), 6, 0)
|
||||
updateLayout.addWidget(QLabel(str(len(debriefing.base_capture_events))), 6, 1)
|
||||
|
||||
# Clear previous content of the window
|
||||
for i in reversed(range(self.gridLayout.count())):
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user