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.
This commit is contained in:
Dan Albert 2021-01-01 13:48:23 -08:00
parent de325c1208
commit 9671542bdf
5 changed files with 28 additions and 63 deletions

View File

@ -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 = {}

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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