mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
This feature allows you to cancel the sales of aircraft or ground vehicles if needed. Upon clicking the minus button, a count of sold units will be appended to the unit count. This count responds to both further presses of the minus button, and also to presses of the plus button. No further units will be requested for the next turn until all sold units have been re-bought. I've tested a bunch of different scenarios with this: - Selling and rebuying a unit - the budget increases and decreases as expected. - Selling one unit, buying a unit worth the new player budget, and then trying to rebuy the old unit - the old unit cannot be rebought until the budget has been freed up for it. - Closing the base window and re-opening it - the sold unit count is retained. - Ending the turn - the sold unit count is reset back to 0 as expected. Contributes to Khopa/dcs_liberation#365
162 lines
5.7 KiB
Python
162 lines
5.7 KiB
Python
import logging
|
|
from typing import Optional, Set, Type
|
|
|
|
from PySide2.QtCore import Qt
|
|
from PySide2.QtWidgets import (
|
|
QFrame,
|
|
QGridLayout,
|
|
QHBoxLayout,
|
|
QLabel,
|
|
QMessageBox,
|
|
QScrollArea,
|
|
QVBoxLayout,
|
|
QWidget,
|
|
)
|
|
from dcs.task import CAP, CAS
|
|
from dcs.unittype import FlyingType, UnitType
|
|
|
|
from game import db
|
|
from game.theater import ControlPoint
|
|
from qt_ui.models import GameModel
|
|
from qt_ui.uiconstants import ICONS
|
|
from qt_ui.windows.basemenu.QRecruitBehaviour import QRecruitBehaviour
|
|
|
|
|
|
class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
|
def __init__(self, cp: ControlPoint, game_model: GameModel) -> None:
|
|
QFrame.__init__(self)
|
|
self.cp = cp
|
|
self.game_model = game_model
|
|
|
|
self.bought_amount_labels = {}
|
|
self.existing_units_labels = {}
|
|
|
|
# Determine maximum number of aircrafts that can be bought
|
|
self.set_maximum_units(self.cp.total_aircraft_parking)
|
|
self.set_recruitable_types([CAP, CAS])
|
|
|
|
self.bought_amount_labels = {}
|
|
self.existing_units_labels = {}
|
|
|
|
self.hangar_status = QHangarStatus(game_model, self.cp)
|
|
|
|
self.init_ui()
|
|
|
|
def init_ui(self):
|
|
main_layout = QVBoxLayout()
|
|
|
|
tasks = [CAP, CAS]
|
|
|
|
scroll_content = QWidget()
|
|
task_box_layout = QGridLayout()
|
|
row = 0
|
|
|
|
unit_types: Set[Type[FlyingType]] = set()
|
|
for task in tasks:
|
|
units = db.find_unittype(task, self.game_model.game.player_name)
|
|
if not units:
|
|
continue
|
|
for unit in units:
|
|
if not issubclass(unit, FlyingType):
|
|
continue
|
|
if self.cp.is_carrier and unit not in db.CARRIER_CAPABLE:
|
|
continue
|
|
if self.cp.is_lha and unit not in db.LHA_CAPABLE:
|
|
continue
|
|
unit_types.add(unit)
|
|
|
|
sorted_units = sorted(unit_types, key=lambda u: db.unit_type_name_2(u))
|
|
for unit_type in sorted_units:
|
|
row = self.add_purchase_row(
|
|
unit_type, task_box_layout, row,
|
|
disabled=not self.cp.can_operate(unit_type))
|
|
stretch = QVBoxLayout()
|
|
stretch.addStretch()
|
|
task_box_layout.addLayout(stretch, row, 0)
|
|
|
|
scroll_content.setLayout(task_box_layout)
|
|
scroll = QScrollArea()
|
|
scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
|
scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
|
|
scroll.setWidgetResizable(True)
|
|
scroll.setWidget(scroll_content)
|
|
main_layout.addLayout(self.hangar_status)
|
|
main_layout.addWidget(scroll)
|
|
self.setLayout(main_layout)
|
|
|
|
def buy(self, unit_type):
|
|
global_inventory = self.game_model.game.aircraft_inventory
|
|
inventory = global_inventory.for_control_point(self.cp)
|
|
if self.maximum_units > 0:
|
|
if self.cp.unclaimed_parking(self.game_model.game) <= 0:
|
|
logging.debug(f"No space for additional aircraft at {self.cp}.")
|
|
QMessageBox.warning(
|
|
self, "No space for additional aircraft",
|
|
f"There is no parking space left at {self.cp.name} to accommodate another plane.", QMessageBox.Ok)
|
|
return
|
|
sold_count = self.cp.base.sold_units.get(unit_type)
|
|
if sold_count is None:
|
|
sold_count = 0
|
|
if sold_count > 0:
|
|
inventory.add_aircraft(unit_type, 1)
|
|
super().buy(unit_type)
|
|
self.hangar_status.update_label()
|
|
|
|
def sell(self, unit_type: UnitType):
|
|
# Don't need to remove aircraft from the inventory if we're canceling
|
|
# orders.
|
|
if self.pending_deliveries.units.get(unit_type, 0) <= 0:
|
|
global_inventory = self.game_model.game.aircraft_inventory
|
|
inventory = global_inventory.for_control_point(self.cp)
|
|
try:
|
|
inventory.remove_aircraft(unit_type, 1)
|
|
except ValueError:
|
|
QMessageBox.critical(
|
|
self, "Could not sell aircraft",
|
|
f"Attempted to sell one {unit_type.id} at {self.cp.name} "
|
|
"but none are available. Are all aircraft currently "
|
|
"assigned to a mission?", QMessageBox.Ok)
|
|
return
|
|
super().sell(unit_type)
|
|
self.hangar_status.update_label()
|
|
|
|
|
|
class QHangarStatus(QHBoxLayout):
|
|
|
|
def __init__(self, game_model: GameModel,
|
|
control_point: ControlPoint) -> None:
|
|
super().__init__()
|
|
self.game_model = game_model
|
|
self.control_point = control_point
|
|
|
|
self.icon = QLabel()
|
|
self.icon.setPixmap(ICONS["Hangar"])
|
|
self.text = QLabel("")
|
|
|
|
self.update_label()
|
|
self.addWidget(self.icon, Qt.AlignLeft)
|
|
self.addWidget(self.text, Qt.AlignLeft)
|
|
self.addStretch(50)
|
|
self.setAlignment(Qt.AlignLeft)
|
|
|
|
def update_label(self) -> None:
|
|
next_turn = self.control_point.expected_aircraft_next_turn(
|
|
self.game_model.game)
|
|
max_amount = self.control_point.total_aircraft_parking
|
|
|
|
components = [f"{next_turn.present} present"]
|
|
if next_turn.ordered > 0:
|
|
components.append(f"{next_turn.ordered} purchased")
|
|
elif next_turn.ordered < 0:
|
|
components.append(f"{-next_turn.ordered} sold")
|
|
|
|
transferring = next_turn.transferring
|
|
if transferring > 0:
|
|
components.append(f"{transferring} transferring in")
|
|
if transferring < 0:
|
|
components.append(f"{-transferring} transferring out")
|
|
|
|
details = ", ".join(components)
|
|
self.text.setText(
|
|
f"<strong>{next_turn.total}/{max_amount}</strong> ({details})")
|