diff --git a/changelog.md b/changelog.md
index 002dc15a..b98a9459 100644
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,18 @@
+#2.0 RC 7
+
+##Features/Improvements :
+* **[Units/Factions]** Added P-47D-30 for factions allies_1944
+* **[Mission Generator]** CAP flights have been slightly reworked
+* **[Mission Generator]** Add PP points for JF-17 on STRIKE missions
+* **[Mission Generator]** Add ST point for F-14B on STRIKE missions
+* **[Mission Generator]** Flights with client slots will never be delayed
+* **[Mission Generator]** AI units can start from parking
+
+##Fixed issues :
+* **[Mission Generator]** When playing as RED the activation trigger would not be properly generated
+* **[Mission Generator]** Changed "strike" payload for Su-24M
+* **[Mission Generator]** FW-190A8 is now properly considered as flyable
+
#2.0 RC 6
Saves file from RC5 are not compatible with the new version.
diff --git a/game/settings.py b/game/settings.py
index d399803a..547c6ab0 100644
--- a/game/settings.py
+++ b/game/settings.py
@@ -21,5 +21,6 @@ class Settings:
perf_artillery = True
perf_moving_units = True
perf_infantry = True
+ perf_ai_parking_start = True
diff --git a/gen/flights/ai_flight_planner_db.py b/gen/flights/ai_flight_planner_db.py
index e8eed392..d43167e8 100644
--- a/gen/flights/ai_flight_planner_db.py
+++ b/gen/flights/ai_flight_planner_db.py
@@ -48,6 +48,7 @@ CAP_CAPABLE = [
P_51D_30_NA,
P_51D,
+ P_47D_30,
SpitfireLFMkIXCW,
SpitfireLFMkIX,
@@ -106,6 +107,7 @@ CAS_CAPABLE = [
P_51D_30_NA,
P_51D,
+ P_47D_30,
A_20G,
SpitfireLFMkIXCW,
@@ -169,6 +171,7 @@ STRIKE_CAPABLE = [
P_51D_30_NA,
P_51D,
+ P_47D_30,
A_20G,
SpitfireLFMkIXCW,
diff --git a/qt_ui/main.py b/qt_ui/main.py
index b71975a8..649a3ec5 100644
--- a/qt_ui/main.py
+++ b/qt_ui/main.py
@@ -4,6 +4,7 @@ import sys
from shutil import copyfile
import dcs
+from PySide2 import QtWidgets
from PySide2.QtGui import QPixmap
from PySide2.QtWidgets import QApplication, QSplashScreen
from dcs import installation
@@ -11,12 +12,22 @@ from dcs import installation
from qt_ui import uiconstants
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal
from qt_ui.windows.QLiberationWindow import QLiberationWindow
-from userdata import persistency, logging as logging_module
+from qt_ui.windows.preferences.QLiberationFirstStartWindow import QLiberationFirstStartWindow
+from userdata import persistency, logging as logging_module, liberation_install
if __name__ == "__main__":
- persistency.setup(installation.get_dcs_saved_games_directory())
+ app = QApplication(sys.argv)
+ css = ""
+ with open("./resources/stylesheets/style.css") as stylesheet:
+ app.setStyleSheet(stylesheet.read())
+
+ # Logging setup
+ VERSION_STRING = "2.0RC6"
+ logging_module.setup_version_string(VERSION_STRING)
+
+ # Inject custom payload in pydcs framework
custom_payloads = os.path.join(os.path.dirname(os.path.realpath(__file__)), "..\\resources\\customized_payloads")
if os.path.exists(custom_payloads):
dcs.planes.FlyingType.payload_dirs.append(custom_payloads)
@@ -27,11 +38,14 @@ if __name__ == "__main__":
if os.path.exists(custom_payloads):
dcs.planes.FlyingType.payload_dirs.append(custom_payloads)
- VERSION_STRING = "2.0RC6"
- logging_module.setup_version_string(VERSION_STRING)
- logging.info("Using {} as userdata folder".format(persistency.base_path()))
- app = QApplication(sys.argv)
+ first_start = liberation_install.init()
+ if first_start:
+ window = QLiberationFirstStartWindow()
+ window.exec_()
+
+ logging.info("Using {} as 'Saved Game Folder'".format(persistency.base_path()))
+ logging.info("Using {} as 'DCS installation folder'".format(liberation_install.get_dcs_install_directory()))
# Splash screen setup
pixmap = QPixmap("./resources/ui/splash_screen.png")
@@ -44,24 +58,28 @@ if __name__ == "__main__":
uiconstants.load_aircraft_icons()
uiconstants.load_vehicle_icons()
-
- css = ""
- with open("./resources/stylesheets/style.css") as stylesheet:
- css = stylesheet.read()
-
# Replace DCS Mission scripting file to allow DCS Liberation to work
- print("Replace : " + installation.get_dcs_install_directory() + os.path.sep + "Scripts/MissionScripting.lua")
- copyfile("./resources/scripts/MissionScripting.lua", installation.get_dcs_install_directory() + os.path.sep + "Scripts/MissionScripting.lua")
- app.processEvents()
+ try:
+ liberation_install.replace_mission_scripting_file()
+ except:
+ error_dialog = QtWidgets.QErrorMessage()
+ error_dialog.setWindowTitle("Wrong DCS installation directory.")
+ error_dialog.showMessage("Unable to modify Mission Scripting file. Possible issues with rights. Try running as admin, or please perform the modification of the MissionScripting file manually.")
+ error_dialog.exec_()
# Apply CSS (need works)
- app.setStyleSheet(css)
GameUpdateSignal()
# Start window
window = QLiberationWindow()
window.showMaximized()
-
splash.finish(window)
- sys.exit(app.exec_())
+ qt_execution_code = app.exec_()
+
+ # Restore Mission Scripting file
+ logging.info("QT App terminated with status code : " + str(qt_execution_code))
+ logging.info("Attempt to restore original mission scripting file")
+ liberation_install.restore_original_mission_scripting()
+ sys.exit(qt_execution_code)
+
diff --git a/qt_ui/uiconstants.py b/qt_ui/uiconstants.py
index 63e8ccb2..0fe11d9e 100644
--- a/qt_ui/uiconstants.py
+++ b/qt_ui/uiconstants.py
@@ -8,12 +8,12 @@ from game.event import UnitsDeliveryEvent, FrontlineAttackEvent
from theater.theatergroundobject import CATEGORY_MAP
URLS : Dict[str, str] = {
- "Manual": "https://github.com/shdwp/dcs_liberation/wiki/Manual",
+ "Manual": "https://github.com/khopa/dcs_liberation/wiki",
"Troubleshooting": "https://github.com/shdwp/dcs_liberation/wiki/Troubleshooting",
"Modding": "https://github.com/shdwp/dcs_liberation/wiki/Modding-tutorial",
- "Repository": "https://github.com/shdwp/dcs_liberation",
+ "Repository": "https://github.com/khopa/dcs_liberation",
"ForumThread": "https://forums.eagle.ru/showthread.php?t=214834",
- "Issues": "https://github.com/shdwp/dcs_liberation/issues"
+ "Issues": "https://github.com/khopa/dcs_liberation/issues"
}
LABELS_OPTIONS = ["Full", "Abbreviated", "Dot Only", "Off"]
diff --git a/qt_ui/windows/QLiberationWindow.py b/qt_ui/windows/QLiberationWindow.py
index 31ba3bac..605ad1e5 100644
--- a/qt_ui/windows/QLiberationWindow.py
+++ b/qt_ui/windows/QLiberationWindow.py
@@ -1,10 +1,9 @@
import sys
import webbrowser
-from PySide2 import QtGui
from PySide2.QtCore import Qt
from PySide2.QtGui import QIcon
-from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget, \
+from PySide2.QtWidgets import QWidget, QVBoxLayout, QMainWindow, QAction, QMessageBox, QDesktopWidget, \
QSplitter
import qt_ui.uiconstants as CONST
@@ -12,10 +11,12 @@ from game import Game
from qt_ui.uiconstants import URLS
from qt_ui.widgets.QTopPanel import QTopPanel
from qt_ui.widgets.map.QLiberationMap import QLiberationMap
+from qt_ui.windows.preferences import QLiberationPreferences
from qt_ui.windows.GameUpdateSignal import GameUpdateSignal, DebriefingSignal
from qt_ui.windows.QDebriefingWindow import QDebriefingWindow
from qt_ui.windows.QNewGameWizard import NewGameWizard
from qt_ui.windows.infos.QInfoPanel import QInfoPanel
+from qt_ui.windows.preferences.QLiberationPreferencesWindow import QLiberationPreferencesWindow
from userdata import persistency
@@ -79,6 +80,10 @@ class QLiberationWindow(QMainWindow):
self.showAboutDialogAction.setIcon(QIcon.fromTheme("help-about"))
self.showAboutDialogAction.triggered.connect(self.showAboutDialog)
+ self.showLiberationPrefDialogAction = QAction("Preferences", self)
+ self.showLiberationPrefDialogAction.setIcon(QIcon.fromTheme("help-about"))
+ self.showLiberationPrefDialogAction.triggered.connect(self.showLiberationDialog)
+
def initToolbar(self):
self.tool_bar = self.addToolBar("File")
self.tool_bar.addAction(self.newGameAction)
@@ -92,17 +97,21 @@ class QLiberationWindow(QMainWindow):
file_menu.addAction(self.newGameAction)
#file_menu.addAction(QIcon(CONST.ICONS["Open"]), "Open") # TODO : implement
file_menu.addAction(self.saveGameAction)
+ file_menu.addSeparator()
+ file_menu.addAction(self.showLiberationPrefDialogAction)
+ file_menu.addSeparator()
#file_menu.addAction("Save As") # TODO : implement
#file_menu.addAction("Close Current Game", lambda: self.closeGame()) # Not working
file_menu.addAction("Exit" , lambda: self.exit())
help_menu = self.menu.addMenu("Help")
- #help_menu.addAction("Online Manual", lambda: webbrowser.open_new_tab(URLS["Manual"]))
+ help_menu.addAction("Online Manual", lambda: webbrowser.open_new_tab(URLS["Manual"]))
+ help_menu.addAction("Discord", lambda: webbrowser.open_new_tab("https://" + "discord.gg" + "/" + "bKrt" + "rkJ"))
#help_menu.addAction("Troubleshooting Guide", lambda: webbrowser.open_new_tab(URLS["Troubleshooting"]))
#help_menu.addAction("Modding Guide", lambda: webbrowser.open_new_tab(URLS["Modding"]))
#help_menu.addSeparator() ----> Note from Khopa : I disable these links since it's not up to date for this branch
- help_menu.addAction("Contribute", lambda: webbrowser.open_new_tab(URLS["Repository"]))
+ #help_menu.addAction("Contribute", lambda: webbrowser.open_new_tab(URLS["Repository"]))
help_menu.addAction("Forum Thread", lambda: webbrowser.open_new_tab(URLS["ForumThread"]))
help_menu.addAction("Report an issue", lambda: webbrowser.open_new_tab(URLS["Issues"]))
help_menu.addSeparator()
@@ -192,6 +201,10 @@ class QLiberationWindow(QMainWindow):
print(about.textFormat())
about.exec_()
+ def showLiberationDialog(self):
+ self.subwindow = QLiberationPreferencesWindow()
+ self.subwindow.show()
+
def onDebriefing(self, debrief: DebriefingSignal):
print("On Debriefing")
self.debriefing = QDebriefingWindow(debrief.debriefing, debrief.gameEvent, debrief.game)
diff --git a/qt_ui/windows/preferences/QLiberationFirstStartWindow.py b/qt_ui/windows/preferences/QLiberationFirstStartWindow.py
new file mode 100644
index 00000000..f441f2d3
--- /dev/null
+++ b/qt_ui/windows/preferences/QLiberationFirstStartWindow.py
@@ -0,0 +1,80 @@
+from PySide2.QtGui import QIcon, Qt
+from PySide2.QtWidgets import QDialog, QVBoxLayout, QPushButton, QHBoxLayout, QPlainTextEdit, QTextEdit
+
+from qt_ui.windows.preferences.QLiberationPreferences import QLiberationPreferences
+
+
+class QLiberationFirstStartWindow(QDialog):
+
+ def __init__(self):
+ super(QLiberationFirstStartWindow, self).__init__()
+
+ self.setModal(True)
+ self.setWindowTitle("First start configuration")
+ self.setMinimumSize(500, 200)
+ self.setWindowIcon(QIcon("./resources/icon.png"))
+ self.setWindowFlags(Qt.WindowStaysOnTopHint | Qt.Dialog | Qt.WindowTitleHint)
+ self.setWindowModality(Qt.WindowModal)
+ self.preferences = QLiberationPreferences()
+
+ WARN_TEXT = """
+ Welcome to DCS Liberation !
+
+ Please take 30 seconds to read this :
+
+
DCS Liberation will modify this file in your DCS installation directory :
+
+ <dcs_installation_directory>/Scripts/MissionScripting.lua
+
+
+ This will disable some security limits of the DCS World Lua scripting environment, in order to allow communication between DCS World and DCS Liberation.
+ However, the modification of this file could potentially grant access to your filesystem to malicious DCS mission files.
+
+
+ So, you should not join untrusted servers or open untrusted mission files within DCS world while DCS Liberation is running.
+
+
+ DCS Liberation will restore your original MissionScripting file when it close.
+
+
+
+ However, should DCS Liberation encounter an unexpected crash (which should not happen), the MissionScripting file might not be restored.
+ If that occurs, you can use the backup file saved in the DCS Liberation directory there :
+
+
+
+ ./resources/scripts/MissionScripting.original.lua
+
+ Then copy it in your DCS installation directory to replace this file :
+
+
+ <dcs_installation_directory>/Scripts/MissionScripting.lua
+
+ As you click on the button below, the file will be replaced in your DCS installation directory.
+
+
+
+ Thank you for reading !
+ """
+ self.warning_text = QTextEdit(WARN_TEXT)
+ self.warning_text.setReadOnly(True)
+ self.apply_button = QPushButton("I have read everything and I Accept")
+ self.apply_button.clicked.connect(lambda : self.apply())
+ self.initUI()
+
+ def initUI(self):
+ layout = QVBoxLayout()
+ layout.addWidget(self.preferences)
+ layout.addWidget(self.warning_text)
+ layout.addStretch()
+ apply_btn_layout = QHBoxLayout()
+ apply_btn_layout.addStretch()
+ apply_btn_layout.addWidget(self.apply_button)
+ layout.addLayout(apply_btn_layout)
+ self.setLayout(layout)
+
+ def apply(self):
+ print("Applying changes")
+ if self.preferences.apply():
+ self.close()
+
diff --git a/qt_ui/windows/preferences/QLiberationPreferences.py b/qt_ui/windows/preferences/QLiberationPreferences.py
new file mode 100644
index 00000000..eba000fe
--- /dev/null
+++ b/qt_ui/windows/preferences/QLiberationPreferences.py
@@ -0,0 +1,93 @@
+import os
+
+from PySide2 import QtWidgets
+from PySide2.QtGui import Qt
+from PySide2.QtWidgets import QFrame, QLineEdit, QGridLayout, QVBoxLayout, QLabel, QPushButton, \
+ QFileDialog, QMessageBox, QDialog
+
+from userdata import liberation_install
+
+
+class QLiberationPreferences(QFrame):
+
+ def __init__(self):
+ super(QLiberationPreferences, self).__init__()
+ self.saved_game_dir = ""
+ self.dcs_install_dir = ""
+
+ self.dcs_install_dir = liberation_install.get_dcs_install_directory()
+ self.saved_game_dir = liberation_install.get_saved_game_dir()
+
+ self.edit_dcs_install_dir = QLineEdit(self.dcs_install_dir)
+ self.edit_saved_game_dir = QLineEdit(self.saved_game_dir)
+
+ self.edit_dcs_install_dir.setMinimumWidth(300)
+ self.edit_saved_game_dir.setMinimumWidth(300)
+
+ self.browse_saved_game = QPushButton("Browse...")
+ self.browse_saved_game.clicked.connect(self.on_browse_saved_games)
+ self.browse_install_dir = QPushButton("Browse...")
+ self.browse_install_dir.clicked.connect(self.on_browse_installation_dir)
+
+ self.initUi()
+
+ def initUi(self):
+ main_layout = QVBoxLayout()
+ layout = QGridLayout()
+ layout.addWidget(QLabel("DCS saved game directory:"), 0, 0, alignment=Qt.AlignLeft)
+ layout.addWidget(self.edit_saved_game_dir, 1, 0, alignment=Qt.AlignRight)
+ layout.addWidget(self.browse_saved_game, 1, 1, alignment=Qt.AlignRight)
+ layout.addWidget(QLabel("DCS installation directory:"), 2, 0, alignment=Qt.AlignLeft)
+ layout.addWidget(self.edit_dcs_install_dir, 3, 0, alignment=Qt.AlignRight)
+ layout.addWidget(self.browse_install_dir, 3, 1, alignment=Qt.AlignRight)
+
+ main_layout.addLayout(layout)
+ main_layout.addStretch()
+
+ self.setLayout(main_layout)
+
+ def on_browse_saved_games(self):
+ saved_game_dir = str(QFileDialog.getExistingDirectory(self, "Select DCS Saved Game Directory"))
+ if saved_game_dir:
+ self.saved_game_dir = saved_game_dir
+ self.edit_saved_game_dir.setText(saved_game_dir)
+
+ def on_browse_installation_dir(self):
+ install_dir = str(QFileDialog.getExistingDirectory(self, "Select DCS Installation Directory"))
+ if install_dir:
+ self.dcs_install_dir = install_dir
+ self.edit_dcs_install_dir.setText(install_dir)
+
+ def apply(self):
+
+ print("Applying changes")
+ self.saved_game_dir = self.edit_saved_game_dir.text()
+ self.dcs_install_dir = self.edit_dcs_install_dir.text()
+
+ if not os.path.isdir(self.saved_game_dir):
+ error_dialog = QMessageBox.critical(self, "Wrong DCS Saved Games directory.",
+ self.saved_game_dir + " is not a valid directory",
+ QMessageBox.StandardButton.Ok)
+ error_dialog.exec_()
+ return False
+
+ if 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",
+ QMessageBox.StandardButton.Ok)
+ error_dialog.exec_()
+ return False
+
+ if 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(self, "Wrong DCS installation directory.",
+ self.dcs_install_dir + " is not a valid DCS installation directory",
+ QMessageBox.StandardButton.Ok)
+ error_dialog.exec_()
+ return False
+
+ liberation_install.setup(self.saved_game_dir, self.dcs_install_dir)
+ liberation_install.save_config()
+ return True
+
+
+
diff --git a/qt_ui/windows/preferences/QLiberationPreferencesWindow.py b/qt_ui/windows/preferences/QLiberationPreferencesWindow.py
new file mode 100644
index 00000000..ce5a65ff
--- /dev/null
+++ b/qt_ui/windows/preferences/QLiberationPreferencesWindow.py
@@ -0,0 +1,37 @@
+from PySide2.QtGui import QIcon, Qt
+from PySide2.QtWidgets import QDialog, QVBoxLayout, QPushButton, QHBoxLayout
+
+from qt_ui.windows.preferences.QLiberationPreferences import QLiberationPreferences
+
+
+class QLiberationPreferencesWindow(QDialog):
+
+ def __init__(self):
+ super(QLiberationPreferencesWindow, self).__init__()
+
+ self.setModal(True)
+ self.setWindowTitle("Preferences")
+ self.setMinimumSize(300, 200)
+ self.setWindowIcon(QIcon("./resources/icon.png"))
+ self.preferences = QLiberationPreferences()
+ self.apply_button = QPushButton("Apply")
+ self.apply_button.clicked.connect(lambda : self.apply())
+ self.initUI()
+
+ def initUI(self):
+ layout = QVBoxLayout()
+ layout.addWidget(self.preferences)
+ layout.addStretch()
+ apply_btn_layout = QHBoxLayout()
+ apply_btn_layout.addStretch()
+ apply_btn_layout.addWidget(self.apply_button)
+ layout.addLayout(apply_btn_layout)
+ self.setLayout(layout)
+
+ def apply(self):
+ if self.preferences.apply():
+ print("Closing")
+ self.close()
+ else:
+ print("Not Closing")
+
diff --git a/qt_ui/windows/settings/QSettingsWindow.py b/qt_ui/windows/settings/QSettingsWindow.py
index efec774f..3f660ed3 100644
--- a/qt_ui/windows/settings/QSettingsWindow.py
+++ b/qt_ui/windows/settings/QSettingsWindow.py
@@ -98,11 +98,11 @@ class QSettingsWindow(QDialog):
self.enemyAASkill.currentIndexChanged.connect(self.applySettings)
self.difficultyLayout.addWidget(QLabel("Player coalition skill"), 0, 0)
- self.difficultyLayout.addWidget(self.playerCoalitionSkill, 0, 1)
+ self.difficultyLayout.addWidget(self.playerCoalitionSkill, 0, 1, Qt.AlignRight)
self.difficultyLayout.addWidget(QLabel("Enemy skill"), 1, 0)
- self.difficultyLayout.addWidget(self.enemyCoalitionSkill, 1, 1)
+ self.difficultyLayout.addWidget(self.enemyCoalitionSkill, 1, 1, Qt.AlignRight)
self.difficultyLayout.addWidget(QLabel("Enemy AA and vehicles skill"), 2, 0)
- self.difficultyLayout.addWidget(self.enemyAASkill, 2, 1)
+ self.difficultyLayout.addWidget(self.enemyAASkill, 2, 1, Qt.AlignRight)
self.difficultyLabel = QComboBox()
[self.difficultyLabel.addItem(t) for t in CONST.LABELS_OPTIONS]
@@ -110,13 +110,13 @@ class QSettingsWindow(QDialog):
self.difficultyLabel.currentIndexChanged.connect(self.applySettings)
self.difficultyLayout.addWidget(QLabel("In Game Labels"), 3, 0)
- self.difficultyLayout.addWidget(self.difficultyLabel, 3, 1)
+ self.difficultyLayout.addWidget(self.difficultyLabel, 3, 1, Qt.AlignRight)
self.noNightMission = QCheckBox()
self.noNightMission.setChecked(self.game.settings.night_disabled)
self.noNightMission.toggled.connect(self.applySettings)
self.difficultyLayout.addWidget(QLabel("No night missions"), 4, 0)
- self.difficultyLayout.addWidget(self.noNightMission, 4, 1)
+ self.difficultyLayout.addWidget(self.noNightMission, 4, 1, Qt.AlignRight)
def initGeneratorLayout(self):
@@ -135,7 +135,7 @@ class QSettingsWindow(QDialog):
self.supercarrier.toggled.connect(self.applySettings)
self.gameplayLayout.addWidget(QLabel("Use Supercarrier Module"), 0, 0)
- self.gameplayLayout.addWidget(self.supercarrier, 0, 1)
+ self.gameplayLayout.addWidget(self.supercarrier, 0, 1, Qt.AlignRight)
self.performance = QGroupBox("Performance")
self.performanceLayout = QGridLayout();
@@ -162,16 +162,22 @@ class QSettingsWindow(QDialog):
self.infantry.setChecked(self.game.settings.perf_infantry)
self.infantry.toggled.connect(self.applySettings)
+ self.ai_parking_start = QCheckBox()
+ self.ai_parking_start.setChecked(self.game.settings.perf_ai_parking_start)
+ self.ai_parking_start.toggled.connect(self.applySettings)
+
self.performanceLayout.addWidget(QLabel("Smoke visual effect on frontline"), 0, 0)
- self.performanceLayout.addWidget(self.smoke, 0, 1)
+ self.performanceLayout.addWidget(self.smoke, 0, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("SAM starts in RED alert mode"), 1, 0)
- self.performanceLayout.addWidget(self.red_alert, 1, 1)
+ self.performanceLayout.addWidget(self.red_alert, 1, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("Artillery strikes"), 2, 0)
- self.performanceLayout.addWidget(self.arti, 2, 1)
+ self.performanceLayout.addWidget(self.arti, 2, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("Moving ground units"), 3, 0)
- self.performanceLayout.addWidget(self.moving_units, 3, 1)
+ self.performanceLayout.addWidget(self.moving_units, 3, 1, alignment=Qt.AlignRight)
self.performanceLayout.addWidget(QLabel("Generate infantry squads along vehicles"), 4, 0)
- self.performanceLayout.addWidget(self.infantry, 4, 1)
+ self.performanceLayout.addWidget(self.infantry, 4, 1, alignment=Qt.AlignRight)
+ self.performanceLayout.addWidget(QLabel("AI planes parking start (AI starts in flight if disabled)"), 5, 0)
+ self.performanceLayout.addWidget(self.ai_parking_start, 5, 1, alignment=Qt.AlignRight)
self.generatorLayout.addWidget(self.gameplay)
self.generatorLayout.addWidget(QLabel("Disabling settings below may improve performance, but will impact the overall quality of the experience."))
@@ -230,6 +236,7 @@ class QSettingsWindow(QDialog):
self.game.settings.perf_artillery = self.arti.isChecked()
self.game.settings.perf_moving_units = self.moving_units.isChecked()
self.game.settings.perf_infantry = self.infantry.isChecked()
+ self.game.settings.perf_ai_parking_start = self.ai_parking_start.isChecked()
GameUpdateSignal.get_instance().updateGame(self.game)
diff --git a/userdata/dcs_environment.py b/userdata/dcs_environment.py
deleted file mode 100644
index 0c5d1ce4..00000000
--- a/userdata/dcs_environment.py
+++ /dev/null
@@ -1,132 +0,0 @@
-"""
-This utility classes provides methods to check players installed DCS environment.
-
-TODO : add method 'is_using_open_beta', 'is_using_stable'
-TODO : [NICE to have] add method to check list of installed DCS modules (could be done either through window registry, or through filesystem analysis)
-"""
-
-import winreg
-import os
-
-
-def is_using_dcs_steam_edition():
- """
- Check if DCS World : Steam Edition version is installed on this computer
- :return True if DCS Steam edition is installed,
- -1 if DCS Steam Edition is registered in Steam apps but not installed,
- False if never installed in Steam
- """
- try:
- # Note : Steam App ID for DCS World is 223750
- dcs_steam_app_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Valve\\Steam\\Apps\\223750")
- installed = winreg.QueryValueEx(dcs_steam_app_key, "Installed")
- winreg.CloseKey(dcs_steam_app_key)
- if installed[0] == 1:
- return True
- else:
- return False
- except FileNotFoundError as fnfe:
- return False
-
-
-def is_using_dcs_standalone_edition():
- """
- Check if DCS World standalone edition is installed on this computer
- :return True if Standalone is installed, False if it is not
- """
- try:
- dcs_path_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Eagle Dynamics\\DCS World")
- winreg.CloseKey(dcs_path_key)
- return True
- except FileNotFoundError as fnfe:
- return False
-
-
-def _find_steam_directory():
- """
- Get the Steam install directory for this computer from registry
- :return Steam installation path
- """
- try:
- steam_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Valve\\Steam")
- path = winreg.QueryValueEx(steam_key, "SteamPath")[0]
- winreg.CloseKey(steam_key)
- return path
- except FileNotFoundError as fnfe:
- print(fnfe)
- return ""
-
-
-def _get_steam_library_folders():
- """
- Get the installation directory for Steam games
- :return List of Steam library folders where games can be installed
- """
- try:
- steam_dir = _find_steam_directory()
- """
- For reference here is what the vdf file is supposed to look like :
-
- "LibraryFolders"
- {
- "TimeNextStatsReport" "1561832478"
- "ContentStatsID" "-158337411110787451"
- "1" "D:\\Games\\Steam"
- "2" "E:\\Steam"
- }
- """
- vdf_file_location = steam_dir + os.path.sep + "steamapps" + os.path.sep + "libraryfolders.vdf"
- with open(vdf_file_location) as adf_file:
- paths = [l.split("\"")[3] for l in adf_file.readlines()[1:] if ':\\\\' in l]
- return paths
- except Exception as e:
- print(e)
- return []
-
-
-def _find_steam_dcs_directory():
- """
- Find the DCS install directory for DCS World Steam Edition
- :return: Install directory as string, empty string if not found
- """
- for library_folder in _get_steam_library_folders():
- folder = library_folder + os.path.sep + "steamapps" + os.path.sep + "common" + os.path.sep + "DCSWorld"
- if os.path.isdir(folder):
- return folder + os.path.sep
- return ""
-
-
-def get_dcs_install_directory():
- """
- Get the DCS World install directory for this computer
- :return DCS World install directory
- """
- if is_using_dcs_standalone_edition():
- try:
- dcs_path_key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, "Software\\Eagle Dynamics\\DCS World")
- path = winreg.QueryValueEx(dcs_path_key, "Path")
- dcs_dir = path[0] + os.path.sep
- winreg.CloseKey(dcs_path_key)
- return dcs_dir
- except Exception as e:
- print("Couldn't detect DCS World installation folder")
- return ""
- elif is_using_dcs_steam_edition():
- return _find_steam_dcs_directory()
- else:
- print("Couldn't detect any installed DCS World version")
-
-
-def get_dcs_saved_games_directory():
- """
- Get the save game directory for DCS World
- :return: Save game directory as string
- """
- return os.path.join(os.path.expanduser("~"), "Saved Games", "DCS")
-
-
-if __name__ == "__main__":
- print("Using STEAM Edition : " + str(is_using_dcs_steam_edition()))
- print("Using Standalone Edition : " + str(is_using_dcs_standalone_edition()))
- print("DCS Installation directory : " + get_dcs_install_directory())
- print("DCS saved games directory : " + get_dcs_saved_games_directory())
\ No newline at end of file
diff --git a/userdata/liberation_install.py b/userdata/liberation_install.py
new file mode 100644
index 00000000..5f19ec0a
--- /dev/null
+++ b/userdata/liberation_install.py
@@ -0,0 +1,99 @@
+import json
+import os
+from shutil import copyfile
+
+import dcs
+
+from userdata import persistency
+
+global __dcs_saved_game_directory
+global __dcs_installation_directory
+
+PREFERENCES_FILE_PATH = "liberation_preferences.json"
+
+def init():
+ global __dcs_saved_game_directory
+ global __dcs_installation_directory
+
+ if os.path.isfile(PREFERENCES_FILE_PATH):
+ try:
+ with(open(PREFERENCES_FILE_PATH)) as prefs:
+ pref_data = json.loads(prefs.read())
+ __dcs_saved_game_directory = pref_data["saved_game_dir"]
+ __dcs_installation_directory = pref_data["dcs_install_dir"]
+ is_first_start = False
+ except:
+ __dcs_saved_game_directory = ""
+ __dcs_installation_directory = ""
+ is_first_start = True
+ else:
+ try:
+ __dcs_saved_game_directory = dcs.installation.get_dcs_saved_games_directory()
+ if os.path.exists(__dcs_saved_game_directory + ".openbeta"):
+ __dcs_saved_game_directory = dcs.installation.get_dcs_saved_games_directory() + ".openbeta"
+ except:
+ __dcs_saved_game_directory = ""
+ try:
+ __dcs_installation_directory = dcs.installation.get_dcs_install_directory()
+ except:
+ __dcs_installation_directory = ""
+
+ is_first_start = True
+ persistency.setup(__dcs_saved_game_directory)
+ return is_first_start
+
+
+def setup(saved_game_dir, install_dir):
+ global __dcs_saved_game_directory
+ global __dcs_installation_directory
+ __dcs_saved_game_directory = saved_game_dir
+ __dcs_installation_directory = install_dir
+ persistency.setup(__dcs_saved_game_directory)
+
+
+def save_config():
+ global __dcs_saved_game_directory
+ global __dcs_installation_directory
+ pref_data = {"saved_game_dir": __dcs_saved_game_directory,
+ "dcs_install_dir": __dcs_installation_directory}
+ with(open(PREFERENCES_FILE_PATH, "w")) as prefs:
+ prefs.write(json.dumps(pref_data))
+
+
+def get_dcs_install_directory():
+ global __dcs_installation_directory
+ return __dcs_installation_directory
+
+
+def get_saved_game_dir():
+ global __dcs_saved_game_directory
+ return __dcs_saved_game_directory
+
+
+def replace_mission_scripting_file():
+ install_dir = get_dcs_install_directory()
+ mission_scripting_path = os.path.join(install_dir, "Scripts", "MissionScripting.lua")
+ liberation_scripting_path = "./resources/scripts/MissionScripting.lua"
+ backup_scripting_path = "./resources/scripts/MissionScripting.original.lua"
+ if os.path.isfile(mission_scripting_path):
+ with open(mission_scripting_path, "r") as ms:
+ current_file_content = ms.read()
+ with open(liberation_scripting_path, "r") as libe_ms:
+ liberation_file_content = libe_ms.read()
+
+ # Save original file
+ if current_file_content != liberation_file_content:
+ copyfile(mission_scripting_path, backup_scripting_path)
+
+ # Replace DCS file
+ copyfile(liberation_scripting_path, mission_scripting_path)
+
+
+def restore_original_mission_scripting():
+ install_dir = get_dcs_install_directory()
+ mission_scripting_path = os.path.join(install_dir, "Scripts", "MissionScripting.lua")
+ backup_scripting_path = "./resources/scripts/MissionScripting.original.lua"
+
+ if os.path.isfile(backup_scripting_path) and os.path.isfile(mission_scripting_path):
+ copyfile(backup_scripting_path, mission_scripting_path)
+
diff --git a/userdata/persistency.py b/userdata/persistency.py
index 020bcf1f..fa833597 100644
--- a/userdata/persistency.py
+++ b/userdata/persistency.py
@@ -2,9 +2,6 @@ import logging
import os
import pickle
import shutil
-import sys
-
-from dcs import installation
_dcs_saved_game_folder = None # type: str
@@ -17,12 +14,7 @@ def setup(user_folder: str):
def base_path() -> str:
global _dcs_saved_game_folder
assert _dcs_saved_game_folder
-
- openbeta_path = _dcs_saved_game_folder + ".openbeta"
- if os.path.exists(openbeta_path):
- return openbeta_path # For standalone openbeta users
- else:
- return _dcs_saved_game_folder # For standalone stable users & steam users (any branch)
+ return _dcs_saved_game_folder
def _save_file() -> str: