mirror of
https://github.com/dcs-retribution/dcs-retribution.git
synced 2025-11-10 15:41:24 +00:00
Make ASAP a checkbox and maintain ASAP on changes.
Fixes https://github.com/Khopa/dcs_liberation/issues/642
This commit is contained in:
parent
768d239840
commit
5047b535c4
@ -29,6 +29,7 @@ Saves from 2.3 are not compatible with 2.4.
|
||||
* **[UI]** Aircraft for a new flight are now only selectable if they match the task type for that flight.
|
||||
* **[UI]** WIP - There is now a unit info button for each unit in the recruitment list, that should help newer players learn what each unit does.
|
||||
* **[UI]** Docs for time-on-target and creating new theaters/factions/loadouts are now linked in the UI at the appropriate places.
|
||||
* **[UI]** ASAP is now a checkbox rather than a button. Enabling this will disable the TOT selector but changes to the package structure will automatically re-ASAP the package.
|
||||
* **[Factions]** Added option for date-based loadout restriction. Active radar homing missiles are handled, patches welcome for the other thousand weapons.
|
||||
* **[Factions]** Added Poland 2010 faction.
|
||||
* **[Factions]** Added Greece 2005 faction.
|
||||
|
||||
@ -20,6 +20,7 @@ from game.theater.missiontarget import MissionTarget
|
||||
from game.utils import Speed
|
||||
from .flights.flight import Flight, FlightType
|
||||
from .flights.flightplan import FormationFlightPlan
|
||||
from .flights.traveltime import TotEstimator
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
@ -54,6 +55,11 @@ class Package:
|
||||
|
||||
delay: int = field(default=0)
|
||||
|
||||
#: True if the package ToT should be reset to ASAP whenever the player makes
|
||||
#: a change. This is really a UI property rather than a game property, but
|
||||
#: we want it to persist in the save.
|
||||
auto_asap: bool = field(default=False)
|
||||
|
||||
#: Desired TOT as an offset from mission start.
|
||||
time_over_target: timedelta = field(default=timedelta())
|
||||
|
||||
@ -127,6 +133,9 @@ class Package:
|
||||
return max(times)
|
||||
return None
|
||||
|
||||
def set_tot_asap(self) -> None:
|
||||
self.time_over_target = TotEstimator(self).earliest_tot()
|
||||
|
||||
def add_flight(self, flight: Flight) -> None:
|
||||
"""Adds a flight to the package."""
|
||||
self.flights.append(flight)
|
||||
|
||||
@ -60,7 +60,7 @@ class Dialog:
|
||||
"""Opens the dialog to edit the given flight."""
|
||||
cls.edit_flight_dialog = QEditFlightDialog(
|
||||
cls.game_model,
|
||||
package_model.package,
|
||||
package_model,
|
||||
flight,
|
||||
parent=parent
|
||||
)
|
||||
|
||||
@ -100,6 +100,8 @@ class PackageModel(QAbstractListModel):
|
||||
#: Emitted when this package is being deleted from the ATO.
|
||||
deleted = Signal()
|
||||
|
||||
tot_changed = Signal()
|
||||
|
||||
def __init__(self, package: Package) -> None:
|
||||
super().__init__()
|
||||
self.package = package
|
||||
@ -139,6 +141,8 @@ class PackageModel(QAbstractListModel):
|
||||
"""Adds the given flight to the package."""
|
||||
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
|
||||
self.package.add_flight(flight)
|
||||
# update_tot is not called here because the new flight does not have a
|
||||
# flight plan yet. Will be called manually by the caller.
|
||||
self.endInsertRows()
|
||||
|
||||
def delete_flight_at_index(self, index: QModelIndex) -> None:
|
||||
@ -155,14 +159,24 @@ class PackageModel(QAbstractListModel):
|
||||
self.beginRemoveRows(QModelIndex(), index, index)
|
||||
self.package.remove_flight(flight)
|
||||
self.endRemoveRows()
|
||||
self.update_tot()
|
||||
|
||||
def flight_at_index(self, index: QModelIndex) -> Flight:
|
||||
"""Returns the flight located at the given index."""
|
||||
return self.package.flights[index.row()]
|
||||
|
||||
def update_tot(self, tot: datetime.timedelta) -> None:
|
||||
def set_tot(self, tot: datetime.timedelta) -> None:
|
||||
self.package.time_over_target = tot
|
||||
self.layoutChanged.emit()
|
||||
self.update_tot()
|
||||
|
||||
def set_asap(self, asap: bool) -> None:
|
||||
self.package.auto_asap = asap
|
||||
self.update_tot()
|
||||
|
||||
def update_tot(self) -> None:
|
||||
if self.package.auto_asap:
|
||||
self.package.set_tot_asap()
|
||||
self.tot_changed.emit()
|
||||
|
||||
@property
|
||||
def mission_target(self) -> MissionTarget:
|
||||
|
||||
@ -4,9 +4,8 @@ from PySide2.QtWidgets import (
|
||||
QVBoxLayout,
|
||||
)
|
||||
|
||||
from gen.ato import Package
|
||||
from gen.flights.flight import Flight
|
||||
from qt_ui.models import GameModel
|
||||
from qt_ui.models import GameModel, PackageModel
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.mission.flight.QFlightPlanner import QFlightPlanner
|
||||
@ -15,7 +14,8 @@ from qt_ui.windows.mission.flight.QFlightPlanner import QFlightPlanner
|
||||
class QEditFlightDialog(QDialog):
|
||||
"""Dialog window for editing flight plans and loadouts."""
|
||||
|
||||
def __init__(self, game_model: GameModel, package: Package, flight: Flight, parent=None) -> None:
|
||||
def __init__(self, game_model: GameModel, package_model: PackageModel,
|
||||
flight: Flight, parent=None) -> None:
|
||||
super().__init__(parent=parent)
|
||||
|
||||
self.game_model = game_model
|
||||
@ -25,7 +25,8 @@ class QEditFlightDialog(QDialog):
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
self.flight_planner = QFlightPlanner(package, flight, game_model.game)
|
||||
self.flight_planner = QFlightPlanner(package_model, flight,
|
||||
game_model.game)
|
||||
layout.addWidget(self.flight_planner)
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
@ -3,8 +3,9 @@ import logging
|
||||
from datetime import timedelta
|
||||
from typing import Optional
|
||||
|
||||
from PySide2.QtCore import QItemSelection, QTime, Signal, Qt
|
||||
from PySide2.QtCore import QItemSelection, QTime, Qt, Signal
|
||||
from PySide2.QtWidgets import (
|
||||
QCheckBox,
|
||||
QDialog,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
@ -15,16 +16,15 @@ from PySide2.QtWidgets import (
|
||||
)
|
||||
|
||||
from game.game import Game
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
from gen.ato import Package
|
||||
from gen.flights.flight import Flight
|
||||
from gen.flights.flightplan import FlightPlanBuilder, PlanningError
|
||||
from gen.flights.traveltime import TotEstimator
|
||||
from qt_ui.models import AtoModel, GameModel, PackageModel
|
||||
from qt_ui.uiconstants import EVENT_ICONS
|
||||
from qt_ui.widgets.ato import QFlightList
|
||||
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
|
||||
from qt_ui.windows.mission.flight.QFlightCreator import QFlightCreator
|
||||
from game.theater.missiontarget import MissionTarget
|
||||
|
||||
|
||||
class QPackageDialog(QDialog):
|
||||
@ -79,15 +79,17 @@ class QPackageDialog(QDialog):
|
||||
self.tot_spinner.setDisplayFormat("T+hh:mm:ss")
|
||||
self.tot_spinner.timeChanged.connect(self.save_tot)
|
||||
self.tot_spinner.setToolTip("Package TOT relative to mission TOT")
|
||||
self.tot_spinner.setEnabled(not self.package_model.package.auto_asap)
|
||||
self.tot_column.addWidget(self.tot_spinner)
|
||||
|
||||
self.reset_tot_button = QPushButton("ASAP")
|
||||
self.reset_tot_button.setToolTip(
|
||||
self.auto_asap = QCheckBox("ASAP")
|
||||
self.auto_asap.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.auto_asap.setChecked(self.package_model.package.auto_asap)
|
||||
self.auto_asap.toggled.connect(self.set_asap)
|
||||
self.tot_column.addWidget(self.auto_asap)
|
||||
|
||||
self.tot_help_label = QLabel("<a href=\"https://github.com/Khopa/dcs_liberation/wiki/Mission-planning\"><span style=\"color:#FFFFFF;\">Help</span></a>")
|
||||
self.tot_help_label.setAlignment(Qt.AlignCenter)
|
||||
@ -113,6 +115,8 @@ class QPackageDialog(QDialog):
|
||||
self.delete_flight_button.setEnabled(model.rowCount() > 0)
|
||||
self.button_layout.addWidget(self.delete_flight_button)
|
||||
|
||||
self.package_model.tot_changed.connect(self.update_tot)
|
||||
|
||||
self.button_layout.addStretch()
|
||||
|
||||
self.setLayout(self.layout)
|
||||
@ -145,14 +149,14 @@ class QPackageDialog(QDialog):
|
||||
def save_tot(self) -> None:
|
||||
time = self.tot_spinner.time()
|
||||
seconds = time.hour() * 3600 + time.minute() * 60 + time.second()
|
||||
self.package_model.update_tot(timedelta(seconds=seconds))
|
||||
self.package_model.set_tot(timedelta(seconds=seconds))
|
||||
|
||||
def reset_tot(self) -> None:
|
||||
if not list(self.package_model.flights):
|
||||
self.package_model.update_tot(timedelta())
|
||||
else:
|
||||
self.package_model.update_tot(
|
||||
TotEstimator(self.package_model.package).earliest_tot())
|
||||
def set_asap(self, checked: bool) -> None:
|
||||
self.package_model.set_asap(checked)
|
||||
self.tot_spinner.setEnabled(not self.package_model.package.auto_asap)
|
||||
self.update_tot()
|
||||
|
||||
def update_tot(self) -> None:
|
||||
self.tot_spinner.setTime(self.tot_qtime())
|
||||
|
||||
def on_selection_changed(self, selected: QItemSelection,
|
||||
@ -183,6 +187,7 @@ class QPackageDialog(QDialog):
|
||||
QMessageBox.critical(
|
||||
self, "Could not create flight", str(ex), QMessageBox.Ok
|
||||
)
|
||||
self.package_model.update_tot()
|
||||
# noinspection PyUnresolvedReferences
|
||||
self.package_changed.emit()
|
||||
|
||||
|
||||
@ -1,9 +1,8 @@
|
||||
from PySide2.QtCore import Signal
|
||||
from PySide2.QtWidgets import QTabWidget
|
||||
|
||||
from game import Game
|
||||
from gen.ato import Package
|
||||
from gen.flights.flight import Flight
|
||||
from qt_ui.models import PackageModel
|
||||
from qt_ui.windows.mission.flight.payload.QFlightPayloadTab import \
|
||||
QFlightPayloadTab
|
||||
from qt_ui.windows.mission.flight.settings.QGeneralFlightSettingsTab import \
|
||||
@ -14,22 +13,15 @@ from qt_ui.windows.mission.flight.waypoints.QFlightWaypointTab import \
|
||||
|
||||
class QFlightPlanner(QTabWidget):
|
||||
|
||||
on_planned_flight_changed = Signal()
|
||||
|
||||
def __init__(self, package: Package, flight: Flight, game: Game):
|
||||
def __init__(self, package_model: PackageModel, flight: Flight, game: Game):
|
||||
super().__init__()
|
||||
|
||||
self.general_settings_tab = QGeneralFlightSettingsTab(
|
||||
game, package, flight
|
||||
game, package_model, 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.waypoint_tab = QFlightWaypointTab(game, package_model.package,
|
||||
flight)
|
||||
self.addTab(self.general_settings_tab, "General Flight settings")
|
||||
self.addTab(self.payload_tab, "Payload")
|
||||
self.addTab(self.waypoint_tab, "Waypoints")
|
||||
|
||||
@ -1,32 +1,38 @@
|
||||
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?
|
||||
from qt_ui.models import PackageModel
|
||||
|
||||
|
||||
class QFlightDepartureDisplay(QGroupBox):
|
||||
|
||||
def __init__(self, package: Package, flight: Flight):
|
||||
def __init__(self, package_model: PackageModel, flight: Flight):
|
||||
super().__init__("Departure")
|
||||
self.package_model = package_model
|
||||
self.flight = flight
|
||||
|
||||
layout = QVBoxLayout()
|
||||
|
||||
departure_row = QHBoxLayout()
|
||||
layout.addLayout(departure_row)
|
||||
|
||||
estimator = TotEstimator(package)
|
||||
delay = 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}"))
|
||||
self.departure_time = QLabel()
|
||||
self.package_model.tot_changed.connect(self.update_departure_time)
|
||||
departure_row.addWidget(self.departure_time)
|
||||
self.update_departure_time()
|
||||
|
||||
layout.addWidget(QLabel("Determined based on the package TOT. Edit the "
|
||||
"package to adjust the TOT."))
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def update_departure_time(self) -> None:
|
||||
estimator = TotEstimator(self.package_model.package)
|
||||
delay = estimator.mission_start_time(self.flight)
|
||||
self.departure_time.setText(f"At T+{delay}")
|
||||
|
||||
@ -1,15 +1,20 @@
|
||||
import logging
|
||||
|
||||
from PySide2.QtCore import Signal
|
||||
from PySide2.QtWidgets import QLabel, QHBoxLayout, QGroupBox, QSpinBox, QGridLayout
|
||||
from PySide2.QtWidgets import QLabel, QGroupBox, QSpinBox, QGridLayout
|
||||
|
||||
from game import Game
|
||||
from gen.flights.flight import Flight
|
||||
from qt_ui.models import PackageModel
|
||||
|
||||
|
||||
class QFlightSlotEditor(QGroupBox):
|
||||
|
||||
changed = Signal()
|
||||
|
||||
def __init__(self, flight, game):
|
||||
super(QFlightSlotEditor, self).__init__("Slots")
|
||||
def __init__(self, package_model: PackageModel, flight: Flight, game: Game):
|
||||
super().__init__("Slots")
|
||||
self.package_model = package_model
|
||||
self.flight = flight
|
||||
self.game = game
|
||||
self.inventory = self.game.aircraft_inventory.for_control_point(
|
||||
@ -70,6 +75,7 @@ class QFlightSlotEditor(QGroupBox):
|
||||
def _changed_client_count(self):
|
||||
self.flight.client_count = int(self.client_count_spinner.value())
|
||||
self._cap_client_count()
|
||||
self.package_model.update_tot()
|
||||
self.changed.emit()
|
||||
|
||||
def _cap_client_count(self):
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
from PySide2.QtWidgets import QGroupBox, QHBoxLayout, QComboBox, QLabel
|
||||
from dcs.mission import StartType
|
||||
from PySide2.QtWidgets import QComboBox, QGroupBox, QHBoxLayout, QLabel
|
||||
|
||||
from gen.flights.flight import Flight
|
||||
from qt_ui.models import PackageModel
|
||||
|
||||
|
||||
class QFlightStartType(QGroupBox):
|
||||
|
||||
def __init__(self, flight:Flight):
|
||||
super(QFlightStartType, self).__init__()
|
||||
|
||||
def __init__(self, package_model: PackageModel, flight: Flight):
|
||||
super().__init__()
|
||||
self.package_model = package_model
|
||||
self.flight = flight
|
||||
|
||||
self.layout = QHBoxLayout()
|
||||
@ -28,6 +28,4 @@ class QFlightStartType(QGroupBox):
|
||||
def _on_start_type_selected(self):
|
||||
selected = self.start_type.currentData()
|
||||
self.flight.start_type = selected
|
||||
|
||||
|
||||
|
||||
self.package_model.update_tot()
|
||||
@ -1,9 +1,10 @@
|
||||
from PySide2.QtCore import Signal
|
||||
from PySide2.QtWidgets import QFrame, QGridLayout, QVBoxLayout, QLabel
|
||||
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.models import PackageModel
|
||||
from qt_ui.windows.mission.flight.settings.QFlightDepartureDisplay import \
|
||||
QFlightDepartureDisplay
|
||||
from qt_ui.windows.mission.flight.settings.QFlightSlotEditor import \
|
||||
@ -19,14 +20,14 @@ from qt_ui.windows.mission.flight.settings.QCustomName import \
|
||||
class QGeneralFlightSettingsTab(QFrame):
|
||||
on_flight_settings_changed = Signal()
|
||||
|
||||
def __init__(self, game: Game, package: Package, flight: Flight):
|
||||
def __init__(self, game: Game, package_model: PackageModel, flight: Flight):
|
||||
super().__init__()
|
||||
|
||||
layout = QGridLayout()
|
||||
flight_info = QFlightTypeTaskInfo(flight)
|
||||
flight_departure = QFlightDepartureDisplay(package, flight)
|
||||
flight_slots = QFlightSlotEditor(flight, game)
|
||||
flight_start_type = QFlightStartType(flight)
|
||||
flight_departure = QFlightDepartureDisplay(package_model, flight)
|
||||
flight_slots = QFlightSlotEditor(package_model, flight, game)
|
||||
flight_start_type = QFlightStartType(package_model, flight)
|
||||
flight_custom_name = QFlightCustomName(flight)
|
||||
layout.addWidget(flight_info, 0, 0)
|
||||
layout.addWidget(flight_departure, 1, 0)
|
||||
|
||||
@ -29,8 +29,6 @@ from qt_ui.windows.mission.flight.waypoints \
|
||||
|
||||
class QFlightWaypointTab(QFrame):
|
||||
|
||||
on_flight_changed = Signal()
|
||||
|
||||
def __init__(self, game: Game, package: Package, flight: Flight):
|
||||
super(QFlightWaypointTab, self).__init__()
|
||||
self.game = game
|
||||
@ -163,4 +161,3 @@ class QFlightWaypointTab(QFrame):
|
||||
|
||||
def on_change(self):
|
||||
self.flight_waypoint_list.update_list()
|
||||
self.on_flight_changed.emit()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user