mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Merge 'upstream/develop' into new-plugin-system
This commit is contained in:
@@ -164,6 +164,7 @@ class PackageModel(QAbstractListModel):
|
||||
|
||||
def update_tot(self, tot: int) -> None:
|
||||
self.package.time_over_target = tot
|
||||
self.layoutChanged.emit()
|
||||
|
||||
@property
|
||||
def mission_target(self) -> MissionTarget:
|
||||
@@ -234,7 +235,7 @@ class AtoModel(QAbstractListModel):
|
||||
"""Returns the package at the given index."""
|
||||
return self.ato.packages[index.row()]
|
||||
|
||||
def replace_from_game(self, game: Optional[Game]) -> None:
|
||||
def replace_from_game(self, game: Optional[Game], player: bool) -> None:
|
||||
"""Updates the ATO object to match the updated game object.
|
||||
|
||||
If the game is None (as is the case when no game has been loaded), an
|
||||
@@ -244,7 +245,10 @@ class AtoModel(QAbstractListModel):
|
||||
self.game = game
|
||||
self.package_models.clear()
|
||||
if self.game is not None:
|
||||
self.ato = game.blue_ato
|
||||
if player:
|
||||
self.ato = game.blue_ato
|
||||
else:
|
||||
self.ato = game.red_ato
|
||||
else:
|
||||
self.ato = AirTaskingOrder()
|
||||
self.endResetModel()
|
||||
@@ -268,8 +272,8 @@ class GameModel:
|
||||
"""
|
||||
def __init__(self) -> None:
|
||||
self.game: Optional[Game] = None
|
||||
# TODO: Add red ATO model, add cheat option to show red flight plan.
|
||||
self.ato_model = AtoModel(self.game, AirTaskingOrder())
|
||||
self.red_ato_model = AtoModel(self.game, AirTaskingOrder())
|
||||
|
||||
def set(self, game: Optional[Game]) -> None:
|
||||
"""Updates the managed Game object.
|
||||
@@ -280,4 +284,5 @@ class GameModel:
|
||||
loaded.
|
||||
"""
|
||||
self.game = game
|
||||
self.ato_model.replace_from_game(self.game)
|
||||
self.ato_model.replace_from_game(self.game, player=True)
|
||||
self.red_ato_model.replace_from_game(self.game, player=False)
|
||||
|
||||
@@ -6,7 +6,7 @@ from PySide2.QtGui import QColor, QFont, QPixmap
|
||||
from theater.theatergroundobject import CATEGORY_MAP
|
||||
from .liberation_theme import get_theme_icons
|
||||
|
||||
VERSION_STRING = "2.1.4"
|
||||
VERSION_STRING = "2.2.0-preview"
|
||||
|
||||
URLS : Dict[str, str] = {
|
||||
"Manual": "https://github.com/khopa/dcs_liberation/wiki",
|
||||
@@ -40,6 +40,7 @@ COLORS: Dict[str, QColor] = {
|
||||
"light_blue": QColor(105, 182, 240, 90),
|
||||
"blue": QColor(0, 132, 255),
|
||||
"dark_blue": QColor(45, 62, 80),
|
||||
"sea_blue": QColor(52, 68, 85),
|
||||
"blue_transparent": QColor(0, 132, 255, 20),
|
||||
|
||||
"purple": QColor(187, 137, 255),
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from typing import Optional
|
||||
from typing import List, Optional
|
||||
|
||||
from PySide2.QtWidgets import (
|
||||
QFrame,
|
||||
@@ -11,6 +11,8 @@ from PySide2.QtWidgets import (
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game import Game
|
||||
from game.event import CAP, CAS, FrontlineAttackEvent
|
||||
from gen.ato import Package
|
||||
from gen.flights.traveltime import TotEstimator
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.widgets.QBudgetBox import QBudgetBox
|
||||
from qt_ui.widgets.QFactionsInfos import QFactionsInfos
|
||||
@@ -95,7 +97,7 @@ class QTopPanel(QFrame):
|
||||
if game is None:
|
||||
return
|
||||
|
||||
self.turnCounter.setCurrentTurn(game.turn, game.current_day)
|
||||
self.turnCounter.setCurrentTurn(game.turn, game.conditions)
|
||||
self.budgetBox.setGame(game)
|
||||
self.factionsInfos.setGame(game)
|
||||
|
||||
@@ -117,6 +119,24 @@ class QTopPanel(QFrame):
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
self.proceedButton.setEnabled(True)
|
||||
|
||||
def negative_start_packages(self) -> List[Package]:
|
||||
packages = []
|
||||
for package in self.game_model.ato_model.ato.packages:
|
||||
if not package.flights:
|
||||
continue
|
||||
estimator = TotEstimator(package)
|
||||
for flight in package.flights:
|
||||
if estimator.mission_start_time(flight) < 0:
|
||||
packages.append(package)
|
||||
break
|
||||
return packages
|
||||
|
||||
@staticmethod
|
||||
def fix_tots(packages: List[Package]) -> None:
|
||||
for package in packages:
|
||||
estimator = TotEstimator(package)
|
||||
package.time_over_target = estimator.earliest_tot()
|
||||
|
||||
def ato_has_clients(self) -> bool:
|
||||
for package in self.game.blue_ato.packages:
|
||||
for flight in package.flights:
|
||||
@@ -142,12 +162,52 @@ class QTopPanel(QFrame):
|
||||
)
|
||||
return result == QMessageBox.Yes
|
||||
|
||||
def confirm_negative_start_time(self,
|
||||
negative_starts: List[Package]) -> bool:
|
||||
formatted = '<br />'.join(
|
||||
[f"{p.primary_task.name} {p.target.name}" for p in negative_starts]
|
||||
)
|
||||
mbox = QMessageBox(
|
||||
QMessageBox.Question,
|
||||
"Continue with past start times?",
|
||||
("Some flights in the following packages have start times set "
|
||||
"earlier than mission start time:<br />"
|
||||
"<br />"
|
||||
f"{formatted}<br />"
|
||||
"<br />"
|
||||
"Flight start times are estimated based on the package TOT, so it "
|
||||
"is possible that not all flights will be able to reach the "
|
||||
"target area at their assigned times.<br />"
|
||||
"<br />"
|
||||
"You can either continue with the mission as planned, with the "
|
||||
"misplanned flights potentially flying too fast and/or missing "
|
||||
"their rendezvous; automatically fix negative TOTs; or cancel "
|
||||
"mission start and fix the packages manually."),
|
||||
parent=self
|
||||
)
|
||||
auto = mbox.addButton("Fix TOTs automatically", QMessageBox.ActionRole)
|
||||
ignore = mbox.addButton("Continue without fixing",
|
||||
QMessageBox.DestructiveRole)
|
||||
cancel = mbox.addButton(QMessageBox.Cancel)
|
||||
mbox.setEscapeButton(cancel)
|
||||
mbox.exec_()
|
||||
clicked = mbox.clickedButton()
|
||||
if clicked == auto:
|
||||
self.fix_tots(negative_starts)
|
||||
return True
|
||||
elif clicked == ignore:
|
||||
return True
|
||||
return False
|
||||
|
||||
def launch_mission(self):
|
||||
"""Finishes planning and waits for mission completion."""
|
||||
if not self.ato_has_clients() and not self.confirm_no_client_launch():
|
||||
return
|
||||
|
||||
# TODO: Verify no negative start times.
|
||||
negative_starts = self.negative_start_packages()
|
||||
if negative_starts:
|
||||
if not self.confirm_negative_start_time(negative_starts):
|
||||
return
|
||||
|
||||
# TODO: Refactor this nonsense.
|
||||
game_event = None
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import datetime
|
||||
|
||||
from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox
|
||||
from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QVBoxLayout
|
||||
|
||||
from game.weather import Conditions, TimeOfDay
|
||||
import qt_ui.uiconstants as CONST
|
||||
|
||||
|
||||
@@ -13,23 +14,37 @@ class QTurnCounter(QGroupBox):
|
||||
def __init__(self):
|
||||
super(QTurnCounter, self).__init__("Turn")
|
||||
|
||||
self.icons = [CONST.ICONS["Dawn"], CONST.ICONS["Day"], CONST.ICONS["Dusk"], CONST.ICONS["Night"]]
|
||||
|
||||
self.daytime_icon = QLabel()
|
||||
self.daytime_icon.setPixmap(self.icons[0])
|
||||
self.turn_info = QLabel()
|
||||
self.icons = {
|
||||
TimeOfDay.Dawn: CONST.ICONS["Dawn"],
|
||||
TimeOfDay.Day: CONST.ICONS["Day"],
|
||||
TimeOfDay.Dusk: CONST.ICONS["Dusk"],
|
||||
TimeOfDay.Night: CONST.ICONS["Night"],
|
||||
}
|
||||
|
||||
self.layout = QHBoxLayout()
|
||||
self.layout.addWidget(self.daytime_icon)
|
||||
self.layout.addWidget(self.turn_info)
|
||||
self.setLayout(self.layout)
|
||||
|
||||
def setCurrentTurn(self, turn: int, current_day: datetime):
|
||||
self.daytime_icon = QLabel()
|
||||
self.daytime_icon.setPixmap(self.icons[TimeOfDay.Dawn])
|
||||
self.layout.addWidget(self.daytime_icon)
|
||||
|
||||
self.time_column = QVBoxLayout()
|
||||
self.layout.addLayout(self.time_column)
|
||||
|
||||
self.date_display = QLabel()
|
||||
self.time_column.addWidget(self.date_display)
|
||||
|
||||
self.time_display = QLabel()
|
||||
self.time_column.addWidget(self.time_display)
|
||||
|
||||
def setCurrentTurn(self, turn: int, conditions: Conditions) -> None:
|
||||
"""Sets the turn information display.
|
||||
|
||||
:arg turn Current turn number.
|
||||
:arg conditions Current time and weather conditions.
|
||||
"""
|
||||
Set the money amount to display
|
||||
:arg turn Current turn number
|
||||
:arg current_day Current day
|
||||
"""
|
||||
self.daytime_icon.setPixmap(self.icons[turn % 4])
|
||||
self.turn_info.setText(current_day.strftime("%d %b %Y"))
|
||||
self.daytime_icon.setPixmap(self.icons[conditions.time_of_day])
|
||||
self.date_display.setText(conditions.start_time.strftime("%d %b %Y"))
|
||||
self.time_display.setText(
|
||||
conditions.start_time.strftime("%H:%M:%S Local"))
|
||||
self.setTitle("Turn " + str(turn + 1))
|
||||
|
||||
@@ -19,7 +19,6 @@ class QFlightTypeComboBox(QComboBox):
|
||||
|
||||
COMMON_ENEMY_MISSIONS = [
|
||||
FlightType.ESCORT,
|
||||
FlightType.TARCAP,
|
||||
FlightType.SEAD,
|
||||
FlightType.DEAD,
|
||||
# TODO: FlightType.ELINT,
|
||||
@@ -27,42 +26,46 @@ class QFlightTypeComboBox(QComboBox):
|
||||
# TODO: FlightType.RECON,
|
||||
]
|
||||
|
||||
FRIENDLY_AIRBASE_MISSIONS = [
|
||||
FlightType.CAP,
|
||||
# TODO: FlightType.INTERCEPTION
|
||||
# TODO: FlightType.LOGISTICS
|
||||
COMMON_FRIENDLY_MISSIONS = [
|
||||
FlightType.BARCAP,
|
||||
]
|
||||
|
||||
FRIENDLY_AIRBASE_MISSIONS = [
|
||||
# TODO: FlightType.INTERCEPTION
|
||||
# TODO: FlightType.LOGISTICS
|
||||
] + COMMON_FRIENDLY_MISSIONS
|
||||
|
||||
FRIENDLY_CARRIER_MISSIONS = [
|
||||
FlightType.BARCAP,
|
||||
# TODO: FlightType.INTERCEPTION
|
||||
# TODO: Buddy tanking for the A-4?
|
||||
# TODO: Rescue chopper?
|
||||
# TODO: Inter-ship logistics?
|
||||
]
|
||||
] + COMMON_FRIENDLY_MISSIONS
|
||||
|
||||
ENEMY_CARRIER_MISSIONS = [
|
||||
FlightType.ESCORT,
|
||||
FlightType.TARCAP,
|
||||
FlightType.BARCAP,
|
||||
# TODO: FlightType.ANTISHIP
|
||||
]
|
||||
|
||||
ENEMY_AIRBASE_MISSIONS = [
|
||||
FlightType.BARCAP,
|
||||
# TODO: FlightType.STRIKE
|
||||
] + COMMON_ENEMY_MISSIONS
|
||||
|
||||
FRIENDLY_GROUND_OBJECT_MISSIONS = [
|
||||
FlightType.CAP,
|
||||
# TODO: FlightType.LOGISTICS
|
||||
# TODO: FlightType.TROOP_TRANSPORT
|
||||
]
|
||||
] + COMMON_FRIENDLY_MISSIONS
|
||||
|
||||
ENEMY_GROUND_OBJECT_MISSIONS = [
|
||||
FlightType.BARCAP,
|
||||
FlightType.STRIKE,
|
||||
] + COMMON_ENEMY_MISSIONS
|
||||
|
||||
FRONT_LINE_MISSIONS = [
|
||||
FlightType.CAS,
|
||||
FlightType.TARCAP,
|
||||
# TODO: FlightType.TROOP_TRANSPORT
|
||||
# TODO: FlightType.EVAC
|
||||
] + COMMON_ENEMY_MISSIONS
|
||||
|
||||
@@ -21,6 +21,7 @@ from game import Game, db
|
||||
from game.data.aaa_db import AAA_UNITS
|
||||
from game.data.radar_db import UNITS_WITH_RADAR
|
||||
from game.utils import meter_to_feet
|
||||
from game.weather import TimeOfDay
|
||||
from gen import Conflict, PackageWaypointTiming
|
||||
from gen.ato import Package
|
||||
from gen.flights.flight import Flight, FlightWaypoint, FlightWaypointType
|
||||
@@ -55,25 +56,42 @@ class QLiberationMap(QGraphicsView):
|
||||
self.factor = 1
|
||||
self.factorized = 1
|
||||
self.init_scene()
|
||||
self.connectSignals()
|
||||
self.setGame(game_model.game)
|
||||
|
||||
GameUpdateSignal.get_instance().flight_paths_changed.connect(
|
||||
lambda: self.draw_flight_plans(self.scene())
|
||||
)
|
||||
|
||||
def update_package_selection(index: Optional[int]) -> None:
|
||||
self.selected_flight = index, 0
|
||||
def update_package_selection(index: int) -> None:
|
||||
# Optional[int] isn't a valid type for a Qt signal. None will be
|
||||
# converted to zero automatically. We use -1 to indicate no
|
||||
# selection.
|
||||
if index == -1:
|
||||
self.selected_flight = None
|
||||
else:
|
||||
self.selected_flight = index, 0
|
||||
self.draw_flight_plans(self.scene())
|
||||
|
||||
GameUpdateSignal.get_instance().package_selection_changed.connect(
|
||||
update_package_selection
|
||||
)
|
||||
|
||||
def update_flight_selection(index: Optional[int]) -> None:
|
||||
def update_flight_selection(index: int) -> None:
|
||||
if self.selected_flight is None:
|
||||
logging.error("Flight was selected with no package selected")
|
||||
if index != -1:
|
||||
# We don't know what order update_package_selection and
|
||||
# update_flight_selection will be called in when the last
|
||||
# package is removed. If no flight is selected, it's not a
|
||||
# problem to also have no package selected.
|
||||
logging.error(
|
||||
"Flight was selected with no package selected")
|
||||
return
|
||||
|
||||
# Optional[int] isn't a valid type for a Qt signal. None will be
|
||||
# converted to zero automatically. We use -1 to indicate no
|
||||
# selection.
|
||||
if index == -1:
|
||||
self.selected_flight = self.selected_flight[0], None
|
||||
self.selected_flight = self.selected_flight[0], index
|
||||
self.draw_flight_plans(self.scene())
|
||||
|
||||
@@ -90,9 +108,6 @@ class QLiberationMap(QGraphicsView):
|
||||
self.setFrameShape(QFrame.NoFrame)
|
||||
self.setDragMode(QGraphicsView.ScrollHandDrag)
|
||||
|
||||
def connectSignals(self):
|
||||
GameUpdateSignal.get_instance().gameupdated.connect(self.setGame)
|
||||
|
||||
def setGame(self, game: Optional[Game]):
|
||||
self.game = game
|
||||
logging.debug("Reloading Map Canvas")
|
||||
@@ -244,7 +259,7 @@ class QLiberationMap(QGraphicsView):
|
||||
text.setDefaultTextColor(Qt.white)
|
||||
text.setPos(pos[0] + CONST.CP_SIZE + 1, pos[1] - CONST.CP_SIZE / 2 + 1)
|
||||
|
||||
def draw_flight_plans(self, scene) -> None:
|
||||
def clear_flight_paths(self, scene: QGraphicsScene) -> None:
|
||||
for item in self.flight_path_items:
|
||||
try:
|
||||
scene.removeItem(item)
|
||||
@@ -252,12 +267,20 @@ class QLiberationMap(QGraphicsView):
|
||||
# Something may have caused those items to already be removed.
|
||||
pass
|
||||
self.flight_path_items.clear()
|
||||
|
||||
def draw_flight_plans(self, scene: QGraphicsScene) -> None:
|
||||
self.clear_flight_paths(scene)
|
||||
if DisplayOptions.flight_paths.hide:
|
||||
return
|
||||
packages = list(self.game_model.ato_model.packages)
|
||||
if self.game.settings.show_red_ato:
|
||||
packages.extend(self.game_model.red_ato_model.packages)
|
||||
for p_idx, package_model in enumerate(packages):
|
||||
for f_idx, flight in enumerate(package_model.flights):
|
||||
selected = (p_idx, f_idx) == self.selected_flight
|
||||
if self.selected_flight is None:
|
||||
selected = False
|
||||
else:
|
||||
selected = (p_idx, f_idx) == self.selected_flight
|
||||
if DisplayOptions.flight_paths.only_selected and not selected:
|
||||
continue
|
||||
self.draw_flight_plan(scene, package_model.package, flight,
|
||||
@@ -486,9 +509,9 @@ class QLiberationMap(QGraphicsView):
|
||||
scene.addPixmap(bg)
|
||||
|
||||
# Apply graphical effects to simulate current daytime
|
||||
if self.game.current_turn_daytime == "day":
|
||||
if self.game.current_turn_time_of_day == TimeOfDay.Day:
|
||||
pass
|
||||
elif self.game.current_turn_daytime == "night":
|
||||
elif self.game.current_turn_time_of_day == TimeOfDay.Night:
|
||||
ov = QPixmap(bg.width(), bg.height())
|
||||
ov.fill(CONST.COLORS["night_overlay"])
|
||||
overlay = scene.addPixmap(ov)
|
||||
@@ -507,6 +530,11 @@ class QLiberationMap(QGraphicsView):
|
||||
# Polygon display mode
|
||||
if self.game.theater.landmap is not None:
|
||||
|
||||
for sea_zone in self.game.theater.landmap[2]:
|
||||
print(sea_zone)
|
||||
poly = QPolygonF([QPointF(*self._transform_point(Point(point[0], point[1]))) for point in sea_zone])
|
||||
scene.addPolygon(poly, CONST.COLORS["sea_blue"], CONST.COLORS["sea_blue"])
|
||||
|
||||
for inclusion_zone in self.game.theater.landmap[0]:
|
||||
poly = QPolygonF([QPointF(*self._transform_point(Point(point[0], point[1]))) for point in inclusion_zone])
|
||||
scene.addPolygon(poly, CONST.COLORS["grey"], CONST.COLORS["dark_grey"])
|
||||
@@ -516,3 +544,5 @@ class QLiberationMap(QGraphicsView):
|
||||
scene.addPolygon(poly, CONST.COLORS["grey"], CONST.COLORS["dark_dark_grey"])
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ from PySide2.QtWidgets import QGraphicsItem
|
||||
import qt_ui.uiconstants as const
|
||||
from game import Game
|
||||
from game.data.building_data import FORTIFICATION_BUILDINGS
|
||||
from game.db import REWARDS
|
||||
from qt_ui.windows.groundobject.QGroundObjectMenu import QGroundObjectMenu
|
||||
from theater import ControlPoint, TheaterGroundObject
|
||||
from .QMapObject import QMapObject
|
||||
@@ -27,7 +28,14 @@ class QMapGroundObject(QMapObject):
|
||||
self.buildings = buildings if buildings is not None else []
|
||||
self.setFlag(QGraphicsItem.ItemIgnoresTransformations, False)
|
||||
self.ground_object_dialog: Optional[QGroundObjectMenu] = None
|
||||
self.setToolTip(self.tooltip)
|
||||
|
||||
@property
|
||||
def tooltip(self) -> str:
|
||||
lines = [
|
||||
f"[{self.ground_object.obj_name}]",
|
||||
f"${self.production_per_turn} per turn",
|
||||
]
|
||||
if self.ground_object.groups:
|
||||
units = {}
|
||||
for g in self.ground_object.groups:
|
||||
@@ -36,16 +44,23 @@ class QMapGroundObject(QMapObject):
|
||||
units[u.type] = units[u.type]+1
|
||||
else:
|
||||
units[u.type] = 1
|
||||
tooltip = "[" + self.ground_object.obj_name + "]" + "\n"
|
||||
|
||||
for unit in units.keys():
|
||||
tooltip = tooltip + str(unit) + "x" + str(units[unit]) + "\n"
|
||||
self.setToolTip(tooltip[:-1])
|
||||
lines.append(f"{unit} x {units[unit]}")
|
||||
else:
|
||||
tooltip = "[" + self.ground_object.obj_name + "]" + "\n"
|
||||
for building in buildings:
|
||||
for building in self.buildings:
|
||||
if not building.is_dead:
|
||||
tooltip = tooltip + str(building.dcs_identifier) + "\n"
|
||||
self.setToolTip(tooltip[:-1])
|
||||
lines.append(f"{building.dcs_identifier}")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
@property
|
||||
def production_per_turn(self) -> int:
|
||||
production = 0
|
||||
for g in self.control_point.ground_objects:
|
||||
if g.category in REWARDS.keys():
|
||||
production += REWARDS[g.category]
|
||||
return production
|
||||
|
||||
def paint(self, painter, option, widget=None) -> None:
|
||||
player_icons = "_blue"
|
||||
|
||||
@@ -24,8 +24,8 @@ class GameUpdateSignal(QObject):
|
||||
debriefingReceived = Signal(DebriefingSignal)
|
||||
|
||||
flight_paths_changed = Signal()
|
||||
package_selection_changed = Signal(int) # Optional[int]
|
||||
flight_selection_changed = Signal(int) # Optional[int]
|
||||
package_selection_changed = Signal(int) # -1 indicates no selection.
|
||||
flight_selection_changed = Signal(int) # -1 indicates no selection.
|
||||
|
||||
def __init__(self):
|
||||
super(GameUpdateSignal, self).__init__()
|
||||
@@ -33,11 +33,11 @@ class GameUpdateSignal(QObject):
|
||||
|
||||
def select_package(self, index: Optional[int]) -> None:
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.package_selection_changed.emit(index)
|
||||
self.package_selection_changed.emit(-1 if index is None else index)
|
||||
|
||||
def select_flight(self, index: Optional[int]) -> None:
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.flight_selection_changed.emit(index)
|
||||
self.flight_selection_changed.emit(-1 if index is None else index)
|
||||
|
||||
def redraw_flight_paths(self) -> None:
|
||||
# noinspection PyUnresolvedReferences
|
||||
|
||||
@@ -43,6 +43,7 @@ class QLiberationWindow(QMainWindow):
|
||||
Dialog.set_game(self.game_model)
|
||||
self.ato_panel = None
|
||||
self.info_panel = None
|
||||
self.liberation_map = None
|
||||
self.setGame(persistency.restore_game())
|
||||
|
||||
self.setGeometry(300, 100, 270, 100)
|
||||
@@ -224,9 +225,11 @@ class QLiberationWindow(QMainWindow):
|
||||
if game is not None:
|
||||
game.on_load()
|
||||
self.game = game
|
||||
if self.info_panel:
|
||||
if self.info_panel is not None:
|
||||
self.info_panel.setGame(game)
|
||||
self.game_model.set(self.game)
|
||||
if self.liberation_map is not None:
|
||||
self.liberation_map.setGame(game)
|
||||
|
||||
def showAboutDialog(self):
|
||||
text = "<h3>DCS Liberation " + CONST.VERSION_STRING + "</h3>" + \
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
from typing import Optional
|
||||
from typing import Optional, Set
|
||||
|
||||
from PySide2.QtCore import Qt
|
||||
from PySide2.QtWidgets import (
|
||||
QFrame,
|
||||
QGridLayout,
|
||||
QScrollArea,
|
||||
QVBoxLayout,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QScrollArea,
|
||||
QVBoxLayout,
|
||||
QWidget,
|
||||
)
|
||||
from dcs.unittype import UnitType
|
||||
|
||||
from game.event.event import UnitsDeliveryEvent
|
||||
from qt_ui.models import GameModel
|
||||
@@ -48,26 +49,27 @@ class QAircraftRecruitmentMenu(QFrame, QRecruitBehaviour):
|
||||
def init_ui(self):
|
||||
main_layout = QVBoxLayout()
|
||||
|
||||
units = {
|
||||
CAP: db.find_unittype(CAP, self.game_model.game.player_name),
|
||||
CAS: db.find_unittype(CAS, self.game_model.game.player_name),
|
||||
}
|
||||
tasks = [CAP, CAS]
|
||||
|
||||
scroll_content = QWidget()
|
||||
task_box_layout = QGridLayout()
|
||||
row = 0
|
||||
|
||||
for task_type in units.keys():
|
||||
units_column = list(set(units[task_type]))
|
||||
if len(units_column) == 0:
|
||||
unit_types: Set[UnitType] = set()
|
||||
for task in tasks:
|
||||
units = db.find_unittype(task, self.game_model.game.player_name)
|
||||
if not units:
|
||||
continue
|
||||
units_column.sort(key=lambda x: db.PRICES[x])
|
||||
for unit_type in units_column:
|
||||
if self.cp.is_carrier and not unit_type in db.CARRIER_CAPABLE:
|
||||
for unit in units:
|
||||
if self.cp.is_carrier and unit not in db.CARRIER_CAPABLE:
|
||||
continue
|
||||
if self.cp.is_lha and not unit_type in db.LHA_CAPABLE:
|
||||
if self.cp.is_lha and unit not in db.LHA_CAPABLE:
|
||||
continue
|
||||
row = self.add_purchase_row(unit_type, task_box_layout, row)
|
||||
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)
|
||||
stretch = QVBoxLayout()
|
||||
stretch.addStretch()
|
||||
task_box_layout.addLayout(stretch, row, 0)
|
||||
|
||||
@@ -16,6 +16,7 @@ from game.game import Game
|
||||
from gen.ato import Package
|
||||
from gen.flights.flight import Flight
|
||||
from gen.flights.flightplan import FlightPlanBuilder
|
||||
from gen.flights.traveltime import TotEstimator
|
||||
from qt_ui.models import AtoModel, PackageModel
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.widgets.ato import QFlightList
|
||||
@@ -34,12 +35,6 @@ class QPackageDialog(QDialog):
|
||||
#: Emitted when a change is made to the package.
|
||||
package_changed = Signal()
|
||||
|
||||
#: Emitted when a flight is added to the package.
|
||||
flight_added = Signal(Flight)
|
||||
|
||||
#: Emitted when a flight is removed from the package.
|
||||
flight_removed = Signal(Flight)
|
||||
|
||||
def __init__(self, game: Game, model: PackageModel) -> None:
|
||||
super().__init__()
|
||||
self.game = game
|
||||
@@ -77,20 +72,20 @@ class QPackageDialog(QDialog):
|
||||
self.tot_label = QLabel("Time Over Target:")
|
||||
self.tot_column.addWidget(self.tot_label)
|
||||
|
||||
if self.package_model.package.time_over_target is None:
|
||||
time = None
|
||||
else:
|
||||
delay = self.package_model.package.time_over_target
|
||||
hours = delay // 3600
|
||||
minutes = delay // 60 % 60
|
||||
seconds = delay % 60
|
||||
time = QTime(hours, minutes, seconds)
|
||||
|
||||
self.tot_spinner = QTimeEdit(time)
|
||||
self.tot_spinner = QTimeEdit(self.tot_qtime())
|
||||
self.tot_spinner.setMinimumTime(QTime(0, 0))
|
||||
self.tot_spinner.setDisplayFormat("T+hh:mm:ss")
|
||||
self.tot_spinner.timeChanged.connect(self.save_tot)
|
||||
self.tot_column.addWidget(self.tot_spinner)
|
||||
|
||||
self.reset_tot_button = QPushButton("Reset TOT")
|
||||
self.reset_tot_button.setToolTip(
|
||||
"Sets the package TOT to the earliest time that all flights can "
|
||||
"arrive at the target."
|
||||
)
|
||||
self.reset_tot_button.clicked.connect(self.reset_tot)
|
||||
self.tot_column.addWidget(self.reset_tot_button)
|
||||
|
||||
self.package_view = QFlightList(self.package_model)
|
||||
self.package_view.selectionModel().selectionChanged.connect(
|
||||
self.on_selection_changed
|
||||
@@ -114,17 +109,40 @@ class QPackageDialog(QDialog):
|
||||
|
||||
self.setLayout(self.layout)
|
||||
|
||||
self.accepted.connect(self.on_save)
|
||||
self.finished.connect(self.on_close)
|
||||
self.rejected.connect(self.on_cancel)
|
||||
|
||||
def tot_qtime(self) -> QTime:
|
||||
delay = self.package_model.package.time_over_target
|
||||
hours = delay // 3600
|
||||
minutes = delay // 60 % 60
|
||||
seconds = delay % 60
|
||||
return QTime(hours, minutes, seconds)
|
||||
|
||||
def on_cancel(self) -> None:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def on_close(_result) -> None:
|
||||
GameUpdateSignal.get_instance().redraw_flight_paths()
|
||||
|
||||
def on_save(self) -> None:
|
||||
self.save_tot()
|
||||
|
||||
def save_tot(self) -> None:
|
||||
time = self.tot_spinner.time()
|
||||
seconds = time.hour() * 3600 + time.minute() * 60 + time.second()
|
||||
self.package_model.update_tot(seconds)
|
||||
|
||||
def reset_tot(self) -> None:
|
||||
if not list(self.package_model.flights):
|
||||
self.package_model.update_tot(0)
|
||||
else:
|
||||
self.package_model.update_tot(
|
||||
TotEstimator(self.package_model.package).earliest_tot())
|
||||
self.tot_spinner.setTime(self.tot_qtime())
|
||||
|
||||
def on_selection_changed(self, selected: QItemSelection,
|
||||
_deselected: QItemSelection) -> None:
|
||||
"""Updates the state of the delete button."""
|
||||
@@ -139,14 +157,13 @@ class QPackageDialog(QDialog):
|
||||
|
||||
def add_flight(self, flight: Flight) -> None:
|
||||
"""Adds the new flight to the package."""
|
||||
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)
|
||||
planner.populate_flight_plan(flight)
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.package_changed.emit()
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.flight_added.emit(flight)
|
||||
|
||||
def on_delete_flight(self) -> None:
|
||||
"""Removes the selected flight from the package."""
|
||||
@@ -154,11 +171,10 @@ class QPackageDialog(QDialog):
|
||||
if flight is None:
|
||||
logging.error(f"Cannot delete flight when no flight is selected.")
|
||||
return
|
||||
self.game.aircraft_inventory.return_from_flight(flight)
|
||||
self.package_model.delete_flight(flight)
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.package_changed.emit()
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.flight_removed.emit(flight)
|
||||
|
||||
|
||||
class QNewPackageDialog(QPackageDialog):
|
||||
@@ -174,22 +190,22 @@ class QNewPackageDialog(QPackageDialog):
|
||||
|
||||
self.save_button = QPushButton("Save")
|
||||
self.save_button.setProperty("style", "start-button")
|
||||
self.save_button.clicked.connect(self.on_save)
|
||||
self.save_button.clicked.connect(self.accept)
|
||||
self.button_layout.addWidget(self.save_button)
|
||||
|
||||
self.delete_flight_button.clicked.connect(self.on_delete_flight)
|
||||
|
||||
def on_save(self) -> None:
|
||||
"""Saves the created package.
|
||||
|
||||
Empty packages may be created. They can be modified later, and will have
|
||||
no effect if empty when the mission is generated.
|
||||
"""
|
||||
self.save_tot()
|
||||
super().on_save()
|
||||
self.ato_model.add_package(self.package_model.package)
|
||||
|
||||
def on_cancel(self) -> None:
|
||||
super().on_cancel()
|
||||
for flight in self.package_model.package.flights:
|
||||
self.game.aircraft_inventory.claim_for_flight(flight)
|
||||
self.close()
|
||||
self.game_model.game.aircraft_inventory.return_from_flight(flight)
|
||||
|
||||
|
||||
class QEditPackageDialog(QPackageDialog):
|
||||
@@ -210,30 +226,9 @@ class QEditPackageDialog(QPackageDialog):
|
||||
|
||||
self.done_button = QPushButton("Done")
|
||||
self.done_button.setProperty("style", "start-button")
|
||||
self.done_button.clicked.connect(self.on_done)
|
||||
self.done_button.clicked.connect(self.accept)
|
||||
self.button_layout.addWidget(self.done_button)
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.flight_added.connect(self.on_flight_added)
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.flight_removed.connect(self.on_flight_removed)
|
||||
|
||||
# TODO: Make the new package dialog do this too, return on cancel.
|
||||
# Not claiming the aircraft when they are added to the planner means that
|
||||
# inventory counts are not updated until after the new package is updated,
|
||||
# so you can add an infinite number of aircraft to a new package in the UI,
|
||||
# which will crash when the flight package is saved.
|
||||
def on_flight_added(self, flight: Flight) -> None:
|
||||
self.game.aircraft_inventory.claim_for_flight(flight)
|
||||
|
||||
def on_flight_removed(self, flight: Flight) -> None:
|
||||
self.game.aircraft_inventory.return_from_flight(flight)
|
||||
|
||||
def on_done(self) -> None:
|
||||
"""Closes the window."""
|
||||
self.save_tot()
|
||||
self.close()
|
||||
|
||||
def on_delete(self) -> None:
|
||||
"""Removes the viewed package from the ATO."""
|
||||
# The ATO model returns inventory for us when deleting a package.
|
||||
|
||||
@@ -19,11 +19,15 @@ class QFlightPlanner(QTabWidget):
|
||||
def __init__(self, package: Package, flight: Flight, game: Game):
|
||||
super().__init__()
|
||||
|
||||
self.general_settings_tab = QGeneralFlightSettingsTab(game, flight)
|
||||
self.general_settings_tab = QGeneralFlightSettingsTab(
|
||||
game, package, flight
|
||||
)
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.general_settings_tab.on_flight_settings_changed.connect(
|
||||
lambda: self.on_planned_flight_changed.emit())
|
||||
self.payload_tab = QFlightPayloadTab(flight, game)
|
||||
self.waypoint_tab = QFlightWaypointTab(game, package, flight)
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.waypoint_tab.on_flight_changed.connect(
|
||||
lambda: self.on_planned_flight_changed.emit())
|
||||
self.addTab(self.general_settings_tab, "General Flight settings")
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
import datetime
|
||||
|
||||
from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QVBoxLayout
|
||||
|
||||
from gen.ato import Package
|
||||
from gen.flights.flight import Flight
|
||||
from gen.flights.traveltime import TotEstimator
|
||||
|
||||
|
||||
# TODO: Remove?
|
||||
class QFlightDepartureDisplay(QGroupBox):
|
||||
|
||||
def __init__(self, package: Package, flight: Flight):
|
||||
super().__init__("Departure")
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
departure_row = QHBoxLayout()
|
||||
layout.addLayout(departure_row)
|
||||
|
||||
estimator = TotEstimator(package)
|
||||
delay = datetime.timedelta(seconds=estimator.mission_start_time(flight))
|
||||
|
||||
departure_row.addWidget(QLabel(
|
||||
f"Departing from <b>{flight.from_cp.name}</b>"
|
||||
))
|
||||
departure_row.addWidget(QLabel(f"At T+{delay}"))
|
||||
|
||||
layout.addWidget(QLabel("Determined based on the package TOT. Edit the "
|
||||
"package to adjust the TOT."))
|
||||
|
||||
self.setLayout(layout)
|
||||
@@ -1,31 +0,0 @@
|
||||
from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QSpinBox
|
||||
|
||||
|
||||
# TODO: Remove?
|
||||
class QFlightDepartureEditor(QGroupBox):
|
||||
|
||||
def __init__(self, flight):
|
||||
super(QFlightDepartureEditor, self).__init__("Departure")
|
||||
self.flight = flight
|
||||
|
||||
layout = QHBoxLayout()
|
||||
self.depart_from = QLabel("Departing from <b>" + self.flight.from_cp.name + "</b>")
|
||||
self.depart_at_t = QLabel("At T +")
|
||||
self.minutes = QLabel(" minutes")
|
||||
|
||||
self.departure_delta = QSpinBox(self)
|
||||
self.departure_delta.setMinimum(0)
|
||||
self.departure_delta.setMaximum(120)
|
||||
self.departure_delta.setValue(self.flight.scheduled_in // 60)
|
||||
self.departure_delta.valueChanged.connect(self.change_scheduled)
|
||||
|
||||
layout.addWidget(self.depart_from)
|
||||
layout.addWidget(self.depart_at_t)
|
||||
layout.addWidget(self.departure_delta)
|
||||
layout.addWidget(self.minutes)
|
||||
self.setLayout(layout)
|
||||
|
||||
self.changed = self.departure_delta.valueChanged
|
||||
|
||||
def change_scheduled(self):
|
||||
self.flight.scheduled_in = int(self.departure_delta.value() * 60)
|
||||
@@ -2,26 +2,29 @@ from PySide2.QtCore import Signal
|
||||
from PySide2.QtWidgets import QFrame, QGridLayout, QVBoxLayout
|
||||
|
||||
from game import Game
|
||||
from gen.ato import Package
|
||||
from gen.flights.flight import Flight
|
||||
from qt_ui.windows.mission.flight.settings.QFlightDepartureEditor import QFlightDepartureEditor
|
||||
from qt_ui.windows.mission.flight.settings.QFlightSlotEditor import QFlightSlotEditor
|
||||
from qt_ui.windows.mission.flight.settings.QFlightStartType import QFlightStartType
|
||||
from qt_ui.windows.mission.flight.settings.QFlightTypeTaskInfo import QFlightTypeTaskInfo
|
||||
from qt_ui.windows.mission.flight.settings.QFlightDepartureDisplay import \
|
||||
QFlightDepartureDisplay
|
||||
from qt_ui.windows.mission.flight.settings.QFlightSlotEditor import \
|
||||
QFlightSlotEditor
|
||||
from qt_ui.windows.mission.flight.settings.QFlightStartType import \
|
||||
QFlightStartType
|
||||
from qt_ui.windows.mission.flight.settings.QFlightTypeTaskInfo import \
|
||||
QFlightTypeTaskInfo
|
||||
|
||||
|
||||
class QGeneralFlightSettingsTab(QFrame):
|
||||
on_flight_settings_changed = Signal()
|
||||
|
||||
def __init__(self, game: Game, flight: Flight):
|
||||
super(QGeneralFlightSettingsTab, self).__init__()
|
||||
self.flight = flight
|
||||
self.game = game
|
||||
def __init__(self, game: Game, package: Package, flight: Flight):
|
||||
super().__init__()
|
||||
|
||||
layout = QGridLayout()
|
||||
flight_info = QFlightTypeTaskInfo(self.flight)
|
||||
flight_departure = QFlightDepartureEditor(self.flight)
|
||||
flight_slots = QFlightSlotEditor(self.flight, self.game)
|
||||
flight_start_type = QFlightStartType(self.flight)
|
||||
flight_info = QFlightTypeTaskInfo(flight)
|
||||
flight_departure = QFlightDepartureDisplay(package, flight)
|
||||
flight_slots = QFlightSlotEditor(flight, game)
|
||||
flight_start_type = QFlightStartType(flight)
|
||||
layout.addWidget(flight_info, 0, 0)
|
||||
layout.addWidget(flight_departure, 1, 0)
|
||||
layout.addWidget(flight_slots, 2, 0)
|
||||
@@ -31,8 +34,6 @@ class QGeneralFlightSettingsTab(QFrame):
|
||||
layout.addLayout(vstretch, 3, 0)
|
||||
self.setLayout(layout)
|
||||
|
||||
flight_start_type.setEnabled(self.flight.client_count > 0)
|
||||
flight_start_type.setEnabled(flight.client_count > 0)
|
||||
flight_slots.changed.connect(
|
||||
lambda: flight_start_type.setEnabled(self.flight.client_count > 0))
|
||||
flight_departure.changed.connect(
|
||||
lambda: self.on_flight_settings_changed.emit())
|
||||
lambda: flight_start_type.setEnabled(flight.client_count > 0))
|
||||
|
||||
@@ -54,6 +54,7 @@ class QFlightWaypointTab(QFrame):
|
||||
rlayout.addWidget(QLabel("<strong>Generator :</strong>"))
|
||||
rlayout.addWidget(QLabel("<small>AI compatible</small>"))
|
||||
|
||||
# TODO: Filter by objective type.
|
||||
self.recreate_buttons.clear()
|
||||
recreate_types = [
|
||||
FlightType.CAS,
|
||||
@@ -137,13 +138,16 @@ class QFlightWaypointTab(QFrame):
|
||||
QMessageBox.Yes
|
||||
)
|
||||
if result == QMessageBox.Yes:
|
||||
# TODO: These should all be just CAP.
|
||||
# TODO: Should be buttons for both BARCAP and TARCAP.
|
||||
# BARCAP and TARCAP behave differently. TARCAP arrives a few minutes
|
||||
# ahead of the rest of the package and stays until the package
|
||||
# departs, whereas BARCAP usually isn't part of a strike package and
|
||||
# has a fixed mission time.
|
||||
if task == FlightType.CAP:
|
||||
if isinstance(self.package.target, FrontLine):
|
||||
task = FlightType.TARCAP
|
||||
elif isinstance(self.package.target, ControlPoint):
|
||||
if self.package.target.is_fleet:
|
||||
task = FlightType.BARCAP
|
||||
task = FlightType.BARCAP
|
||||
self.flight.flight_type = task
|
||||
self.planner.populate_flight_plan(self.flight)
|
||||
self.flight_waypoint_list.update_list()
|
||||
|
||||
@@ -1,18 +1,50 @@
|
||||
import logging
|
||||
from typing import Callable
|
||||
|
||||
from PySide2.QtCore import QSize, Qt, QItemSelectionModel, QPoint
|
||||
from PySide2.QtGui import QStandardItemModel, QStandardItem
|
||||
from PySide2.QtWidgets import QLabel, QDialog, QGridLayout, QListView, QStackedLayout, QComboBox, QWidget, \
|
||||
QAbstractItemView, QPushButton, QGroupBox, QCheckBox, QVBoxLayout, QSpinBox
|
||||
from PySide2.QtWidgets import (
|
||||
QLabel,
|
||||
QDialog,
|
||||
QGridLayout,
|
||||
QListView,
|
||||
QStackedLayout,
|
||||
QComboBox,
|
||||
QWidget,
|
||||
QAbstractItemView,
|
||||
QPushButton,
|
||||
QGroupBox,
|
||||
QCheckBox,
|
||||
QVBoxLayout,
|
||||
QSpinBox,
|
||||
)
|
||||
from dcs.forcedoptions import ForcedOptions
|
||||
|
||||
import qt_ui.uiconstants as CONST
|
||||
from game.game import Game
|
||||
from game.infos.information import Information
|
||||
from qt_ui.widgets.QLabeledWidget import QLabeledWidget
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.finances.QFinancesMenu import QHorizontalSeparationLine
|
||||
from plugin import LuaPluginManager
|
||||
|
||||
class CheatSettingsBox(QGroupBox):
|
||||
def __init__(self, game: Game, apply_settings: Callable[[], None]) -> None:
|
||||
super().__init__("Cheat Settings")
|
||||
self.main_layout = QVBoxLayout()
|
||||
self.setLayout(self.main_layout)
|
||||
|
||||
self.red_ato_checkbox = QCheckBox()
|
||||
self.red_ato_checkbox.setChecked(game.settings.show_red_ato)
|
||||
self.red_ato_checkbox.toggled.connect(apply_settings)
|
||||
self.red_ato = QLabeledWidget("Show Red ATO:", self.red_ato_checkbox)
|
||||
self.main_layout.addLayout(self.red_ato)
|
||||
|
||||
@property
|
||||
def show_red_ato(self) -> bool:
|
||||
return self.red_ato_checkbox.isChecked()
|
||||
|
||||
|
||||
class QSettingsWindow(QDialog):
|
||||
|
||||
def __init__(self, game: Game):
|
||||
@@ -262,9 +294,12 @@ class QSettingsWindow(QDialog):
|
||||
def initCheatLayout(self):
|
||||
|
||||
self.cheatPage = QWidget()
|
||||
self.cheatLayout = QGridLayout()
|
||||
self.cheatLayout = QVBoxLayout()
|
||||
self.cheatPage.setLayout(self.cheatLayout)
|
||||
|
||||
self.cheat_options = CheatSettingsBox(self.game, self.applySettings)
|
||||
self.cheatLayout.addWidget(self.cheat_options)
|
||||
|
||||
self.moneyCheatBox = QGroupBox("Money Cheat")
|
||||
self.moneyCheatBox.setAlignment(Qt.AlignTop)
|
||||
self.moneyCheatBoxLayout = QGridLayout()
|
||||
@@ -280,7 +315,7 @@ class QSettingsWindow(QDialog):
|
||||
btn.setProperty("style", "btn-danger")
|
||||
btn.clicked.connect(self.cheatLambda(amount))
|
||||
self.moneyCheatBoxLayout.addWidget(btn, i/2, i%2)
|
||||
self.cheatLayout.addWidget(self.moneyCheatBox, 0, 0)
|
||||
self.cheatLayout.addWidget(self.moneyCheatBox, stretch=1)
|
||||
|
||||
def initPluginsLayout(self):
|
||||
uiPrepared = False
|
||||
@@ -332,8 +367,6 @@ class QSettingsWindow(QDialog):
|
||||
self.game.settings.external_views_allowed = self.ext_views.isChecked()
|
||||
self.game.settings.generate_marks = self.generate_marks.isChecked()
|
||||
|
||||
print(self.game.settings.map_coalition_visibility)
|
||||
|
||||
self.game.settings.supercarrier = self.supercarrier.isChecked()
|
||||
|
||||
self.game.settings.perf_red_alert_state = self.red_alert.isChecked()
|
||||
@@ -347,6 +380,8 @@ class QSettingsWindow(QDialog):
|
||||
self.game.settings.perf_culling = self.culling.isChecked()
|
||||
self.game.settings.perf_culling_distance = int(self.culling_distance.value())
|
||||
|
||||
self.game.settings.show_red_ato = self.cheat_options.show_red_ato
|
||||
|
||||
GameUpdateSignal.get_instance().updateGame(self.game)
|
||||
|
||||
def onSelectionChanged(self):
|
||||
|
||||
Reference in New Issue
Block a user