mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Load two units per cargo plane.
Fixes https://github.com/dcs-liberation/dcs_liberation/issues/1029
This commit is contained in:
parent
cb159e3341
commit
96cdea2a94
@ -24,7 +24,7 @@ from game import db
|
||||
from game.theater import Airfield, ControlPoint
|
||||
from game.transfers import CargoShip
|
||||
from game.unitmap import (
|
||||
AirliftUnit,
|
||||
AirliftUnits,
|
||||
Building,
|
||||
ConvoyUnit,
|
||||
FrontLineUnit,
|
||||
@ -75,8 +75,8 @@ class GroundLosses:
|
||||
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)
|
||||
player_airlifts: List[AirliftUnits] = field(default_factory=list)
|
||||
enemy_airlifts: List[AirliftUnits] = field(default_factory=list)
|
||||
|
||||
player_ground_objects: List[GroundObjectUnit] = field(default_factory=list)
|
||||
enemy_ground_objects: List[GroundObjectUnit] = field(default_factory=list)
|
||||
@ -160,7 +160,7 @@ class Debriefing:
|
||||
yield from self.ground_losses.enemy_cargo_ships
|
||||
|
||||
@property
|
||||
def airlift_losses(self) -> Iterator[AirliftUnit]:
|
||||
def airlift_losses(self) -> Iterator[AirliftUnits]:
|
||||
yield from self.ground_losses.player_airlifts
|
||||
yield from self.ground_losses.enemy_airlifts
|
||||
|
||||
@ -220,7 +220,8 @@ class Debriefing:
|
||||
else:
|
||||
losses = self.ground_losses.enemy_airlifts
|
||||
for loss in losses:
|
||||
losses_by_type[loss.unit_type] += 1
|
||||
for unit_type in loss.cargo:
|
||||
losses_by_type[unit_type] += 1
|
||||
return losses_by_type
|
||||
|
||||
def building_losses_by_type(self, player: bool) -> Dict[str, int]:
|
||||
|
||||
@ -202,19 +202,17 @@ class Event:
|
||||
@staticmethod
|
||||
def commit_airlift_losses(debriefing: Debriefing) -> None:
|
||||
for loss in debriefing.airlift_losses:
|
||||
unit_type = loss.unit_type
|
||||
transfer = loss.transfer
|
||||
available = loss.transfer.units.get(unit_type, 0)
|
||||
airlift_name = f"airlift from {transfer.origin} to {transfer.destination}"
|
||||
if available <= 0:
|
||||
logging.error(
|
||||
f"Found killed {unit_type} in {airlift_name} but that airlift has "
|
||||
"none available."
|
||||
)
|
||||
continue
|
||||
|
||||
logging.info(f"{unit_type} destroyed in {airlift_name}")
|
||||
for unit_type in loss.cargo:
|
||||
try:
|
||||
transfer.kill_unit(unit_type)
|
||||
logging.info(f"{unit_type} destroyed in {airlift_name}")
|
||||
except KeyError:
|
||||
logging.exception(
|
||||
f"Found killed {unit_type} in {airlift_name} but that airlift "
|
||||
"has none available."
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def commit_ground_object_losses(debriefing: Debriefing) -> None:
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
import math
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass, field
|
||||
from functools import singledispatchmethod
|
||||
@ -89,10 +90,9 @@ class TransferOrder:
|
||||
self.units.clear()
|
||||
|
||||
def kill_unit(self, unit_type: Type[VehicleType]) -> None:
|
||||
if unit_type in self.units:
|
||||
if unit_type not in self.units or not self.units[unit_type]:
|
||||
raise KeyError(f"{self.destination} has no {unit_type} remaining")
|
||||
self.units[unit_type] -= 1
|
||||
return
|
||||
raise KeyError
|
||||
|
||||
@property
|
||||
def size(self) -> int:
|
||||
@ -254,11 +254,13 @@ class AirliftPlanner:
|
||||
self, squadron: Squadron, inventory: ControlPointAircraftInventory
|
||||
) -> int:
|
||||
available = inventory.available(squadron.aircraft)
|
||||
# 4 is the max flight size in DCS.
|
||||
flight_size = min(self.transfer.size, available, 4)
|
||||
capacity_each = 1 if squadron.aircraft.helicopter else 2
|
||||
required = math.ceil(self.transfer.size / capacity_each)
|
||||
flight_size = min(required, available, squadron.aircraft.group_size_max)
|
||||
capacity = flight_size * capacity_each
|
||||
|
||||
if flight_size < self.transfer.size:
|
||||
transfer = self.game.transfers.split_transfer(self.transfer, flight_size)
|
||||
if capacity < self.transfer.size:
|
||||
transfer = self.game.transfers.split_transfer(self.transfer, capacity)
|
||||
else:
|
||||
transfer = self.transfer
|
||||
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
"""Maps generated units back to their Liberation types."""
|
||||
import itertools
|
||||
import math
|
||||
from dataclasses import dataclass
|
||||
from typing import Dict, Optional, Type
|
||||
|
||||
@ -40,8 +42,8 @@ class ConvoyUnit:
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class AirliftUnit:
|
||||
unit_type: Type[VehicleType]
|
||||
class AirliftUnits:
|
||||
cargo: tuple[Type[VehicleType], ...]
|
||||
transfer: TransferOrder
|
||||
|
||||
|
||||
@ -59,7 +61,7 @@ class UnitMap:
|
||||
self.buildings: Dict[str, Building] = {}
|
||||
self.convoys: Dict[str, ConvoyUnit] = {}
|
||||
self.cargo_ships: Dict[str, CargoShip] = {}
|
||||
self.airlifts: Dict[str, AirliftUnit] = {}
|
||||
self.airlifts: Dict[str, AirliftUnits] = {}
|
||||
|
||||
def add_aircraft(self, group: FlyingGroup, flight: Flight) -> None:
|
||||
for pilot, unit in zip(flight.roster.pilots, group.units):
|
||||
@ -177,15 +179,26 @@ class UnitMap:
|
||||
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()):
|
||||
capacity_each = math.ceil(transfer.size / len(group.units))
|
||||
for idx, transport in enumerate(group.units):
|
||||
# Slice the units in groups based on the capacity of each unit. Cargo is
|
||||
# assigned arbitrarily to units in the order of the group. The last unit in
|
||||
# the group will receive a partial load if there is not enough cargo to fill
|
||||
# every transport.
|
||||
base_idx = idx * capacity_each
|
||||
cargo = tuple(
|
||||
itertools.islice(
|
||||
transfer.iter_units(), base_idx, base_idx + capacity_each
|
||||
)
|
||||
)
|
||||
# The actual name is a String (the pydcs translatable string), which
|
||||
# doesn't define __eq__.
|
||||
name = str(transport.name)
|
||||
if name in self.airlifts:
|
||||
raise RuntimeError(f"Duplicate airlift unit: {name}")
|
||||
self.airlifts[name] = AirliftUnit(cargo_type, transfer)
|
||||
self.airlifts[name] = AirliftUnits(cargo, transfer)
|
||||
|
||||
def airlift_unit(self, name: str) -> Optional[AirliftUnit]:
|
||||
def airlift_unit(self, name: str) -> Optional[AirliftUnits]:
|
||||
return self.airlifts.get(name, None)
|
||||
|
||||
def add_building(self, ground_object: BuildingGroundObject, group: Group) -> None:
|
||||
|
||||
@ -133,10 +133,10 @@ class QWaitingForMissionResultWindow(QDialog):
|
||||
self.setLayout(self.layout)
|
||||
|
||||
@staticmethod
|
||||
def add_update_row(description: str, count: Sized, layout: QGridLayout) -> None:
|
||||
def add_update_row(description: str, count: int, layout: QGridLayout) -> None:
|
||||
row = layout.rowCount()
|
||||
layout.addWidget(QLabel(f"<b>{description}</b>"), row, 0)
|
||||
layout.addWidget(QLabel(f"{len(count)}"), row, 1)
|
||||
layout.addWidget(QLabel(f"{count}"), row, 1)
|
||||
|
||||
def updateLayout(self, debriefing: Debriefing) -> None:
|
||||
updateBox = QGroupBox("Mission status")
|
||||
@ -145,34 +145,36 @@ class QWaitingForMissionResultWindow(QDialog):
|
||||
self.debriefing = debriefing
|
||||
|
||||
self.add_update_row(
|
||||
"Aircraft destroyed", list(debriefing.air_losses.losses), update_layout
|
||||
"Aircraft destroyed", len(list(debriefing.air_losses.losses)), update_layout
|
||||
)
|
||||
self.add_update_row(
|
||||
"Front line units destroyed",
|
||||
list(debriefing.front_line_losses),
|
||||
len(list(debriefing.front_line_losses)),
|
||||
update_layout,
|
||||
)
|
||||
self.add_update_row(
|
||||
"Convoy units destroyed", list(debriefing.convoy_losses), update_layout
|
||||
"Convoy units destroyed", len(list(debriefing.convoy_losses)), update_layout
|
||||
)
|
||||
self.add_update_row(
|
||||
"Shipping cargo destroyed",
|
||||
list(debriefing.cargo_ship_losses),
|
||||
len(list(debriefing.cargo_ship_losses)),
|
||||
update_layout,
|
||||
)
|
||||
self.add_update_row(
|
||||
"Airlift cargo destroyed", list(debriefing.airlift_losses), update_layout
|
||||
"Airlift cargo destroyed",
|
||||
sum(len(loss.cargo) for loss in debriefing.airlift_losses),
|
||||
update_layout,
|
||||
)
|
||||
self.add_update_row(
|
||||
"Ground units lost at objective areas",
|
||||
list(debriefing.ground_object_losses),
|
||||
len(list(debriefing.ground_object_losses)),
|
||||
update_layout,
|
||||
)
|
||||
self.add_update_row(
|
||||
"Buildings destroyed", list(debriefing.building_losses), update_layout
|
||||
"Buildings destroyed", len(list(debriefing.building_losses)), update_layout
|
||||
)
|
||||
self.add_update_row(
|
||||
"Base capture events", debriefing.base_captures, update_layout
|
||||
"Base capture events", len(debriefing.base_captures), update_layout
|
||||
)
|
||||
|
||||
# Clear previous content of the window
|
||||
|
||||
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user