mirror of
https://github.com/dcs-liberation/dcs_liberation.git
synced 2025-11-10 14:22:26 +00:00
Move calculation of aircraft amounts into game.
The planner needs to know how much space is still expected to be available next turn.
This commit is contained in:
parent
f8b2dbe283
commit
c4b8a41742
@ -352,11 +352,13 @@ class Event:
|
|||||||
logging.info(info.text)
|
logging.info(info.text)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class UnitsDeliveryEvent(Event):
|
class UnitsDeliveryEvent(Event):
|
||||||
|
|
||||||
informational = True
|
informational = True
|
||||||
|
|
||||||
def __init__(self, attacker_name: str, defender_name: str, from_cp: ControlPoint, to_cp: ControlPoint, game):
|
def __init__(self, attacker_name: str, defender_name: str,
|
||||||
|
from_cp: ControlPoint, to_cp: ControlPoint,
|
||||||
|
game: Game) -> None:
|
||||||
super(UnitsDeliveryEvent, self).__init__(game=game,
|
super(UnitsDeliveryEvent, self).__init__(game=game,
|
||||||
location=to_cp.position,
|
location=to_cp.position,
|
||||||
from_cp=from_cp,
|
from_cp=from_cp,
|
||||||
@ -364,17 +366,16 @@ class UnitsDeliveryEvent(Event):
|
|||||||
attacker_name=attacker_name,
|
attacker_name=attacker_name,
|
||||||
defender_name=defender_name)
|
defender_name=defender_name)
|
||||||
|
|
||||||
self.units: Dict[UnitType, int] = {}
|
self.units: Dict[Type[UnitType], int] = {}
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self) -> str:
|
||||||
return "Pending delivery to {}".format(self.to_cp)
|
return "Pending delivery to {}".format(self.to_cp)
|
||||||
|
|
||||||
def deliver(self, units: Dict[UnitType, int]):
|
def deliver(self, units: Dict[Type[UnitType], int]) -> None:
|
||||||
for k, v in units.items():
|
for k, v in units.items():
|
||||||
self.units[k] = self.units.get(k, 0) + v
|
self.units[k] = self.units.get(k, 0) + v
|
||||||
|
|
||||||
def skip(self):
|
def skip(self) -> None:
|
||||||
|
|
||||||
for k, v in self.units.items():
|
for k, v in self.units.items():
|
||||||
info = Information("Ally Reinforcement", str(k.id) + " x " + str(v) + " at " + self.to_cp.name, self.game.turn)
|
info = Information("Ally Reinforcement", str(k.id) + " x " + str(v) + " at " + self.to_cp.name, self.game.turn)
|
||||||
self.game.informations.append(info)
|
self.game.informations.append(info)
|
||||||
|
|||||||
@ -316,7 +316,7 @@ class Game:
|
|||||||
if i > 50 or budget_for_aircraft <= 0:
|
if i > 50 or budget_for_aircraft <= 0:
|
||||||
break
|
break
|
||||||
target_cp = random.choice(potential_cp_armor)
|
target_cp = random.choice(potential_cp_armor)
|
||||||
if target_cp.base.total_planes >= MAX_AIRCRAFT:
|
if target_cp.base.total_aircraft >= MAX_AIRCRAFT:
|
||||||
continue
|
continue
|
||||||
unit = random.choice(potential_units)
|
unit = random.choice(potential_units)
|
||||||
price = db.PRICES[unit] * 2
|
price = db.PRICES[unit] * 2
|
||||||
|
|||||||
@ -4,9 +4,8 @@ import math
|
|||||||
import typing
|
import typing
|
||||||
from typing import Dict, Type
|
from typing import Dict, Type
|
||||||
|
|
||||||
from dcs.planes import PlaneType
|
|
||||||
from dcs.task import CAP, CAS, Embarking, PinpointStrike, Task
|
from dcs.task import CAP, CAS, Embarking, PinpointStrike, Task
|
||||||
from dcs.unittype import UnitType, VehicleType
|
from dcs.unittype import FlyingType, UnitType, VehicleType
|
||||||
from dcs.vehicles import AirDefence, Armor
|
from dcs.vehicles import AirDefence, Armor
|
||||||
|
|
||||||
from game import db
|
from game import db
|
||||||
@ -21,20 +20,16 @@ BASE_MIN_STRENGTH = 0
|
|||||||
|
|
||||||
|
|
||||||
class Base:
|
class Base:
|
||||||
aircraft = {} # type: typing.Dict[PlaneType, int]
|
|
||||||
armor = {} # type: typing.Dict[VehicleType, int]
|
|
||||||
aa = {} # type: typing.Dict[AirDefence, int]
|
|
||||||
strength = 1 # type: float
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.aircraft = {}
|
self.aircraft: Dict[FlyingType, int] = {}
|
||||||
self.armor = {}
|
self.armor: Dict[VehicleType, int] = {}
|
||||||
self.aa = {}
|
self.aa: Dict[AirDefence, int] = {}
|
||||||
self.commision_points: Dict[Type, float] = {}
|
self.commision_points: Dict[Type, float] = {}
|
||||||
self.strength = 1
|
self.strength = 1
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def total_planes(self) -> int:
|
def total_aircraft(self) -> int:
|
||||||
return sum(self.aircraft.values())
|
return sum(self.aircraft.values())
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -83,7 +78,7 @@ class Base:
|
|||||||
logging.info("{} for {} ({}): {}".format(self, for_type, count, result))
|
logging.info("{} for {} ({}): {}".format(self, for_type, count, result))
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _find_best_planes(self, for_type: Task, count: int) -> typing.Dict[PlaneType, int]:
|
def _find_best_planes(self, for_type: Task, count: int) -> typing.Dict[FlyingType, int]:
|
||||||
return self._find_best_unit(self.aircraft, for_type, count)
|
return self._find_best_unit(self.aircraft, for_type, count)
|
||||||
|
|
||||||
def _find_best_armor(self, for_type: Task, count: int) -> typing.Dict[Armor, int]:
|
def _find_best_armor(self, for_type: Task, count: int) -> typing.Dict[Armor, int]:
|
||||||
@ -155,7 +150,7 @@ class Base:
|
|||||||
if task:
|
if task:
|
||||||
count = sum([v for k, v in self.aircraft.items() if db.unit_task(k) == task])
|
count = sum([v for k, v in self.aircraft.items() if db.unit_task(k) == task])
|
||||||
else:
|
else:
|
||||||
count = self.total_planes
|
count = self.total_aircraft
|
||||||
|
|
||||||
count = int(math.ceil(count * PLANES_SCRAMBLE_FACTOR * self.strength))
|
count = int(math.ceil(count * PLANES_SCRAMBLE_FACTOR * self.strength))
|
||||||
return min(min(max(count, PLANES_SCRAMBLE_MIN_BASE), int(PLANES_SCRAMBLE_MAX_BASE * multiplier)), count)
|
return min(min(max(count, PLANES_SCRAMBLE_MIN_BASE), int(PLANES_SCRAMBLE_MAX_BASE * multiplier)), count)
|
||||||
@ -167,18 +162,18 @@ class Base:
|
|||||||
# previous logic removed because we always want the full air defense capabilities.
|
# previous logic removed because we always want the full air defense capabilities.
|
||||||
return self.total_aa
|
return self.total_aa
|
||||||
|
|
||||||
def scramble_sweep(self, multiplier: float) -> typing.Dict[PlaneType, int]:
|
def scramble_sweep(self, multiplier: float) -> typing.Dict[FlyingType, int]:
|
||||||
return self._find_best_planes(CAP, self.scramble_count(multiplier, CAP))
|
return self._find_best_planes(CAP, self.scramble_count(multiplier, CAP))
|
||||||
|
|
||||||
def scramble_last_defense(self):
|
def scramble_last_defense(self):
|
||||||
# return as many CAP-capable aircraft as we can since this is the last defense of the base
|
# return as many CAP-capable aircraft as we can since this is the last defense of the base
|
||||||
# (but not more than 20 - that's just nuts)
|
# (but not more than 20 - that's just nuts)
|
||||||
return self._find_best_planes(CAP, min(self.total_planes, 20))
|
return self._find_best_planes(CAP, min(self.total_aircraft, 20))
|
||||||
|
|
||||||
def scramble_cas(self, multiplier: float) -> typing.Dict[PlaneType, int]:
|
def scramble_cas(self, multiplier: float) -> typing.Dict[FlyingType, int]:
|
||||||
return self._find_best_planes(CAS, self.scramble_count(multiplier, CAS))
|
return self._find_best_planes(CAS, self.scramble_count(multiplier, CAS))
|
||||||
|
|
||||||
def scramble_interceptors(self, multiplier: float) -> typing.Dict[PlaneType, int]:
|
def scramble_interceptors(self, multiplier: float) -> typing.Dict[FlyingType, int]:
|
||||||
return self._find_best_planes(CAP, self.scramble_count(multiplier, CAP))
|
return self._find_best_planes(CAP, self.scramble_count(multiplier, CAP))
|
||||||
|
|
||||||
def assemble_attack(self) -> typing.Dict[Armor, int]:
|
def assemble_attack(self) -> typing.Dict[Armor, int]:
|
||||||
|
|||||||
@ -376,6 +376,15 @@ class ControlPoint(MissionTarget):
|
|||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@property
|
||||||
|
def expected_aircraft_next_turn(self) -> int:
|
||||||
|
total = self.base.total_aircraft
|
||||||
|
assert self.pending_unit_deliveries
|
||||||
|
for unit_bought in self.pending_unit_deliveries.units:
|
||||||
|
if issubclass(unit_bought, FlyingType):
|
||||||
|
total += self.pending_unit_deliveries.units[unit_bought]
|
||||||
|
return total
|
||||||
|
|
||||||
|
|
||||||
class OffMapSpawn(ControlPoint):
|
class OffMapSpawn(ControlPoint):
|
||||||
def __init__(self, id: int, name: str, position: Point):
|
def __init__(self, id: int, name: str, position: Point):
|
||||||
|
|||||||
@ -57,7 +57,7 @@ class QBaseMenu2(QDialog):
|
|||||||
title = QLabel("<b>" + self.cp.name + "</b>")
|
title = QLabel("<b>" + self.cp.name + "</b>")
|
||||||
title.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
title.setAlignment(Qt.AlignLeft | Qt.AlignTop)
|
||||||
title.setProperty("style", "base-title")
|
title.setProperty("style", "base-title")
|
||||||
unitsPower = QLabel("{} / {} / Runway : {}".format(self.cp.base.total_planes, self.cp.base.total_armor,
|
unitsPower = QLabel("{} / {} / Runway : {}".format(self.cp.base.total_aircraft, self.cp.base.total_armor,
|
||||||
"Available" if self.cp.has_runway() else "Unavailable"))
|
"Available" if self.cp.has_runway() else "Unavailable"))
|
||||||
self.topLayout.addWidget(title)
|
self.topLayout.addWidget(title)
|
||||||
self.topLayout.addWidget(unitsPower)
|
self.topLayout.addWidget(unitsPower)
|
||||||
|
|||||||
@ -126,13 +126,6 @@ class QRecruitBehaviour:
|
|||||||
QRecruitBehaviour.BUDGET_FORMAT.format(self.budget))
|
QRecruitBehaviour.BUDGET_FORMAT.format(self.budget))
|
||||||
|
|
||||||
def buy(self, unit_type):
|
def buy(self, unit_type):
|
||||||
|
|
||||||
if self.maximum_units > 0:
|
|
||||||
if self.total_units + 1 > self.maximum_units:
|
|
||||||
logging.info("Not enough space left !")
|
|
||||||
# TODO : display modal warning
|
|
||||||
return
|
|
||||||
|
|
||||||
price = db.PRICES[unit_type]
|
price = db.PRICES[unit_type]
|
||||||
if self.budget >= price:
|
if self.budget >= price:
|
||||||
self.pending_deliveries.deliver({unit_type: 1})
|
self.pending_deliveries.deliver({unit_type: 1})
|
||||||
@ -158,19 +151,6 @@ class QRecruitBehaviour:
|
|||||||
self._update_count_label(unit_type)
|
self._update_count_label(unit_type)
|
||||||
self.update_available_budget()
|
self.update_available_budget()
|
||||||
|
|
||||||
@property
|
|
||||||
def total_units(self):
|
|
||||||
total = 0
|
|
||||||
for unit_type in self.recruitables_types:
|
|
||||||
total += self.cp.base.total_units(unit_type)
|
|
||||||
|
|
||||||
if self.pending_deliveries:
|
|
||||||
for unit_bought in self.pending_deliveries.units:
|
|
||||||
if db.unit_task(unit_bought) in self.recruitables_types:
|
|
||||||
total += self.pending_deliveries.units[unit_bought]
|
|
||||||
|
|
||||||
return total
|
|
||||||
|
|
||||||
def set_maximum_units(self, maximum_units):
|
def set_maximum_units(self, maximum_units):
|
||||||
"""
|
"""
|
||||||
Set the maximum number of units that can be bought
|
Set the maximum number of units that can be bought
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import logging
|
||||||
from typing import Optional, Set
|
from typing import Optional, Set
|
||||||
|
|
||||||
from PySide2.QtCore import Qt
|
from PySide2.QtCore import Qt
|
||||||
@ -37,7 +38,7 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
|||||||
self.bought_amount_labels = {}
|
self.bought_amount_labels = {}
|
||||||
self.existing_units_labels = {}
|
self.existing_units_labels = {}
|
||||||
|
|
||||||
self.hangar_status = QHangarStatus(self.total_units, self.cp.available_aircraft_slots)
|
self.hangar_status = QHangarStatus(self.total_aircraft, self.cp.available_aircraft_slots)
|
||||||
|
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
|
|
||||||
@ -80,8 +81,18 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
|||||||
self.setLayout(main_layout)
|
self.setLayout(main_layout)
|
||||||
|
|
||||||
def buy(self, unit_type):
|
def buy(self, unit_type):
|
||||||
|
if self.maximum_units > 0:
|
||||||
|
if self.total_aircraft + 1 > self.maximum_units:
|
||||||
|
logging.debug(f"No space for additional aircraft at {self.cp}.")
|
||||||
|
return
|
||||||
|
|
||||||
super().buy(unit_type)
|
super().buy(unit_type)
|
||||||
self.hangar_status.update_label(self.total_units, self.cp.available_aircraft_slots)
|
self.hangar_status.update_label(self.total_aircraft,
|
||||||
|
self.cp.available_aircraft_slots)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def total_aircraft(self) -> int:
|
||||||
|
return self.cp.expected_aircraft_next_turn
|
||||||
|
|
||||||
def sell(self, unit_type: UnitType):
|
def sell(self, unit_type: UnitType):
|
||||||
# Don't need to remove aircraft from the inventory if we're canceling
|
# Don't need to remove aircraft from the inventory if we're canceling
|
||||||
@ -99,7 +110,7 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
|||||||
"assigned to a mission?", QMessageBox.Ok)
|
"assigned to a mission?", QMessageBox.Ok)
|
||||||
return
|
return
|
||||||
super().sell(unit_type)
|
super().sell(unit_type)
|
||||||
self.hangar_status.update_label(self.total_units, self.cp.available_aircraft_slots)
|
self.hangar_status.update_label(self.total_aircraft, self.cp.available_aircraft_slots)
|
||||||
|
|
||||||
|
|
||||||
class QHangarStatus(QHBoxLayout):
|
class QHangarStatus(QHBoxLayout):
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user