diff --git a/changelog.md b/changelog.md index b0dc6293..0fc7d44e 100644 --- a/changelog.md +++ b/changelog.md @@ -28,6 +28,7 @@ Saves from 3.x are not compatible with 4.0. * **[UI]** Multiple waypoints can now be deleted simultaneously if multiple waypoints are selected. * **[UI]** Carriers and LHAs now match the colour of airfields, and their destination icons are translucent. * **[UI]** Updated intel box text for first turn. +* **[UI]** Base Capture Cheat is now usable at all bases and can also be used to transfer player-owned bases to OPFOR. * **[Units/Factions/Mods]** Removes MB-339PAN support, as the mod is now deprecated and no longer works with DCS 2.7+. * **[New Game Wizard]** Mods are now selected via checkboxes in the new game wizard, not as separate factions. @@ -35,6 +36,7 @@ Saves from 3.x are not compatible with 4.0. * **[Campaign AI]** Fix procurement for factions that lack some unit types. * **[Campaign AI]** Fix auto purchase of aircraft for factions that have no transport aircraft. +* **[Campaign AI]** Fix refunding of pending aircraft purchases when a side has no factory available. * **[Mission Generation]** Fixed problem with mission load when control point name contained an apostrophe. * **[Mission Generation]** Fixed EWR group names so they contribute to Skynet again. * **[Mission Generation]** Fixed duplicate name error when generating convoys and cargo ships when creating manual transfers after loading a game. diff --git a/game/unitdelivery.py b/game/unitdelivery.py index 4de3addf..a6de6a71 100644 --- a/game/unitdelivery.py +++ b/game/unitdelivery.py @@ -3,7 +3,7 @@ from __future__ import annotations import logging from collections import defaultdict from dataclasses import dataclass -from typing import Dict, Optional, TYPE_CHECKING, Any +from typing import Optional, TYPE_CHECKING, Any from game.theater import ControlPoint from .dcs.groundunittype import GroundUnitType @@ -28,16 +28,16 @@ class PendingUnitDeliveries: self.destination = destination # Maps unit type to order quantity. - self.units: Dict[UnitType, int] = defaultdict(int) + self.units: dict[UnitType, int] = defaultdict(int) def __str__(self) -> str: return f"Pending delivery to {self.destination}" - def order(self, units: Dict[UnitType, int]) -> None: + def order(self, units: dict[UnitType, int]) -> None: for k, v in units.items(): self.units[k] += v - def sell(self, units: Dict[UnitType, int]) -> None: + def sell(self, units: dict[UnitType, int]) -> None: for k, v in units.items(): self.units[k] -= v @@ -45,7 +45,15 @@ class PendingUnitDeliveries: self.refund(game, self.units) self.units = defaultdict(int) - def refund(self, game: Game, units: Dict[UnitType, int]) -> None: + def refund_ground_units(self, game: Game) -> None: + ground_units: dict[UnitType[Any], int] = { + u: self.units[u] for u in self.units.keys() if isinstance(u, GroundUnitType) + } + self.refund(game, ground_units) + for gu in ground_units.keys(): + del self.units[gu] + + def refund(self, game: Game, units: dict[UnitType, int]) -> None: for unit_type, count in units.items(): logging.info(f"Refunding {count} {unit_type} at {self.destination.name}") game.adjust_budget( @@ -69,12 +77,11 @@ class PendingUnitDeliveries: f"{self.destination.name} lost its source for ground unit " "reinforcements. Refunding purchase price." ) - self.refund_all(game) - return + self.refund_ground_units(game) - bought_units: Dict[UnitType, int] = {} - units_needing_transfer: Dict[GroundUnitType, int] = {} - sold_units: Dict[UnitType, int] = {} + bought_units: dict[UnitType, int] = {} + units_needing_transfer: dict[GroundUnitType, int] = {} + sold_units: dict[UnitType, int] = {} for unit_type, count in self.units.items(): coalition = "Ally" if self.destination.captured else "Enemy" d: dict[Any, int] @@ -102,11 +109,16 @@ class PendingUnitDeliveries: self.destination.base.commit_losses(sold_units) if units_needing_transfer: + if ground_unit_source is None: + raise RuntimeError( + f"ground unit source could not be found for {self.destination} but still tried to " + f"transfer units to there" + ) ground_unit_source.base.commission_units(units_needing_transfer) self.create_transfer(game, ground_unit_source, units_needing_transfer) def create_transfer( - self, game: Game, source: ControlPoint, units: Dict[GroundUnitType, int] + self, game: Game, source: ControlPoint, units: dict[GroundUnitType, int] ) -> None: game.transfers.new_transfer(TransferOrder(source, self.destination, units)) diff --git a/qt_ui/windows/basemenu/QBaseMenu2.py b/qt_ui/windows/basemenu/QBaseMenu2.py index 4b8265c8..8a913280 100644 --- a/qt_ui/windows/basemenu/QBaseMenu2.py +++ b/qt_ui/windows/basemenu/QBaseMenu2.py @@ -118,18 +118,10 @@ class QBaseMenu2(QDialog): @property def cheat_capturable(self) -> bool: - if not self.game_model.game.settings.enable_base_capture_cheat: - return False - if self.cp.captured: - return False - - for connected in self.cp.connected_points: - if connected.captured: - return True - return False + return self.game_model.game.settings.enable_base_capture_cheat def cheat_capture(self) -> None: - self.cp.capture(self.game_model.game, for_player=True) + self.cp.capture(self.game_model.game, for_player=not self.cp.captured) # Reinitialized ground planners and the like. The ATO needs to be reset because # missions planned against the flipped base are no longer valid. self.game_model.game.reset_ato()