mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Also separate out SEAD and DEAD taskings. Some aircraft can DEAD but not SEAD. Also make the recruitment menu use the pretty names in the alphabetical sort func.
162 lines
5.8 KiB
Python
162 lines
5.8 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_pretty_name(self.game_model.game.player_country, 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):
|
|
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
|
|
# If we change our mind about selling, we want the aircraft to be put
|
|
# back in the inventory immediately.
|
|
elif 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)
|
|
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})")
|