mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Merge branch 'develop' into helipads
# Conflicts: # game/game.py # game/operation/operation.py # game/theater/conflicttheater.py # game/theater/controlpoint.py # gen/groundobjectsgen.py # resources/campaigns/golan_heights_lite.miz
This commit is contained in:
326
qt_ui/windows/AirWingConfigurationDialog.py
Normal file
326
qt_ui/windows/AirWingConfigurationDialog.py
Normal file
@@ -0,0 +1,326 @@
|
||||
from typing import Optional, Callable
|
||||
|
||||
from PySide2.QtCore import (
|
||||
QItemSelectionModel,
|
||||
QModelIndex,
|
||||
QSize,
|
||||
Qt,
|
||||
QItemSelection,
|
||||
Signal,
|
||||
)
|
||||
from PySide2.QtGui import QStandardItemModel, QStandardItem, QIcon
|
||||
from PySide2.QtWidgets import (
|
||||
QAbstractItemView,
|
||||
QDialog,
|
||||
QListView,
|
||||
QVBoxLayout,
|
||||
QGroupBox,
|
||||
QLabel,
|
||||
QWidget,
|
||||
QScrollArea,
|
||||
QLineEdit,
|
||||
QTextEdit,
|
||||
QCheckBox,
|
||||
QHBoxLayout,
|
||||
QStackedLayout,
|
||||
QTabWidget,
|
||||
)
|
||||
|
||||
from game import Game
|
||||
from game.dcs.aircrafttype import AircraftType
|
||||
from game.squadrons import Squadron, AirWing, Pilot
|
||||
from gen.flights.flight import FlightType
|
||||
from qt_ui.models import AirWingModel, SquadronModel
|
||||
from qt_ui.uiconstants import AIRCRAFT_ICONS
|
||||
from qt_ui.windows.AirWingDialog import SquadronDelegate
|
||||
from qt_ui.windows.SquadronDialog import SquadronDialog
|
||||
|
||||
|
||||
class SquadronList(QListView):
|
||||
"""List view for displaying the air wing's squadrons."""
|
||||
|
||||
def __init__(self, air_wing_model: AirWingModel) -> None:
|
||||
super().__init__()
|
||||
self.air_wing_model = air_wing_model
|
||||
self.dialog: Optional[SquadronDialog] = None
|
||||
|
||||
self.setIconSize(QSize(91, 24))
|
||||
self.setItemDelegate(SquadronDelegate(self.air_wing_model))
|
||||
self.setModel(self.air_wing_model)
|
||||
self.selectionModel().setCurrentIndex(
|
||||
self.air_wing_model.index(0, 0, QModelIndex()), QItemSelectionModel.Select
|
||||
)
|
||||
|
||||
# self.setIconSize(QSize(91, 24))
|
||||
self.setSelectionBehavior(QAbstractItemView.SelectItems)
|
||||
self.doubleClicked.connect(self.on_double_click)
|
||||
|
||||
def on_double_click(self, index: QModelIndex) -> None:
|
||||
if not index.isValid():
|
||||
return
|
||||
self.dialog = SquadronDialog(
|
||||
SquadronModel(self.air_wing_model.squadron_at_index(index)), self
|
||||
)
|
||||
self.dialog.show()
|
||||
|
||||
|
||||
class AllowedMissionTypeControls(QVBoxLayout):
|
||||
def __init__(self, squadron: Squadron) -> None:
|
||||
super().__init__()
|
||||
self.squadron = squadron
|
||||
self.allowed_mission_types = set()
|
||||
|
||||
self.addWidget(QLabel("Allowed mission types"))
|
||||
|
||||
def make_callback(toggled_task: FlightType) -> Callable[[bool], None]:
|
||||
def callback(checked: bool) -> None:
|
||||
self.on_toggled(toggled_task, checked)
|
||||
|
||||
return callback
|
||||
|
||||
for task in FlightType:
|
||||
enabled = task in squadron.mission_types
|
||||
if enabled:
|
||||
self.allowed_mission_types.add(task)
|
||||
checkbox = QCheckBox(text=task.value)
|
||||
checkbox.setChecked(enabled)
|
||||
checkbox.toggled.connect(make_callback(task))
|
||||
self.addWidget(checkbox)
|
||||
|
||||
self.addStretch()
|
||||
|
||||
def on_toggled(self, task: FlightType, checked: bool) -> None:
|
||||
if checked:
|
||||
self.allowed_mission_types.add(task)
|
||||
else:
|
||||
self.allowed_mission_types.remove(task)
|
||||
|
||||
|
||||
class SquadronConfigurationBox(QGroupBox):
|
||||
def __init__(self, squadron: Squadron) -> None:
|
||||
super().__init__()
|
||||
self.setCheckable(True)
|
||||
self.squadron = squadron
|
||||
self.reset_title()
|
||||
|
||||
columns = QHBoxLayout()
|
||||
self.setLayout(columns)
|
||||
|
||||
left_column = QVBoxLayout()
|
||||
columns.addLayout(left_column)
|
||||
|
||||
left_column.addWidget(QLabel("Name:"))
|
||||
self.name_edit = QLineEdit(squadron.name)
|
||||
self.name_edit.textChanged.connect(self.on_name_changed)
|
||||
left_column.addWidget(self.name_edit)
|
||||
|
||||
left_column.addWidget(QLabel("Nickname:"))
|
||||
self.nickname_edit = QLineEdit(squadron.nickname)
|
||||
self.nickname_edit.textChanged.connect(self.on_nickname_changed)
|
||||
left_column.addWidget(self.nickname_edit)
|
||||
|
||||
if squadron.player:
|
||||
player_label = QLabel(
|
||||
"Players (one per line, leave empty for an AI-only squadron):"
|
||||
)
|
||||
else:
|
||||
player_label = QLabel("Player slots not available for opfor")
|
||||
left_column.addWidget(player_label)
|
||||
|
||||
players = [p for p in squadron.pilot_pool if p.player]
|
||||
for player in players:
|
||||
squadron.pilot_pool.remove(player)
|
||||
if not squadron.player:
|
||||
players = []
|
||||
self.player_list = QTextEdit("<br />".join(p.name for p in players))
|
||||
self.player_list.setAcceptRichText(False)
|
||||
self.player_list.setEnabled(squadron.player)
|
||||
left_column.addWidget(self.player_list)
|
||||
|
||||
left_column.addStretch()
|
||||
|
||||
self.allowed_missions = AllowedMissionTypeControls(squadron)
|
||||
columns.addLayout(self.allowed_missions)
|
||||
|
||||
def on_name_changed(self, text: str) -> None:
|
||||
self.squadron.name = text
|
||||
self.reset_title()
|
||||
|
||||
def on_nickname_changed(self, text: str) -> None:
|
||||
self.squadron.nickname = text
|
||||
|
||||
def reset_title(self) -> None:
|
||||
self.setTitle(f"{self.squadron.name} - {self.squadron.aircraft}")
|
||||
|
||||
def apply(self) -> Squadron:
|
||||
player_names = self.player_list.toPlainText().splitlines()
|
||||
# Prepend player pilots so they get set active first.
|
||||
self.squadron.pilot_pool = [
|
||||
Pilot(n, player=True) for n in player_names
|
||||
] + self.squadron.pilot_pool
|
||||
self.squadron.mission_types = tuple(self.allowed_missions.allowed_mission_types)
|
||||
return self.squadron
|
||||
|
||||
|
||||
class SquadronConfigurationLayout(QVBoxLayout):
|
||||
def __init__(self, squadrons: list[Squadron]) -> None:
|
||||
super().__init__()
|
||||
self.squadron_configs = []
|
||||
for squadron in squadrons:
|
||||
squadron_config = SquadronConfigurationBox(squadron)
|
||||
self.squadron_configs.append(squadron_config)
|
||||
self.addWidget(squadron_config)
|
||||
|
||||
def apply(self) -> list[Squadron]:
|
||||
keep_squadrons = []
|
||||
for squadron_config in self.squadron_configs:
|
||||
if squadron_config.isChecked():
|
||||
keep_squadrons.append(squadron_config.apply())
|
||||
return keep_squadrons
|
||||
|
||||
|
||||
class AircraftSquadronsPage(QWidget):
|
||||
def __init__(self, squadrons: list[Squadron]) -> None:
|
||||
super().__init__()
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
self.squadrons_config = SquadronConfigurationLayout(squadrons)
|
||||
|
||||
scrolling_widget = QWidget()
|
||||
scrolling_widget.setLayout(self.squadrons_config)
|
||||
|
||||
scrolling_area = QScrollArea()
|
||||
scrolling_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
|
||||
scrolling_area.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
|
||||
scrolling_area.setWidgetResizable(True)
|
||||
scrolling_area.setWidget(scrolling_widget)
|
||||
|
||||
layout.addWidget(scrolling_area)
|
||||
|
||||
def apply(self) -> list[Squadron]:
|
||||
return self.squadrons_config.apply()
|
||||
|
||||
|
||||
class AircraftSquadronsPanel(QStackedLayout):
|
||||
def __init__(self, air_wing: AirWing) -> None:
|
||||
super().__init__()
|
||||
self.air_wing = air_wing
|
||||
self.squadrons_pages: dict[AircraftType, AircraftSquadronsPage] = {}
|
||||
for aircraft, squadrons in self.air_wing.squadrons.items():
|
||||
page = AircraftSquadronsPage(squadrons)
|
||||
self.addWidget(page)
|
||||
self.squadrons_pages[aircraft] = page
|
||||
|
||||
def apply(self) -> None:
|
||||
for aircraft, page in self.squadrons_pages.items():
|
||||
self.air_wing.squadrons[aircraft] = page.apply()
|
||||
|
||||
|
||||
class AircraftTypeList(QListView):
|
||||
page_index_changed = Signal(int)
|
||||
|
||||
def __init__(self, air_wing: AirWing) -> None:
|
||||
super().__init__()
|
||||
self.setIconSize(QSize(91, 24))
|
||||
self.setMinimumWidth(300)
|
||||
|
||||
model = QStandardItemModel(self)
|
||||
self.setModel(model)
|
||||
|
||||
self.selectionModel().setCurrentIndex(
|
||||
model.index(0, 0), QItemSelectionModel.Select
|
||||
)
|
||||
self.selectionModel().selectionChanged.connect(self.on_selection_changed)
|
||||
for aircraft in air_wing.squadrons:
|
||||
aircraft_item = QStandardItem(aircraft.name)
|
||||
icon = self.icon_for(aircraft)
|
||||
if icon is not None:
|
||||
aircraft_item.setIcon(icon)
|
||||
aircraft_item.setEditable(False)
|
||||
aircraft_item.setSelectable(True)
|
||||
model.appendRow(aircraft_item)
|
||||
|
||||
def on_selection_changed(
|
||||
self, selected: QItemSelection, _deselected: QItemSelection
|
||||
) -> None:
|
||||
indexes = selected.indexes()
|
||||
if len(indexes) > 1:
|
||||
raise RuntimeError("Aircraft list should not allow multi-selection")
|
||||
if not indexes:
|
||||
return
|
||||
self.page_index_changed.emit(indexes[0].row())
|
||||
|
||||
@staticmethod
|
||||
def icon_for(aircraft: AircraftType) -> Optional[QIcon]:
|
||||
name = aircraft.dcs_id
|
||||
if name in AIRCRAFT_ICONS:
|
||||
return QIcon(AIRCRAFT_ICONS[name])
|
||||
return None
|
||||
|
||||
|
||||
class AirWingConfigurationTab(QWidget):
|
||||
def __init__(self, air_wing: AirWing) -> None:
|
||||
super().__init__()
|
||||
|
||||
layout = QHBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
type_list = AircraftTypeList(air_wing)
|
||||
type_list.page_index_changed.connect(self.on_aircraft_changed)
|
||||
layout.addWidget(type_list)
|
||||
|
||||
self.squadrons_panel = AircraftSquadronsPanel(air_wing)
|
||||
layout.addLayout(self.squadrons_panel)
|
||||
|
||||
def apply(self) -> None:
|
||||
self.squadrons_panel.apply()
|
||||
|
||||
def on_aircraft_changed(self, index: QModelIndex) -> None:
|
||||
self.squadrons_panel.setCurrentIndex(index)
|
||||
|
||||
|
||||
class AirWingConfigurationDialog(QDialog):
|
||||
"""Dialog window for air wing configuration."""
|
||||
|
||||
def __init__(self, game: Game, parent) -> None:
|
||||
super().__init__(parent)
|
||||
self.setMinimumSize(500, 800)
|
||||
self.setWindowTitle(f"Air Wing Configuration")
|
||||
# TODO: self.setWindowIcon()
|
||||
|
||||
layout = QVBoxLayout()
|
||||
self.setLayout(layout)
|
||||
|
||||
doc_url = (
|
||||
"https://github.com/dcs-liberation/dcs_liberation/wiki/Squadrons-and-pilots"
|
||||
)
|
||||
doc_label = QLabel(
|
||||
"Use this opportunity to customize the squadrons available to your "
|
||||
"coalition. <strong>This is your only opportunity to make changes.</strong>"
|
||||
"<br /><br />"
|
||||
"To accept your changes and continue, close this window.<br />"
|
||||
"<br />"
|
||||
"To remove a squadron from the game, uncheck the box in the title. New "
|
||||
"squadrons cannot be added via the UI at this time. To add a custom "
|
||||
"squadron,<br />"
|
||||
f'see <a style="color:#ffffff" href="{doc_url}">the wiki</a>.'
|
||||
)
|
||||
|
||||
doc_label.setOpenExternalLinks(True)
|
||||
layout.addWidget(doc_label)
|
||||
|
||||
tab_widget = QTabWidget()
|
||||
layout.addWidget(tab_widget)
|
||||
|
||||
self.tabs = []
|
||||
for coalition in game.coalitions:
|
||||
coalition_tab = AirWingConfigurationTab(coalition.air_wing)
|
||||
name = "Blue" if coalition.player else "Red"
|
||||
tab_widget.addTab(coalition_tab, name)
|
||||
self.tabs.append(coalition_tab)
|
||||
|
||||
def reject(self) -> None:
|
||||
for tab in self.tabs:
|
||||
tab.apply()
|
||||
super().reject()
|
||||
@@ -3,12 +3,7 @@ from __future__ import annotations
|
||||
from dataclasses import dataclass
|
||||
from typing import Optional, Iterator
|
||||
|
||||
from PySide2.QtCore import (
|
||||
QItemSelectionModel,
|
||||
QModelIndex,
|
||||
Qt,
|
||||
QSize,
|
||||
)
|
||||
from PySide2.QtCore import QItemSelectionModel, QModelIndex, QSize
|
||||
from PySide2.QtWidgets import (
|
||||
QAbstractItemView,
|
||||
QCheckBox,
|
||||
@@ -183,7 +178,7 @@ class AirInventoryView(QWidget):
|
||||
self.table.setSortingEnabled(True)
|
||||
|
||||
def iter_allocated_aircraft(self) -> Iterator[AircraftInventoryData]:
|
||||
for package in self.game_model.game.blue_ato.packages:
|
||||
for package in self.game_model.game.blue.ato.packages:
|
||||
for flight in package.flights:
|
||||
yield from AircraftInventoryData.from_flight(flight)
|
||||
|
||||
|
||||
@@ -36,6 +36,8 @@ from qt_ui.windows.preferences.QLiberationPreferencesWindow import (
|
||||
)
|
||||
from qt_ui.windows.settings.QSettingsWindow import QSettingsWindow
|
||||
from qt_ui.windows.stats.QStatsWindow import QStatsWindow
|
||||
from qt_ui.windows.notes.QNotesWindow import QNotesWindow
|
||||
from qt_ui.windows.logs.QLogsWindow import QLogsWindow
|
||||
|
||||
|
||||
class QLiberationWindow(QMainWindow):
|
||||
@@ -150,6 +152,9 @@ class QLiberationWindow(QMainWindow):
|
||||
)
|
||||
)
|
||||
|
||||
self.openLogsAction = QAction("Show &logs", self)
|
||||
self.openLogsAction.triggered.connect(self.showLogsDialog)
|
||||
|
||||
self.openSettingsAction = QAction("Settings", self)
|
||||
self.openSettingsAction.setIcon(CONST.ICONS["Settings"])
|
||||
self.openSettingsAction.triggered.connect(self.showSettingsDialog)
|
||||
@@ -158,6 +163,10 @@ class QLiberationWindow(QMainWindow):
|
||||
self.openStatsAction.setIcon(CONST.ICONS["Statistics"])
|
||||
self.openStatsAction.triggered.connect(self.showStatsDialog)
|
||||
|
||||
self.openNotesAction = QAction("Notes", self)
|
||||
self.openNotesAction.setIcon(CONST.ICONS["Notes"])
|
||||
self.openNotesAction.triggered.connect(self.showNotesDialog)
|
||||
|
||||
def initToolbar(self):
|
||||
self.tool_bar = self.addToolBar("File")
|
||||
self.tool_bar.addAction(self.newGameAction)
|
||||
@@ -171,6 +180,7 @@ class QLiberationWindow(QMainWindow):
|
||||
self.actions_bar = self.addToolBar("Actions")
|
||||
self.actions_bar.addAction(self.openSettingsAction)
|
||||
self.actions_bar.addAction(self.openStatsAction)
|
||||
self.actions_bar.addAction(self.openNotesAction)
|
||||
|
||||
def initMenuBar(self):
|
||||
self.menu = self.menuBar()
|
||||
@@ -204,6 +214,7 @@ class QLiberationWindow(QMainWindow):
|
||||
help_menu.addAction(
|
||||
"Report an &issue", lambda: webbrowser.open_new_tab(URLS["Issues"])
|
||||
)
|
||||
help_menu.addAction(self.openLogsAction)
|
||||
|
||||
help_menu.addSeparator()
|
||||
help_menu.addAction(self.showAboutDialogAction)
|
||||
@@ -351,6 +362,14 @@ class QLiberationWindow(QMainWindow):
|
||||
self.dialog = QStatsWindow(self.game)
|
||||
self.dialog.show()
|
||||
|
||||
def showNotesDialog(self):
|
||||
self.dialog = QNotesWindow(self.game)
|
||||
self.dialog.show()
|
||||
|
||||
def showLogsDialog(self):
|
||||
self.dialog = QLogsWindow()
|
||||
self.dialog.show()
|
||||
|
||||
def onDebriefing(self, debrief: Debriefing):
|
||||
logging.info("On Debriefing")
|
||||
self.debriefing = QDebriefingWindow(debrief)
|
||||
|
||||
@@ -94,6 +94,9 @@ class QUnitInfoWindow(QDialog):
|
||||
self.details_text = QTextBrowser()
|
||||
self.details_text.setProperty("style", "info-desc")
|
||||
self.details_text.setText(unit_type.description)
|
||||
self.details_text.setOpenExternalLinks(
|
||||
True
|
||||
) # in aircrafttype.py and groundunittype.py, for the descriptions, if No Data. including a google search link
|
||||
self.gridLayout.addWidget(self.details_text, 3, 0)
|
||||
|
||||
self.layout.addLayout(self.gridLayout, 1, 0)
|
||||
|
||||
@@ -73,11 +73,15 @@ class DepartingConvoysList(QFrame):
|
||||
task_box_layout = QGridLayout()
|
||||
scroll_content.setLayout(task_box_layout)
|
||||
|
||||
for convoy in game_model.game.transfers.convoys.departing_from(cp):
|
||||
for convoy in game_model.game.coalition_for(
|
||||
cp.captured
|
||||
).transfers.convoys.departing_from(cp):
|
||||
group_info = DepartingConvoyInfo(convoy)
|
||||
task_box_layout.addWidget(group_info)
|
||||
|
||||
for cargo_ship in game_model.game.transfers.cargo_ships.departing_from(cp):
|
||||
for cargo_ship in game_model.game.coalition_for(
|
||||
cp.captured
|
||||
).transfers.cargo_ships.departing_from(cp):
|
||||
group_info = DepartingConvoyInfo(cargo_ship)
|
||||
task_box_layout.addWidget(group_info)
|
||||
|
||||
|
||||
@@ -108,7 +108,7 @@ class QBaseMenu2(QDialog):
|
||||
capture_button.clicked.connect(self.cheat_capture)
|
||||
|
||||
self.budget_display = QLabel(
|
||||
QRecruitBehaviour.BUDGET_FORMAT.format(self.game_model.game.budget)
|
||||
QRecruitBehaviour.BUDGET_FORMAT.format(self.game_model.game.blue.budget)
|
||||
)
|
||||
self.budget_display.setAlignment(Qt.AlignRight | Qt.AlignBottom)
|
||||
self.budget_display.setProperty("style", "budget-label")
|
||||
@@ -124,7 +124,6 @@ class QBaseMenu2(QDialog):
|
||||
self.cp.capture(self.game_model.game, for_player=not self.cp.captured)
|
||||
# Reinitialized ground planners and the like. The ATO needs to be reset because
|
||||
# missions planned against the flipped base are no longer valid.
|
||||
self.game_model.game.reset_ato()
|
||||
self.game_model.game.initialize_turn()
|
||||
GameUpdateSignal.get_instance().updateGame(self.game_model.game)
|
||||
|
||||
@@ -140,7 +139,7 @@ class QBaseMenu2(QDialog):
|
||||
|
||||
@property
|
||||
def can_afford_runway_repair(self) -> bool:
|
||||
return self.game_model.game.budget >= db.RUNWAY_REPAIR_COST
|
||||
return self.game_model.game.blue.budget >= db.RUNWAY_REPAIR_COST
|
||||
|
||||
def begin_runway_repair(self) -> None:
|
||||
if not self.can_afford_runway_repair:
|
||||
@@ -148,7 +147,7 @@ class QBaseMenu2(QDialog):
|
||||
self,
|
||||
"Cannot repair runway",
|
||||
f"Runway repair costs ${db.RUNWAY_REPAIR_COST}M but you have "
|
||||
f"only ${self.game_model.game.budget}M available.",
|
||||
f"only ${self.game_model.game.blue.budget}M available.",
|
||||
QMessageBox.Ok,
|
||||
)
|
||||
return
|
||||
@@ -162,7 +161,7 @@ class QBaseMenu2(QDialog):
|
||||
return
|
||||
|
||||
self.cp.begin_runway_repair()
|
||||
self.game_model.game.budget -= db.RUNWAY_REPAIR_COST
|
||||
self.game_model.game.blue.budget -= db.RUNWAY_REPAIR_COST
|
||||
self.update_repair_button()
|
||||
self.update_intel_summary()
|
||||
GameUpdateSignal.get_instance().updateGame(self.game_model.game)
|
||||
@@ -196,7 +195,9 @@ class QBaseMenu2(QDialog):
|
||||
ground_unit_limit = self.cp.frontline_unit_count_limit
|
||||
deployable_unit_info = ""
|
||||
|
||||
allocated = self.cp.allocated_ground_units(self.game_model.game.transfers)
|
||||
allocated = self.cp.allocated_ground_units(
|
||||
self.game_model.game.coalition_for(self.cp.captured).transfers
|
||||
)
|
||||
unit_overage = max(
|
||||
allocated.total_present - self.cp.frontline_unit_count_limit, 0
|
||||
)
|
||||
@@ -256,4 +257,6 @@ class QBaseMenu2(QDialog):
|
||||
NewUnitTransferDialog(self.game_model, self.cp, parent=self.window()).show()
|
||||
|
||||
def update_budget(self, game: Game) -> None:
|
||||
self.budget_display.setText(QRecruitBehaviour.BUDGET_FORMAT.format(game.budget))
|
||||
self.budget_display.setText(
|
||||
QRecruitBehaviour.BUDGET_FORMAT.format(game.blue.budget)
|
||||
)
|
||||
|
||||
@@ -103,11 +103,11 @@ class QRecruitBehaviour:
|
||||
|
||||
@property
|
||||
def budget(self) -> float:
|
||||
return self.game_model.game.budget
|
||||
return self.game_model.game.blue.budget
|
||||
|
||||
@budget.setter
|
||||
def budget(self, value: int) -> None:
|
||||
self.game_model.game.budget = value
|
||||
self.game_model.game.blue.budget = value
|
||||
|
||||
def add_purchase_row(
|
||||
self,
|
||||
@@ -209,8 +209,6 @@ class QRecruitBehaviour:
|
||||
if self.pending_deliveries.available_next_turn(unit_type) > 0:
|
||||
self.budget += unit_type.price
|
||||
self.pending_deliveries.sell({unit_type: 1})
|
||||
if self.pending_deliveries.units[unit_type] == 0:
|
||||
del self.pending_deliveries.units[unit_type]
|
||||
self.update_purchase_controls()
|
||||
self.update_available_budget()
|
||||
return True
|
||||
|
||||
@@ -45,7 +45,7 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
row = 0
|
||||
|
||||
unit_types: Set[AircraftType] = set()
|
||||
for unit_type in self.game_model.game.player_faction.aircrafts:
|
||||
for unit_type in self.game_model.game.blue.faction.aircrafts:
|
||||
if self.cp.is_carrier and not unit_type.carrier_capable:
|
||||
continue
|
||||
if self.cp.is_lha and not unit_type.lha_capable:
|
||||
|
||||
@@ -56,6 +56,5 @@ class QGroundForcesStrategy(QGroupBox):
|
||||
self.cp.base.affect_strength(amount)
|
||||
enemy_point.base.affect_strength(-amount)
|
||||
# Clear the ATO to replan missions affected by the front line.
|
||||
self.game.reset_ato()
|
||||
self.game.initialize_turn()
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
|
||||
@@ -57,10 +57,7 @@ class FinancesLayout(QGridLayout):
|
||||
middle=f"Income multiplier: {income.multiplier:.1f}",
|
||||
right=f"<b>{income.total}M</b>",
|
||||
)
|
||||
if player:
|
||||
budget = game.budget
|
||||
else:
|
||||
budget = game.enemy_budget
|
||||
budget = game.coalition_for(player).budget
|
||||
self.add_row(middle="Balance", right=f"<b>{budget}M</b>")
|
||||
self.setRowStretch(next(self.row), 1)
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import logging
|
||||
from typing import List, Optional
|
||||
|
||||
from PySide2 import QtCore
|
||||
from PySide2.QtGui import Qt
|
||||
from PySide2.QtWidgets import (
|
||||
QComboBox,
|
||||
@@ -238,8 +237,8 @@ class QGroundObjectMenu(QDialog):
|
||||
self.total_value = total_value
|
||||
|
||||
def repair_unit(self, group, unit, price):
|
||||
if self.game.budget > price:
|
||||
self.game.budget -= price
|
||||
if self.game.blue.budget > price:
|
||||
self.game.blue.budget -= price
|
||||
group.units_losts = [u for u in group.units_losts if u.id != unit.id]
|
||||
group.units.append(unit)
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
@@ -257,8 +256,16 @@ class QGroundObjectMenu(QDialog):
|
||||
|
||||
def sell_all(self):
|
||||
self.update_total_value()
|
||||
self.game.budget = self.game.budget + self.total_value
|
||||
self.game.blue.budget = self.game.blue.budget + self.total_value
|
||||
self.ground_object.groups = []
|
||||
|
||||
# Replan if the tgo was a target of the redfor
|
||||
if any(
|
||||
package.target == self.ground_object
|
||||
for package in self.game.ato_for(player=False).packages
|
||||
):
|
||||
self.game.initialize_turn(for_red=True, for_blue=False)
|
||||
|
||||
self.do_refresh_layout()
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
|
||||
@@ -299,14 +306,17 @@ class QBuyGroupForGroundObjectDialog(QDialog):
|
||||
self.buySamBox = QGroupBox("Buy SAM site :")
|
||||
self.buyArmorBox = QGroupBox("Buy defensive position :")
|
||||
|
||||
faction = self.game.player_faction
|
||||
faction = self.game.blue.faction
|
||||
|
||||
# Sams
|
||||
|
||||
possible_sams = get_faction_possible_sams_generator(faction)
|
||||
for sam in possible_sams:
|
||||
# Pre Generate SAM to get the real price
|
||||
generator = sam(self.game, self.ground_object)
|
||||
generator.generate()
|
||||
self.samCombo.addItem(
|
||||
sam.name + " [$" + str(sam.price) + "M]", userData=sam
|
||||
generator.name + " [$" + str(generator.price) + "M]", userData=generator
|
||||
)
|
||||
self.samCombo.currentIndexChanged.connect(self.samComboChanged)
|
||||
|
||||
@@ -331,8 +341,12 @@ class QBuyGroupForGroundObjectDialog(QDialog):
|
||||
buy_ewr_layout.addWidget(self.ewr_selector, 0, 1, alignment=Qt.AlignRight)
|
||||
ewr_types = get_faction_possible_ewrs_generator(faction)
|
||||
for ewr_type in ewr_types:
|
||||
# Pre Generate to get the real price
|
||||
generator = ewr_type(self.game, self.ground_object)
|
||||
generator.generate()
|
||||
self.ewr_selector.addItem(
|
||||
f"{ewr_type.name()} [${ewr_type.price()}M]", ewr_type
|
||||
generator.name() + " [$" + str(generator.price) + "M]",
|
||||
userData=generator,
|
||||
)
|
||||
self.ewr_selector.currentIndexChanged.connect(self.on_ewr_selection_changed)
|
||||
|
||||
@@ -402,7 +416,7 @@ class QBuyGroupForGroundObjectDialog(QDialog):
|
||||
def on_ewr_selection_changed(self, index):
|
||||
ewr = self.ewr_selector.itemData(index)
|
||||
self.buy_ewr_button.setText(
|
||||
f"Buy [${ewr.price()}M][-${self.current_group_value}M]"
|
||||
f"Buy [${ewr.price}M][-${self.current_group_value}M]"
|
||||
)
|
||||
|
||||
def armorComboChanged(self, index):
|
||||
@@ -419,12 +433,12 @@ class QBuyGroupForGroundObjectDialog(QDialog):
|
||||
logging.info("Buying Armor ")
|
||||
utype = self.buyArmorCombo.itemData(self.buyArmorCombo.currentIndex())
|
||||
price = utype.price * self.amount.value() - self.current_group_value
|
||||
if price > self.game.budget:
|
||||
if price > self.game.blue.budget:
|
||||
self.error_money()
|
||||
self.close()
|
||||
return
|
||||
else:
|
||||
self.game.budget -= price
|
||||
self.game.blue.budget -= price
|
||||
|
||||
# Generate Armor
|
||||
group = generate_armor_group_of_type_and_size(
|
||||
@@ -432,36 +446,40 @@ class QBuyGroupForGroundObjectDialog(QDialog):
|
||||
)
|
||||
self.ground_object.groups = [group]
|
||||
|
||||
# Replan redfor missions
|
||||
self.game.initialize_turn(for_red=True, for_blue=False)
|
||||
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
|
||||
def buySam(self):
|
||||
sam_generator = self.samCombo.itemData(self.samCombo.currentIndex())
|
||||
price = sam_generator.price - self.current_group_value
|
||||
if price > self.game.budget:
|
||||
if price > self.game.blue.budget:
|
||||
self.error_money()
|
||||
return
|
||||
else:
|
||||
self.game.budget -= price
|
||||
self.game.blue.budget -= price
|
||||
|
||||
# Generate SAM
|
||||
generator = sam_generator(self.game, self.ground_object)
|
||||
generator.generate()
|
||||
self.ground_object.groups = list(generator.groups)
|
||||
self.ground_object.groups = list(sam_generator.groups)
|
||||
|
||||
# Replan redfor missions
|
||||
self.game.initialize_turn(for_red=True, for_blue=False)
|
||||
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
|
||||
def buy_ewr(self):
|
||||
ewr_generator = self.ewr_selector.itemData(self.ewr_selector.currentIndex())
|
||||
price = ewr_generator.price() - self.current_group_value
|
||||
if price > self.game.budget:
|
||||
price = ewr_generator.price - self.current_group_value
|
||||
if price > self.game.blue.budget:
|
||||
self.error_money()
|
||||
return
|
||||
else:
|
||||
self.game.budget -= price
|
||||
self.game.blue.budget -= price
|
||||
|
||||
generator = ewr_generator(self.game, self.ground_object)
|
||||
generator.generate()
|
||||
self.ground_object.groups = [generator.vg]
|
||||
self.ground_object.groups = [ewr_generator.vg]
|
||||
|
||||
# Replan redfor missions
|
||||
self.game.initialize_turn(for_red=True, for_blue=False)
|
||||
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
|
||||
|
||||
67
qt_ui/windows/logs/QLogsWindow.py
Normal file
67
qt_ui/windows/logs/QLogsWindow.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import logging
|
||||
import typing
|
||||
|
||||
from PySide2.QtWidgets import (
|
||||
QDialog,
|
||||
QPlainTextEdit,
|
||||
QVBoxLayout,
|
||||
QPushButton,
|
||||
)
|
||||
from PySide2.QtGui import QTextCursor
|
||||
|
||||
from qt_ui.logging_handler import HookableInMemoryHandler
|
||||
|
||||
|
||||
class QLogsWindow(QDialog):
|
||||
vbox: QVBoxLayout
|
||||
textbox: QPlainTextEdit
|
||||
clear_button: QPushButton
|
||||
_logging_handler: typing.Optional[HookableInMemoryHandler]
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
|
||||
self.setWindowTitle("Logs")
|
||||
self.setMinimumSize(400, 100)
|
||||
self.resize(1000, 450)
|
||||
|
||||
self.vbox = QVBoxLayout()
|
||||
self.setLayout(self.vbox)
|
||||
|
||||
self.textbox = QPlainTextEdit(self)
|
||||
self.textbox.setReadOnly(True)
|
||||
self.textbox.setLineWrapMode(QPlainTextEdit.LineWrapMode.NoWrap)
|
||||
self.textbox.move(10, 10)
|
||||
self.textbox.resize(1000, 450)
|
||||
self.textbox.setStyleSheet(
|
||||
"font-family: 'Courier New', monospace; background: #1D2731;"
|
||||
)
|
||||
self.vbox.addWidget(self.textbox)
|
||||
|
||||
self.clear_button = QPushButton(self)
|
||||
self.clear_button.setText("CLEAR")
|
||||
self.clear_button.setProperty("style", "btn-primary")
|
||||
self.clear_button.clicked.connect(self.clearLogs)
|
||||
self.vbox.addWidget(self.clear_button)
|
||||
|
||||
self._logging_handler = None
|
||||
logger = logging.getLogger()
|
||||
for handler in logger.handlers:
|
||||
if isinstance(handler, HookableInMemoryHandler):
|
||||
self._logging_handler = handler
|
||||
break
|
||||
if self._logging_handler is not None:
|
||||
self.textbox.setPlainText(self._logging_handler.log)
|
||||
self.textbox.moveCursor(QTextCursor.End)
|
||||
self._logging_handler.setHook(self.appendLog)
|
||||
else:
|
||||
self.textbox.setPlainText("WARNING: logging not initialized!")
|
||||
|
||||
def clearLogs(self) -> None:
|
||||
if self._logging_handler is not None:
|
||||
self._logging_handler.clearLog()
|
||||
self.textbox.setPlainText("")
|
||||
|
||||
def appendLog(self, msg: str):
|
||||
self.textbox.appendPlainText(msg)
|
||||
self.textbox.moveCursor(QTextCursor.End)
|
||||
@@ -180,7 +180,7 @@ class QPackageDialog(QDialog):
|
||||
self.game.aircraft_inventory.claim_for_flight(flight)
|
||||
self.package_model.add_flight(flight)
|
||||
planner = FlightPlanBuilder(
|
||||
self.game, self.package_model.package, is_player=True
|
||||
self.package_model.package, self.game.blue, self.game.theater
|
||||
)
|
||||
try:
|
||||
planner.populate_flight_plan(flight)
|
||||
|
||||
@@ -38,7 +38,7 @@ class QFlightCreator(QDialog):
|
||||
self.game = game
|
||||
self.package = package
|
||||
self.custom_name_text = None
|
||||
self.country = self.game.player_country
|
||||
self.country = self.game.blue.country_name
|
||||
|
||||
self.setWindowTitle("Create flight")
|
||||
self.setWindowIcon(EVENT_ICONS["strike"])
|
||||
@@ -52,7 +52,6 @@ class QFlightCreator(QDialog):
|
||||
|
||||
self.aircraft_selector = QAircraftTypeSelector(
|
||||
self.game.aircraft_inventory.available_types_for_player,
|
||||
self.game.player_country,
|
||||
self.task_selector.currentData(),
|
||||
)
|
||||
self.aircraft_selector.setCurrentIndex(0)
|
||||
|
||||
@@ -47,8 +47,20 @@ class QFlightPayloadTab(QFrame):
|
||||
def reload_from_flight(self) -> None:
|
||||
self.loadout_selector.setCurrentText(self.flight.loadout.name)
|
||||
|
||||
def loadout_at(self, index: int) -> Loadout:
|
||||
loadout = self.loadout_selector.itemData(index)
|
||||
if loadout is None:
|
||||
return Loadout.empty_loadout()
|
||||
return loadout
|
||||
|
||||
def current_loadout(self) -> Loadout:
|
||||
loadout = self.loadout_selector.currentData()
|
||||
if loadout is None:
|
||||
return Loadout.empty_loadout()
|
||||
return loadout
|
||||
|
||||
def on_new_loadout(self, index: int) -> None:
|
||||
self.flight.loadout = self.loadout_selector.itemData(index)
|
||||
self.flight.loadout = self.loadout_at(index)
|
||||
self.payload_editor.reset_pylons()
|
||||
|
||||
def on_custom_toggled(self, use_custom: bool) -> None:
|
||||
@@ -56,5 +68,5 @@ class QFlightPayloadTab(QFrame):
|
||||
if use_custom:
|
||||
self.flight.loadout = self.flight.loadout.derive_custom("Custom")
|
||||
else:
|
||||
self.flight.loadout = self.loadout_selector.currentData()
|
||||
self.flight.loadout = self.current_loadout()
|
||||
self.payload_editor.reset_pylons()
|
||||
|
||||
@@ -56,7 +56,7 @@ class QPylonEditor(QComboBox):
|
||||
#
|
||||
# A similar hack exists in Pylon to support forcibly equipping this even when
|
||||
# it's not known to be compatible.
|
||||
if weapon.cls_id == "<CLEAN>":
|
||||
if weapon.clsid == "<CLEAN>":
|
||||
if not self.has_added_clean_item:
|
||||
self.addItem("Clean", weapon)
|
||||
self.has_added_clean_item = True
|
||||
|
||||
@@ -100,6 +100,6 @@ class FlightAirfieldDisplay(QGroupBox):
|
||||
|
||||
def update_flight_plan(self) -> None:
|
||||
planner = FlightPlanBuilder(
|
||||
self.game, self.package_model.package, is_player=True
|
||||
self.package_model.package, self.game.blue, self.game.theater
|
||||
)
|
||||
planner.populate_flight_plan(self.flight)
|
||||
|
||||
@@ -37,7 +37,7 @@ class QFlightWaypointTab(QFrame):
|
||||
self.game = game
|
||||
self.package = package
|
||||
self.flight = flight
|
||||
self.planner = FlightPlanBuilder(self.game, package, is_player=True)
|
||||
self.planner = FlightPlanBuilder(package, game.blue, game.theater)
|
||||
|
||||
self.flight_waypoint_list: Optional[QFlightWaypointList] = None
|
||||
self.rtb_waypoint: Optional[QPushButton] = None
|
||||
|
||||
@@ -15,6 +15,7 @@ from game.theater.start_generator import GameGenerator, GeneratorSettings, ModSe
|
||||
from game.factions.faction import Faction
|
||||
from qt_ui.widgets.QLiberationCalendar import QLiberationCalendar
|
||||
from qt_ui.widgets.spinsliders import TenthsSpinSlider, TimeInputs, CurrencySpinner
|
||||
from qt_ui.windows.AirWingConfigurationDialog import AirWingConfigurationDialog
|
||||
from qt_ui.windows.newgame.QCampaignList import (
|
||||
Campaign,
|
||||
QCampaignList,
|
||||
@@ -125,6 +126,10 @@ class NewGameWizard(QtWidgets.QWizard):
|
||||
)
|
||||
self.generatedGame = generator.generate()
|
||||
|
||||
AirWingConfigurationDialog(self.generatedGame, self).exec_()
|
||||
|
||||
self.generatedGame.begin_turn_0()
|
||||
|
||||
super(NewGameWizard, self).accept()
|
||||
|
||||
|
||||
|
||||
67
qt_ui/windows/notes/QNotesWindow.py
Normal file
67
qt_ui/windows/notes/QNotesWindow.py
Normal file
@@ -0,0 +1,67 @@
|
||||
from PySide2.QtWidgets import (
|
||||
QDialog,
|
||||
QPlainTextEdit,
|
||||
QVBoxLayout,
|
||||
QHBoxLayout,
|
||||
QPushButton,
|
||||
QLabel,
|
||||
)
|
||||
from PySide2.QtGui import QTextCursor
|
||||
from PySide2.QtCore import QTimer
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game.game import Game
|
||||
|
||||
from time import sleep
|
||||
|
||||
|
||||
class QNotesWindow(QDialog):
|
||||
def __init__(self, game: Game):
|
||||
super(QNotesWindow, self).__init__()
|
||||
|
||||
self.game = game
|
||||
self.setWindowTitle("Notes")
|
||||
self.setWindowIcon(CONST.ICONS["Notes"])
|
||||
self.setMinimumSize(400, 100)
|
||||
self.resize(600, 450)
|
||||
|
||||
self.vbox = QVBoxLayout()
|
||||
self.setLayout(self.vbox)
|
||||
|
||||
self.vbox.addWidget(
|
||||
QLabel("Saved notes are available as a page in your kneeboard.")
|
||||
)
|
||||
|
||||
self.textbox = QPlainTextEdit(self)
|
||||
try:
|
||||
self.textbox.setPlainText(self.game.notes)
|
||||
self.textbox.moveCursor(QTextCursor.End)
|
||||
except AttributeError: # old save may not have game.notes
|
||||
pass
|
||||
self.textbox.move(10, 10)
|
||||
self.textbox.resize(600, 450)
|
||||
self.textbox.setStyleSheet("background: #1D2731;")
|
||||
self.vbox.addWidget(self.textbox)
|
||||
|
||||
self.button_row = QHBoxLayout()
|
||||
self.vbox.addLayout(self.button_row)
|
||||
|
||||
self.clear_button = QPushButton(self)
|
||||
self.clear_button.setText("CLEAR")
|
||||
self.clear_button.setProperty("style", "btn-primary")
|
||||
self.clear_button.clicked.connect(self.clearNotes)
|
||||
self.button_row.addWidget(self.clear_button)
|
||||
|
||||
self.save_button = QPushButton(self)
|
||||
self.save_button.setText("SAVE")
|
||||
self.save_button.setProperty("style", "btn-success")
|
||||
self.save_button.clicked.connect(self.saveNotes)
|
||||
self.button_row.addWidget(self.save_button)
|
||||
|
||||
def clearNotes(self) -> None:
|
||||
self.textbox.setPlainText("")
|
||||
|
||||
def saveNotes(self) -> None:
|
||||
self.game.notes = self.textbox.toPlainText()
|
||||
self.save_button.setText("SAVED")
|
||||
QTimer.singleShot(5000, lambda: self.save_button.setText("SAVE"))
|
||||
@@ -58,6 +58,12 @@ class QLiberationFirstStartWindow(QDialog):
|
||||
|
||||
<p>As you click on the button below, the file will be replaced in your DCS installation directory.</p>
|
||||
|
||||
<br/>
|
||||
<p>If you leave the DCS Installation Directory empty, DCS Liberation can not automatically replace the MissionScripting.lua and will therefore not work correctly!
|
||||
In this case, you need to edit the file yourself. The easiest way to do it is to replace the original file with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua).
|
||||
<br/><br/>You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.</p>
|
||||
|
||||
|
||||
<br/><br/>
|
||||
|
||||
<strong>Thank you for reading !</strong>
|
||||
|
||||
@@ -22,6 +22,7 @@ class QLiberationPreferences(QFrame):
|
||||
super(QLiberationPreferences, self).__init__()
|
||||
self.saved_game_dir = ""
|
||||
self.dcs_install_dir = ""
|
||||
self.install_dir_ignore_warning = False
|
||||
|
||||
self.dcs_install_dir = liberation_install.get_dcs_install_directory()
|
||||
self.saved_game_dir = liberation_install.get_saved_game_dir()
|
||||
@@ -102,17 +103,38 @@ class QLiberationPreferences(QFrame):
|
||||
error_dialog.exec_()
|
||||
return False
|
||||
|
||||
if not os.path.isdir(self.dcs_install_dir):
|
||||
if self.install_dir_ignore_warning and self.dcs_install_dir == "":
|
||||
warning_dialog = QMessageBox.warning(
|
||||
self,
|
||||
"The DCS Installation directory was not set",
|
||||
"You set an empty DCS Installation directory! "
|
||||
"<br/><br/>Without this directory, DCS Liberation can not replace the MissionScripting.lua for you and will not work properly. "
|
||||
"In this case, you need to edit the MissionScripting.lua yourself. The easiest way to do it is to replace the original file (<dcs_installation_directory>/Scripts/MissionScripting.lua) with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua)."
|
||||
"<br/><br/>You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.</p>"
|
||||
"<br/><br/>Are you sure that you want to leave the installation directory empty?"
|
||||
"<br/><br/><strong>This is only recommended for expert users!</strong>",
|
||||
QMessageBox.StandardButton.Yes,
|
||||
QMessageBox.StandardButton.No,
|
||||
)
|
||||
if warning_dialog == QMessageBox.No:
|
||||
return False
|
||||
elif not os.path.isdir(self.dcs_install_dir):
|
||||
error_dialog = QMessageBox.critical(
|
||||
self,
|
||||
"Wrong DCS installation directory.",
|
||||
self.dcs_install_dir + " is not a valid directory",
|
||||
self.dcs_install_dir
|
||||
+ " is not a valid directory. DCS Liberation requires the installation directory to replace the MissionScripting.lua"
|
||||
"<br/><br/>If you ignore this Error, DCS Liberation can not work properly and needs your attention. "
|
||||
"In this case, you need to edit the MissionScripting.lua yourself. The easiest way to do it is to replace the original file (<dcs_installation_directory>/Scripts/MissionScripting.lua) with the file in dcs-liberation distribution (<dcs_liberation_installation>/resources/scripts/MissionScripting.lua)."
|
||||
"<br/><br/>You can find more information on how to manually change this file in the Liberation Wiki (Page: Dedicated Server Guide) on GitHub.</p>"
|
||||
"<br/><br/><strong>This is only recommended for expert users!</strong>",
|
||||
QMessageBox.StandardButton.Ignore,
|
||||
QMessageBox.StandardButton.Ok,
|
||||
)
|
||||
error_dialog.exec_()
|
||||
if error_dialog == QMessageBox.Ignore:
|
||||
self.install_dir_ignore_warning = True
|
||||
return False
|
||||
|
||||
if not os.path.isdir(
|
||||
elif not os.path.isdir(
|
||||
os.path.join(self.dcs_install_dir, "Scripts")
|
||||
) and os.path.isfile(os.path.join(self.dcs_install_dir, "bin", "DCS.exe")):
|
||||
error_dialog = QMessageBox.critical(
|
||||
|
||||
@@ -101,7 +101,7 @@ class HqAutomationSettingsBox(QGroupBox):
|
||||
|
||||
front_line = QCheckBox()
|
||||
front_line.setChecked(self.game.settings.automate_front_line_reinforcements)
|
||||
front_line.toggled.connect(self.set_front_line_automation)
|
||||
front_line.toggled.connect(self.set_front_line_reinforcement_automation)
|
||||
|
||||
layout.addWidget(QLabel("Automate front-line purchases"), 1, 0)
|
||||
layout.addWidget(front_line, 1, 1, Qt.AlignRight)
|
||||
@@ -147,12 +147,30 @@ class HqAutomationSettingsBox(QGroupBox):
|
||||
)
|
||||
layout.addWidget(self.auto_ato_player_missions_asap, 4, 1, Qt.AlignRight)
|
||||
|
||||
self.automate_front_line_stance = QCheckBox()
|
||||
self.automate_front_line_stance.setChecked(
|
||||
self.game.settings.automate_front_line_stance
|
||||
)
|
||||
self.automate_front_line_stance.toggled.connect(
|
||||
self.set_front_line_stance_automation
|
||||
)
|
||||
|
||||
layout.addWidget(
|
||||
QLabel("Automatically manage front line stances"),
|
||||
5,
|
||||
0,
|
||||
)
|
||||
layout.addWidget(self.automate_front_line_stance, 5, 1, Qt.AlignRight)
|
||||
|
||||
def set_runway_automation(self, value: bool) -> None:
|
||||
self.game.settings.automate_runway_repair = value
|
||||
|
||||
def set_front_line_automation(self, value: bool) -> None:
|
||||
def set_front_line_reinforcement_automation(self, value: bool) -> None:
|
||||
self.game.settings.automate_front_line_reinforcements = value
|
||||
|
||||
def set_front_line_stance_automation(self, value: bool) -> None:
|
||||
self.game.settings.automate_front_line_stance = value
|
||||
|
||||
def set_aircraft_automation(self, value: bool) -> None:
|
||||
self.game.settings.automate_aircraft_reinforcements = value
|
||||
|
||||
@@ -855,7 +873,7 @@ class QSettingsWindow(QDialog):
|
||||
|
||||
def cheatMoney(self, amount):
|
||||
logging.info("CHEATING FOR AMOUNT : " + str(amount) + "M")
|
||||
self.game.budget += amount
|
||||
self.game.blue.budget += amount
|
||||
if amount > 0:
|
||||
self.game.informations.append(
|
||||
Information(
|
||||
|
||||
@@ -42,10 +42,16 @@ class QAircraftChart(QFrame):
|
||||
self.chart.setTitle("Aircraft forces over time")
|
||||
|
||||
self.chart.createDefaultAxes()
|
||||
self.chart.axisX().setTitleText("Turn")
|
||||
self.chart.axisX().setLabelFormat("%i")
|
||||
self.chart.axisX().setRange(0, len(self.alliedAircraft))
|
||||
self.chart.axisX().applyNiceNumbers()
|
||||
|
||||
self.chart.axisY().setLabelFormat("%i")
|
||||
self.chart.axisY().setRange(
|
||||
0, max(max(self.alliedAircraft), max(self.enemyAircraft)) + 10
|
||||
)
|
||||
self.chart.axisY().applyNiceNumbers()
|
||||
|
||||
self.chartView = QtCharts.QChartView(self.chart)
|
||||
self.chartView.setRenderHint(QPainter.Antialiasing)
|
||||
|
||||
@@ -42,10 +42,16 @@ class QArmorChart(QFrame):
|
||||
self.chart.setTitle("Combat vehicles over time")
|
||||
|
||||
self.chart.createDefaultAxes()
|
||||
self.chart.axisX().setTitleText("Turn")
|
||||
self.chart.axisX().setLabelFormat("%i")
|
||||
self.chart.axisX().setRange(0, len(self.alliedArmor))
|
||||
self.chart.axisX().applyNiceNumbers()
|
||||
|
||||
self.chart.axisY().setLabelFormat("%i")
|
||||
self.chart.axisY().setRange(
|
||||
0, max(max(self.alliedArmor), max(self.enemyArmor)) + 10
|
||||
)
|
||||
self.chart.axisY().applyNiceNumbers()
|
||||
|
||||
self.chartView = QtCharts.QChartView(self.chart)
|
||||
self.chartView.setRenderHint(QPainter.Antialiasing)
|
||||
|
||||
@@ -14,7 +14,7 @@ class QStatsWindow(QDialog):
|
||||
self.setModal(True)
|
||||
self.setWindowTitle("Stats")
|
||||
self.setWindowIcon(CONST.ICONS["Statistics"])
|
||||
self.setMinimumSize(600, 250)
|
||||
self.setMinimumSize(600, 300)
|
||||
|
||||
self.layout = QGridLayout()
|
||||
self.aircraft_charts = QAircraftChart(self.game)
|
||||
|
||||
Reference in New Issue
Block a user