mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
when a cp capture happens and the next cp has pending unit deliveries then they will be redeployed to the newly captured cp. The redeploy was drecreasing the num of pending unit deliveries for the old cp but was not removing them completly from the dict when all were removed
235 lines
7.5 KiB
Python
235 lines
7.5 KiB
Python
from __future__ import annotations
|
|
|
|
import logging
|
|
from PySide2.QtCore import Qt
|
|
from PySide2.QtWidgets import (
|
|
QGroupBox,
|
|
QHBoxLayout,
|
|
QLabel,
|
|
QPushButton,
|
|
QSizePolicy,
|
|
QSpacerItem,
|
|
QGridLayout,
|
|
QApplication,
|
|
)
|
|
|
|
from game.dcs.unittype import UnitType
|
|
from game.theater import ControlPoint
|
|
from game.unitdelivery import PendingUnitDeliveries
|
|
from qt_ui.models import GameModel
|
|
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
|
from qt_ui.windows.QUnitInfoWindow import QUnitInfoWindow
|
|
from enum import Enum
|
|
|
|
|
|
class RecruitType(Enum):
|
|
BUY = 0
|
|
SELL = 1
|
|
|
|
|
|
class PurchaseGroup(QGroupBox):
|
|
def __init__(self, unit_type: UnitType, recruiter: QRecruitBehaviour) -> None:
|
|
super().__init__()
|
|
self.unit_type = unit_type
|
|
self.recruiter = recruiter
|
|
|
|
self.setProperty("style", "buy-box")
|
|
self.setMaximumHeight(36)
|
|
self.setMinimumHeight(36)
|
|
layout = QHBoxLayout()
|
|
self.setLayout(layout)
|
|
|
|
self.sell_button = QPushButton("-")
|
|
self.sell_button.setProperty("style", "btn-sell")
|
|
self.sell_button.setDisabled(not recruiter.enable_sale(unit_type))
|
|
self.sell_button.setMinimumSize(16, 16)
|
|
self.sell_button.setMaximumSize(16, 16)
|
|
self.sell_button.setSizePolicy(
|
|
QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
|
)
|
|
|
|
self.sell_button.clicked.connect(
|
|
lambda: self.recruiter.recruit_handler(RecruitType.SELL, self.unit_type)
|
|
)
|
|
|
|
self.amount_bought = QLabel()
|
|
self.amount_bought.setSizePolicy(
|
|
QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
|
|
)
|
|
|
|
self.buy_button = QPushButton("+")
|
|
self.buy_button.setProperty("style", "btn-buy")
|
|
self.buy_button.setDisabled(not recruiter.enable_purchase(unit_type))
|
|
self.buy_button.setMinimumSize(16, 16)
|
|
self.buy_button.setMaximumSize(16, 16)
|
|
|
|
self.buy_button.clicked.connect(
|
|
lambda: self.recruiter.recruit_handler(RecruitType.BUY, self.unit_type)
|
|
)
|
|
self.buy_button.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
|
|
|
|
layout.addWidget(self.sell_button)
|
|
layout.addWidget(self.amount_bought)
|
|
layout.addWidget(self.buy_button)
|
|
|
|
self.update_state()
|
|
|
|
@property
|
|
def pending_units(self) -> int:
|
|
return self.recruiter.pending_deliveries.units.get(self.unit_type, 0)
|
|
|
|
def update_state(self) -> None:
|
|
self.buy_button.setEnabled(self.recruiter.enable_purchase(self.unit_type))
|
|
self.sell_button.setEnabled(self.recruiter.enable_sale(self.unit_type))
|
|
self.amount_bought.setText(f"<b>{self.pending_units}</b>")
|
|
|
|
|
|
class QRecruitBehaviour:
|
|
game_model: GameModel
|
|
cp: ControlPoint
|
|
purchase_groups: dict[UnitType, PurchaseGroup]
|
|
existing_units_labels = None
|
|
maximum_units = -1
|
|
BUDGET_FORMAT = "Available Budget: <b>${:.2f}M</b>"
|
|
|
|
def __init__(self) -> None:
|
|
self.existing_units_labels = {}
|
|
self.purchase_groups = {}
|
|
self.update_available_budget()
|
|
|
|
@property
|
|
def pending_deliveries(self) -> PendingUnitDeliveries:
|
|
return self.cp.pending_unit_deliveries
|
|
|
|
@property
|
|
def budget(self) -> float:
|
|
return self.game_model.game.blue.budget
|
|
|
|
@budget.setter
|
|
def budget(self, value: int) -> None:
|
|
self.game_model.game.blue.budget = value
|
|
|
|
def add_purchase_row(
|
|
self,
|
|
unit_type: UnitType,
|
|
layout: QGridLayout,
|
|
row: int,
|
|
) -> None:
|
|
exist = QGroupBox()
|
|
exist.setProperty("style", "buy-box")
|
|
exist.setMaximumHeight(36)
|
|
exist.setMinimumHeight(36)
|
|
existLayout = QHBoxLayout()
|
|
exist.setLayout(existLayout)
|
|
|
|
existing_units = self.cp.base.total_units_of_type(unit_type)
|
|
|
|
unitName = QLabel(f"<b>{unit_type.name}</b>")
|
|
unitName.setSizePolicy(
|
|
QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
|
)
|
|
|
|
existing_units = QLabel(str(existing_units))
|
|
existing_units.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
|
|
|
|
self.existing_units_labels[unit_type] = existing_units
|
|
|
|
price = QLabel(f"<b>$ {unit_type.price}</b> M")
|
|
price.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
|
|
|
|
purchase_group = PurchaseGroup(unit_type, self)
|
|
self.purchase_groups[unit_type] = purchase_group
|
|
|
|
info = QGroupBox()
|
|
info.setProperty("style", "buy-box")
|
|
info.setMaximumHeight(36)
|
|
info.setMinimumHeight(36)
|
|
infolayout = QHBoxLayout()
|
|
info.setLayout(infolayout)
|
|
|
|
unitInfo = QPushButton("i")
|
|
unitInfo.setProperty("style", "btn-info")
|
|
unitInfo.setMinimumSize(16, 16)
|
|
unitInfo.setMaximumSize(16, 16)
|
|
unitInfo.clicked.connect(lambda: self.info(unit_type))
|
|
unitInfo.setSizePolicy(QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed))
|
|
|
|
existLayout.addWidget(unitName)
|
|
existLayout.addItem(
|
|
QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum)
|
|
)
|
|
existLayout.addWidget(existing_units)
|
|
existLayout.addItem(
|
|
QSpacerItem(20, 0, QSizePolicy.Minimum, QSizePolicy.Minimum)
|
|
)
|
|
existLayout.addWidget(price)
|
|
|
|
infolayout.addWidget(unitInfo)
|
|
|
|
layout.addWidget(exist, row, 1)
|
|
layout.addWidget(purchase_group, row, 2)
|
|
layout.addWidget(info, row, 3)
|
|
|
|
def update_available_budget(self) -> None:
|
|
GameUpdateSignal.get_instance().updateBudget(self.game_model.game)
|
|
|
|
def recruit_handler(self, recruit_type: RecruitType, unit_type: UnitType) -> None:
|
|
# Lookup if Keyboard Modifiers were pressed
|
|
# Shift = 10 times
|
|
# CTRL = 5 Times
|
|
modifiers = QApplication.keyboardModifiers()
|
|
if modifiers == Qt.ShiftModifier:
|
|
amount = 10
|
|
elif modifiers == Qt.ControlModifier:
|
|
amount = 5
|
|
else:
|
|
amount = 1
|
|
|
|
for i in range(amount):
|
|
if recruit_type == RecruitType.SELL:
|
|
if not self.sell(unit_type):
|
|
return
|
|
elif recruit_type == RecruitType.BUY:
|
|
if not self.buy(unit_type):
|
|
return
|
|
|
|
def buy(self, unit_type: UnitType) -> bool:
|
|
|
|
if not self.enable_purchase(unit_type):
|
|
logging.error(f"Purchase of {unit_type} not allowed at {self.cp.name}")
|
|
return False
|
|
|
|
self.pending_deliveries.order({unit_type: 1})
|
|
self.budget -= unit_type.price
|
|
self.update_purchase_controls()
|
|
self.update_available_budget()
|
|
return True
|
|
|
|
def sell(self, unit_type: UnitType) -> bool:
|
|
if self.pending_deliveries.available_next_turn(unit_type) > 0:
|
|
self.budget += unit_type.price
|
|
self.pending_deliveries.sell({unit_type: 1})
|
|
self.update_purchase_controls()
|
|
self.update_available_budget()
|
|
return True
|
|
|
|
def update_purchase_controls(self) -> None:
|
|
for group in self.purchase_groups.values():
|
|
group.update_state()
|
|
|
|
def enable_purchase(self, unit_type: UnitType) -> bool:
|
|
return self.budget >= unit_type.price
|
|
|
|
def enable_sale(self, unit_type: UnitType) -> bool:
|
|
return True
|
|
|
|
def info(self, unit_type: UnitType) -> None:
|
|
self.info_window = QUnitInfoWindow(self.game_model.game, unit_type)
|
|
self.info_window.show()
|
|
|
|
def set_maximum_units(self, maximum_units):
|
|
"""
|
|
Set the maximum number of units that can be bought
|
|
"""
|
|
self.maximum_units = maximum_units
|