From 9671542bdfe4ebbb19aa23e5acc801ce935e68ce Mon Sep 17 00:00:00 2001 From: Dan Albert Date: Fri, 1 Jan 2021 13:48:23 -0800 Subject: [PATCH] Decouple unit deliveries and conflict events. Fixes https://github.com/Khopa/dcs_liberation/issues/692 and lets us clean up the interface quite a bit. --- game/event/event.py | 49 ++++++++------------- game/game.py | 23 +--------- game/procurement.py | 6 +-- game/theater/controlpoint.py | 10 ++--- qt_ui/windows/basemenu/QRecruitBehaviour.py | 3 +- 5 files changed, 28 insertions(+), 63 deletions(-) diff --git a/game/event/event.py b/game/event/event.py index 61d7e69d..c00ab477 100644 --- a/game/event/event.py +++ b/game/event/event.py @@ -2,7 +2,7 @@ from __future__ import annotations import logging import math -from typing import Dict, List, TYPE_CHECKING, Type +from typing import Dict, Iterator, List, TYPE_CHECKING, Tuple, Type from dcs.mapping import Point from dcs.task import Task @@ -296,9 +296,6 @@ class Event: self.game.turn) self.game.informations.append(info) - def skip(self): - pass - def redeploy_units(self, cp): """" Auto redeploy units to newly captured base @@ -340,32 +337,25 @@ class Event: logging.info(info.text) -class UnitsDeliveryEvent(Event): - - informational = True - - def __init__(self, attacker_name: str, defender_name: str, - from_cp: ControlPoint, to_cp: ControlPoint, - game: Game) -> None: - super(UnitsDeliveryEvent, self).__init__(game=game, - location=to_cp.position, - from_cp=from_cp, - target_cp=to_cp, - attacker_name=attacker_name, - defender_name=defender_name) +class UnitsDeliveryEvent: + def __init__(self, control_point: ControlPoint) -> None: + self.to_cp = control_point self.units: Dict[Type[UnitType], int] = {} def __str__(self) -> str: return "Pending delivery to {}".format(self.to_cp) - def deliver(self, units: Dict[Type[UnitType], int]) -> None: + def order(self, units: Dict[Type[UnitType], int]) -> None: for k, v in units.items(): self.units[k] = self.units.get(k, 0) + v - def refund_all(self) -> None: + def consume_each_order(self) -> Iterator[Tuple[Type[UnitType], int]]: while self.units: - unit_type, count = self.units.popitem() + yield self.units.popitem() + + def refund_all(self, game: Game) -> None: + for unit_type, count in self.consume_each_order(): try: price = PRICES[unit_type] except KeyError: @@ -374,15 +364,14 @@ class UnitsDeliveryEvent(Event): logging.info( f"Refunding {count} {unit_type.id} at {self.to_cp.name}") - self.game.adjust_budget(price * count, player=self.to_cp.captured) - - def skip(self) -> None: - for k, v in self.units.items(): - if self.to_cp.captured: - name = "Ally " - else: - name = "Enemy " - self.game.message( - f"{name} reinforcements: {k.id} x {v} at {self.to_cp.name}") + game.adjust_budget(price * count, player=self.to_cp.captured) + def process(self, game: Game) -> None: + for unit_type, count in self.units.items(): + coalition = "Ally" if self.to_cp.captured else "Enemy" + aircraft = unit_type.id + name = self.to_cp.name + game.message( + f"{coalition} reinforcements: {aircraft} x {count} at {name}") self.to_cp.base.commision_units(self.units) + self.units = {} diff --git a/game/game.py b/game/game.py index 7482b335..86d1b41e 100644 --- a/game/game.py +++ b/game/game.py @@ -110,9 +110,6 @@ class Game: self.theater.controlpoints ) - for cp in self.theater.controlpoints: - cp.pending_unit_deliveries = self.units_delivery_event(cp) - self.sanitize_sides() self.on_load() @@ -204,15 +201,6 @@ class Game: self.enemy_budget = 0 self.enemy_budget += Income(self, player=False).total - def units_delivery_event(self, to_cp: ControlPoint) -> UnitsDeliveryEvent: - event = UnitsDeliveryEvent(attacker_name=self.player_name, - defender_name=self.player_name, - from_cp=to_cp, - to_cp=to_cp, - game=self) - self.events.append(event) - return event - def initiate_event(self, event: Event) -> UnitMap: #assert event in self.events logging.info("Generating {} (regular)".format(event)) @@ -244,16 +232,8 @@ class Game: self.informations.append(Information("End of turn #" + str(self.turn), "-" * 40, 0)) self.turn += 1 - for event in self.events: - if self.settings.version == "dev": - # don't damage player CPs in by skipping in dev mode - if isinstance(event, UnitsDeliveryEvent): - event.skip() - else: - event.skip() - for control_point in self.theater.controlpoints: - control_point.process_turn() + control_point.process_turn(self) self.process_enemy_income() @@ -291,7 +271,6 @@ class Game: self.aircraft_inventory.reset() for cp in self.theater.controlpoints: - cp.pending_unit_deliveries = self.units_delivery_event(cp) self.aircraft_inventory.set_from_control_point(cp) # Check for win or loss condition diff --git a/game/procurement.py b/game/procurement.py index 9a928034..653ddb5b 100644 --- a/game/procurement.py +++ b/game/procurement.py @@ -145,8 +145,7 @@ class ProcurementAi: break budget -= db.PRICES[unit] - assert cp.pending_unit_deliveries is not None - cp.pending_unit_deliveries.deliver({unit: 1}) + cp.pending_unit_deliveries.order({unit: 1}) return budget @@ -190,8 +189,7 @@ class ProcurementAi: continue budget -= db.PRICES[unit] * request.number - assert airbase.pending_unit_deliveries is not None - airbase.pending_unit_deliveries.deliver({unit: request.number}) + airbase.pending_unit_deliveries.order({unit: request.number}) return budget diff --git a/game/theater/controlpoint.py b/game/theater/controlpoint.py index 50efad63..f0bb53a3 100644 --- a/game/theater/controlpoint.py +++ b/game/theater/controlpoint.py @@ -230,7 +230,7 @@ class ControlPoint(MissionTarget, ABC): self.cptype = cptype # TODO: Should be Airbase specific. self.stances: Dict[int, CombatStance] = {} - self.pending_unit_deliveries: Optional[UnitsDeliveryEvent] = None + self.pending_unit_deliveries = UnitsDeliveryEvent(self) self.target_position: Optional[Point] = None @@ -367,8 +367,7 @@ class ControlPoint(MissionTarget, ABC): # TODO: Should be Airbase specific. def capture(self, game: Game, for_player: bool) -> None: - if self.pending_unit_deliveries is not None: - self.pending_unit_deliveries.refund_all() + self.pending_unit_deliveries.refund_all(game) if for_player: self.captured = True @@ -406,7 +405,6 @@ class ControlPoint(MissionTarget, ABC): return total def expected_aircraft_next_turn(self, game: Game) -> PendingOccupancy: - assert self.pending_unit_deliveries on_order = 0 for unit_bought in self.pending_unit_deliveries.units: if issubclass(unit_bought, FlyingType): @@ -443,7 +441,9 @@ class ControlPoint(MissionTarget, ABC): return self.runway_status.begin_repair() - def process_turn(self) -> None: + def process_turn(self, game: Game) -> None: + self.pending_unit_deliveries.process(game) + runway_status = self.runway_status if runway_status is not None: runway_status.process_turn() diff --git a/qt_ui/windows/basemenu/QRecruitBehaviour.py b/qt_ui/windows/basemenu/QRecruitBehaviour.py index 933d6a3e..0cccd16d 100644 --- a/qt_ui/windows/basemenu/QRecruitBehaviour.py +++ b/qt_ui/windows/basemenu/QRecruitBehaviour.py @@ -36,7 +36,6 @@ class QRecruitBehaviour: @property def pending_deliveries(self) -> UnitsDeliveryEvent: - assert self.cp.pending_unit_deliveries return self.cp.pending_unit_deliveries @property @@ -128,7 +127,7 @@ class QRecruitBehaviour: def buy(self, unit_type: Type[UnitType]): price = db.PRICES[unit_type] if self.budget >= price: - self.pending_deliveries.deliver({unit_type: 1}) + self.pending_deliveries.order({unit_type: 1}) self.budget -= price else: # TODO : display modal warning