1.2 update

..
This commit is contained in:
spencer-ki
2022-05-06 21:52:53 -07:00
parent 2ebafda806
commit 8ffaab1e6a
43 changed files with 1481 additions and 8393 deletions

View File

@@ -2,6 +2,7 @@ import json
import yaml
import sys
import os
import operator
import RotorOpsMission as ROps
import RotorOpsUnits
@@ -28,10 +29,18 @@ import qtmodern.windows
# UPDATE BUILD VERSION
maj_version = 1
minor_version = 1
patch_version = 2
minor_version = 2
patch_version = 0
modules_version = 2
modules_url = 'https://dcs-helicopters.com/user-files/modules/'
version_url = 'https://dcs-helicopters.com/app-updates/versions.yaml'
modules_map_url = 'https://dcs-helicopters.com/user-files/modules/module-map-v2.yaml'
ratings_url = 'https://dcs-helicopters.com/user-files/ratings.php'
allowed_paths = ['templates\\Scenarios\\downloaded', 'templates\\Forces\\downloaded', 'templates\\Imports\\downloaded']
user_files_url = 'https://dcs-helicopters.com/user-files/'
version_url = 'https://dcs-helicopters.com/app-updates/versioncheck.yaml'
#Setup logfile and exception handler
logger = logging.getLogger(__name__)
@@ -50,27 +59,39 @@ class directories:
os.chdir("..")
cls.home_dir = os.getcwd()
cls.scenarios = cls.home_dir + "\\templates\\Scenarios"
cls.forces = cls.home_dir + "\\templates\\Forces"
cls.forces_downloaded = cls.home_dir + "\\templates\\Forces\\downloaded"
cls.forces_user = cls.home_dir + "\\templates\\Forces\\user"
cls.scripts = cls.home_dir + "\\scripts"
cls.sound = cls.home_dir + "\\sound\\embedded"
cls.output = cls.home_dir + "\\MissionOutput"
cls.assets = cls.home_dir + "\\assets"
cls.imports = cls.home_dir + "\\templates\\Imports"
cls.imports_downloaded = cls.home_dir + "\\templates\\Imports\\downloaded"
cls.imports_user = cls.home_dir + "\\templates\\Imports\\user"
cls.user_datafile_path = cls.home_dir + "\\config\\user-data.yaml"
cls.scenarios_downloaded = cls.scenarios + "\\downloaded"
cls.scenarios_user = cls.scenarios + "\\user"
cls.default_config = cls.home_dir + '\\config\\default-config.yaml'
os.chdir(current_dir)
directories.find()
@classmethod
def createDirectories(cls):
required_dirs = [cls.scenarios_user, cls.scenarios_downloaded, cls.imports_user, cls.imports_downloaded, cls.forces_user, cls.forces_downloaded, cls.output]
for path in required_dirs:
if not os.path.exists(path):
os.makedirs(path)
import MissionGeneratorScenario
directories.find()
directories.createDirectories()
import MissionGeneratorTemplates
def handle_exception(exc_type, exc_value, exc_traceback):
if issubclass(exc_type, KeyboardInterrupt): #example of handling error subclasses
sys.__excepthook__(exc_type, exc_value, exc_traceback)
return
QApplication.restoreOverrideCursor()
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
msg = QMessageBox()
msg.setWindowTitle("Uncaught exception")
@@ -82,9 +103,6 @@ sys.excepthook = handle_exception
version_string = str(maj_version) + "." + str(minor_version) + "." + str(patch_version)
# scenarios = []
red_forces_files = []
blue_forces_files = []
defenders_text = "Defending Forces:"
attackers_text = "Attacking Forces:"
ratings_json = None
@@ -120,16 +138,17 @@ class Window(QMainWindow, Ui_MainWindow):
self.player_slots = []
self.user_output_dir = None
self.user_data = None
self.forces_list = []
self.imports_list = []
self.user_data = self.loadUserData()
self.m = ROps.RotorOpsMission()
self.setupUi(self)
self.connectSignalsSlots()
self.populateScenarios()
self.populateForces("red", self.redforces_comboBox, red_forces_files)
self.populateForces("blue", self.blueforces_comboBox, blue_forces_files)
self.populateForces()
self.populateSlotSelection()
self.getImports()
# self.blue_forces_label.setText(attackers_text)
# self.red_forces_label.setText(defenders_text)
@@ -139,11 +158,15 @@ class Window(QMainWindow, Ui_MainWindow):
"QStatusBar{padding-left:5px;}")
self.version_label.setText("Version " + version_string)
self.scenarioChanged()
self.time_comboBox.addItem("Default Time")
self.time_comboBox.addItem("Day")
self.time_comboBox.addItem("Night")
self.time_comboBox.addItem("Dusk")
self.time_comboBox.addItem("Dawn")
self.time_comboBox.addItem("Noon")
self.time_comboBox.addItem("Random")
def connectSignalsSlots(self):
@@ -212,7 +235,7 @@ class Window(QMainWindow, Ui_MainWindow):
basename = filename.removesuffix('.miz')
mizpath = os.path.join(path, folder, filename)
# create scenario object
s = MissionGeneratorScenario.Scenario(mizpath, basename)
s = MissionGeneratorTemplates.Scenario(mizpath, basename)
#apply some properties if found in the downloads directory
if path == directories.scenarios_downloaded:
@@ -221,7 +244,6 @@ class Window(QMainWindow, Ui_MainWindow):
s.packageID = folder
if ratings_json:
print(ratings_json)
for module in ratings_json:
if module['package'] == folder:
s.rating = module["avg_rating"]
@@ -256,8 +278,8 @@ class Window(QMainWindow, Ui_MainWindow):
t_scenarios.append(s)
scenarios = t_scenarios.copy()
#self.scenario_comboBox.addItem(s.name)
self.scenarios_list = scenarios.copy()
self.scenarios_list = sorted(scenarios, key=lambda x: x.name, reverse=False)
for s in self.scenarios_list:
self.scenario_comboBox.addItem(s.name)
@@ -268,18 +290,67 @@ class Window(QMainWindow, Ui_MainWindow):
self.populateScenarios()
# self.scenarioChanged() haven't tried yet
def populateForces(self, side, combobox, files_list):
os.chdir(directories.home_dir)
# os.chdir(directories.forces + "/" + side)
os.chdir(directories.forces)
path = os.getcwd()
dir_list = os.listdir(path)
logger.info("Looking for " + side + " Forces files in '" + path)
def populateForces(self):
self.forces_list = []
for filename in dir_list:
if filename.endswith(".miz"):
files_list.append(filename)
combobox.addItem(filename.removesuffix('.miz'))
for path in [directories.forces_downloaded, directories.forces_user]:
logger.info("Looking for forces files in " + path)
os.chdir(path)
module_folders = next(os.walk('.'))[1]
for folder in module_folders:
for filename in os.listdir(folder):
if filename.endswith(".miz"):
basename = filename.removesuffix('.miz')
mizpath = os.path.join(path, folder, filename)
config_file_path = os.path.join(path, folder, basename + '.yaml')
if os.path.exists(config_file_path):
# create forces object with config
try:
config = yaml.safe_load(open(config_file_path))
f = MissionGeneratorTemplates.Forces(mizpath, filename, config)
self.forces_list.append(f)
except:
logger.error("Error in " + config_file_path)
else:
# create forces object without config
f = MissionGeneratorTemplates.Forces(mizpath, basename)
self.forces_list.append(f)
self.forces_list = sorted(self.forces_list, key=lambda x: x.name, reverse=False)
for forces in self.forces_list:
self.redforces_comboBox.addItem(forces.name)
self.blueforces_comboBox.addItem(forces.name)
def getImports(self):
self.imports_list = []
for path in [directories.imports_downloaded, directories.imports_user]:
logger.info("Looking for imports files in " + path)
os.chdir(path)
module_folders = next(os.walk('.'))[1]
for folder in module_folders:
for filename in os.listdir(folder):
if filename.endswith(".miz"):
basename = filename.removesuffix('.miz')
mizpath = os.path.join(path, folder, filename)
config_file_path = os.path.join(path, folder, basename + '.yaml')
if os.path.exists(config_file_path):
# create imports object with config
try:
config = yaml.safe_load(config_file_path)
f = MissionGeneratorTemplates.Import(mizpath, filename, config)
self.imports_list.append(f)
except:
logger.error("Error in " + config_file_path)
else:
# create imports object without config
f = MissionGeneratorTemplates.Import(mizpath, filename)
self.imports_list.append(f)
def populateSlotSelection(self):
self.slot_template_comboBox.addItem("Multiple Slots")
@@ -321,8 +392,7 @@ class Window(QMainWindow, Ui_MainWindow):
# reset some UI elements
self.defense_checkBox.setEnabled(True)
if self.lockedSlot():
self.slot_template_comboBox.removeItem(self.lockedSlot())
self.slot_template_comboBox.removeItem(self.lockedSlot())
self.slot_template_comboBox.setEnabled(True)
self.slot_template_comboBox.setCurrentIndex(0)
@@ -362,11 +432,14 @@ class Window(QMainWindow, Ui_MainWindow):
button.setEnabled(True)
if 'blue_forces' in config:
self.blueforces_comboBox.setCurrentIndex(self.blueforces_comboBox.findText(config['blue_forces']))
for template in self.forces_list:
if template.basename == config['blue_forces']:
self.blueforces_comboBox.setCurrentIndex(self.blueforces_comboBox.findText(template.name))
if 'red_forces' in config:
if self.redforces_comboBox.findText(config['red_forces']) >= 0:
self.redforces_comboBox.setCurrentIndex(self.redforces_comboBox.findText(config['red_forces']))
for template in self.forces_list:
if template.basename == config['red_forces']:
self.redforces_comboBox.setCurrentIndex(self.redforces_comboBox.findText(template.name))
except Exception as e:
logger.error("Error loading config file: " + str(e))
@@ -416,16 +489,16 @@ class Window(QMainWindow, Ui_MainWindow):
return
QApplication.setOverrideCursor(Qt.WaitCursor)
self.slot_template_comboBox.setCurrentIndex(0)
self.scenario = self.scenarios_list[self.scenario_comboBox.currentIndex()]
# reset generator options to default
default_config = self.loadScenarioConfig(directories.default_config)
self.applyScenarioConfig(default_config)
if self.scenario.config:
self.applyScenarioConfig(self.scenario.config)
self.m.setConfig(self.scenario.config)
else:
default_config = self.loadScenarioConfig(directories.default_config)
self.applyScenarioConfig(default_config)
self.m.setConfig(default_config)
path = self.scenario.path.removesuffix(".miz") + ".jpg"
if os.path.isfile(path):
@@ -462,17 +535,27 @@ class Window(QMainWindow, Ui_MainWindow):
def generateMissionAction(self):
QApplication.setOverrideCursor(Qt.WaitCursor)
red_forces_filename = red_forces_files[self.redforces_comboBox.currentIndex()]
blue_forces_filename = blue_forces_files[self.blueforces_comboBox.currentIndex()]
red_forces = self.forces_list[self.redforces_comboBox.currentIndex()]
blue_forces = self.forces_list[self.blueforces_comboBox.currentIndex()]
scenario_name = self.scenario.name
scenario_path = self.scenario.path
source = "offline"
credits = ("'" + scenario_name + "' mission template by " + self.scenario.author + "\n" +
"'" + red_forces.name + "' by " + red_forces.author + "\n" +
"'" + blue_forces.name + "' by " + blue_forces.author + "\n"
)
objects = {
"imports": self.imports_list,
}
data = {
"source": source,
"objects": objects,
"credits": credits,
"scenario_file": scenario_path,
"scenario_name": scenario_name,
"red_forces_filename": red_forces_filename,
"blue_forces_filename": blue_forces_filename,
"red_forces_path": red_forces.path,
"blue_forces_path": blue_forces.path,
"red_quantity": self.redqty_spinBox.value(),
"blue_quantity": self.blueqty_spinBox.value(),
"inf_spawn_qty": self.inf_spawn_spinBox.value(),
@@ -483,7 +566,7 @@ class Window(QMainWindow, Ui_MainWindow):
"f_awacs": self.awacs_checkBox.isChecked(),
"f_tankers": self.tankers_checkBox.isChecked(),
"voiceovers": self.voiceovers_checkBox.isChecked(),
"force_offroad": self.force_offroad_checkBox.isChecked(),
"force_offroad": self.scenario.getConfigValue("force_offroad", default=False),
"game_display": self.game_status_checkBox.isChecked(),
"defending": self.defense_checkBox.isChecked(),
"slots": self.slot_template_comboBox.currentText(),
@@ -494,6 +577,17 @@ class Window(QMainWindow, Ui_MainWindow):
"smoke_pickup_zones": self.smoke_pickup_zone_checkBox.isChecked(),
"player_slots": self.player_slots,
"player_hotstart": self.hotstart_checkBox.isChecked(),
"random_weather": self.random_weather_checkBox.isChecked(),
"time": self.time_comboBox.currentText(),
"start_trigger": self.scenario.getConfigValue("start_trigger", default=True),
"end_trigger": self.scenario.getConfigValue("end_trigger", default=True),
"farp_spawns": self.farp_spawn_checkBox.isChecked(),
"staging_logistics_file": self.scenario.getConfigValue("staging_logistics_file", default=None),
"zone_farp_file": self.scenario.getConfigValue("zone_farp_file", default=None),
"defensive_farp_file": self.scenario.getConfigValue("defensive_farp_file", default=None),
"logistics_farp_file": self.scenario.getConfigValue("logistics_farp_file", default=None),
"zone_protect_file": self.scenario.getConfigValue("zone_protect_file", default=None),
"script": self.scenario.getConfigValue("script", default=None),
}
logger.info("Generating mission with options:")
@@ -674,7 +768,7 @@ class Window(QMainWindow, Ui_MainWindow):
def checkVersion(splashscreen):
version_url = 'https://dcs-helicopters.com/app-updates/versioncheck.yaml'
try:
r = requests.get(version_url, allow_redirects=False, timeout=7)
v = yaml.safe_load(r.content)
@@ -693,31 +787,33 @@ def checkVersion(splashscreen):
modules_url = 'https://dcs-helicopters.com/user-files/modules/'
version_url = 'https://dcs-helicopters.com/app-updates/versions.yaml'
modules_map_url = 'https://dcs-helicopters.com/user-files/modules/module-map.yaml'
ratings_url = 'https://dcs-helicopters.com/user-files/ratings.php'
def loadModules(splashscreen):
msg = QMessageBox()
msg.setWindowTitle("Unable to connect to server")
msg.setText(
"We were unable to connect to the RotorOps server to download content. This is a temporary problem, so please try again later. If the problem persists, please get in touch via Discord.")
try:
r = requests.get(modules_map_url, allow_redirects=False, timeout=7)
if not r.status_code == 200:
logger.error("Could not retrieve the modules map.")
x = msg.exec_()
return
except:
logger.error("Failed to retrieve module map.")
x = msg.exec_()
return
module_list = yaml.safe_load(r.content)
files_success = []
files_failed = []
new_scenarios = []
updated_scenarios = []
new_modules = []
updated_modules = []
outversioned_modules = []
# Download scenarios files
#os.chdir(directories.scenarios)
if module_list:
for module in module_list:
@@ -725,15 +821,31 @@ def loadModules(splashscreen):
should_download = False
new_module = False
# only allow predefined paths
dp = module_list[module]["path"]
if dp not in allowed_paths:
logger.warning("Invalid path for module: " + module)
continue
# check if local version already exists
package_file_path = os.path.join(directories.scenarios_downloaded, module, "package.yaml")
package_file_path = os.path.join(directories.home_dir, module_list[module]["path"], module, "package.yaml")
if os.path.exists(package_file_path):
pkg_file = yaml.safe_load(open(package_file_path))
else:
pkg_file = None
#compare local and remote versions
# compare required generator version and actual version
if 'requires' in module_list[module]:
if module_list[module]['requires'] > modules_version:
name = 'unknown module'
if 'name' in module_list[module]:
name = module_list[module]['name']
outversioned_modules.append(name)
continue
# compare local and remote versions
if pkg_file and 'version' in pkg_file:
local_version = pkg_file['version']
@@ -744,6 +856,20 @@ def loadModules(splashscreen):
should_download = True
new_module = True
# delete modules with 'remove' dist property
if 'dist' in module_list[module] and module_list[module]['dist'] == 'remove':
for filename in module_list[module]["files"]:
module_dir = os.path.join(directories.home_dir, module_list[module]["path"], module)
file_path = os.path.join(module_dir, filename)
if os.path.exists(file_path):
try:
os.remove(file_path)
print("Removed module file: " + filename)
except:
logger.error("Error while trying to remove " + filename)
continue
# download files
if should_download:
logger.info("Updating module: " + module)
module_dir = os.path.join(directories.home_dir, module_list[module]["path"], module)
@@ -751,10 +877,11 @@ def loadModules(splashscreen):
# download files in remote package
for filename in module_list[module]["files"]:
broken_file = False
type_path = module_list[module]["type"]
splash.showMessage("Downloading " + filename + " ...", Qt.AlignHCenter | Qt.AlignTop, Qt.white)
app.processEvents()
url = modules_url + module + "/" + filename
url = modules_url + type_path + "/" + module + "/" + filename
try:
r = requests.get(url, allow_redirects=False, timeout=10)
except:
@@ -771,9 +898,9 @@ def loadModules(splashscreen):
# do some stuff for the dialog popup
if filename.endswith('.miz') and "name" in module_list[module]:
if new_module:
new_scenarios.append(module_list[module]["name"])
new_modules.append(module_list[module]["name"])
else:
updated_scenarios.append(module_list[module]["name"])
updated_modules.append(module_list[module]["name"])
else:
broken_file = True
files_failed.append(filename)
@@ -791,7 +918,7 @@ def loadModules(splashscreen):
logger.error("Problem encountered with modules map.")
# show a popup if we downloaded any packages
if len(files_success) > 0 or len(files_failed) > 0:
if len(files_success) > 0 or len(files_failed) > 0 or len(outversioned_modules) > 0:
if len(files_failed) > 0:
fs = ""
for filename in files_failed:
@@ -800,16 +927,18 @@ def loadModules(splashscreen):
msg = QMessageBox()
msg.setWindowTitle("Downloaded Files")
message = ""
if len(new_scenarios) > 0:
message = message + "New scenarios added: \n\n"
for name in new_scenarios:
if len(new_modules) > 0:
message = message + "New modules added: \n\n"
for name in new_modules:
message = message + name + "\n"
if len(updated_scenarios) > 0:
message = message + "\nScenarios updated: \n"
for name in updated_scenarios:
if len(updated_modules) > 0:
message = message + "\nModules updated: \n"
for name in updated_modules:
message = message + name + "\n"
if len(files_failed) > 0:
message = message + "\n\n" + str(len(files_failed)) + " files failed."
if len(outversioned_modules) > 0:
message = message + "\n\n" + str(len(outversioned_modules)) + " modules did not download because you need an required update."
msg.setText(message)
x = msg.exec_()
else:

View File

@@ -19,6 +19,8 @@ class Scenario:
self.rating_qty = None
self.packageID = None
self.local_rating = None
self.author = "unknown"
def applyConfig(self, config):
self.config = config
@@ -31,8 +33,16 @@ class Scenario:
if 'tags' in config:
for tag in config['tags']:
self.tags.append(tag)
if 'author' in config:
self.author = config["author"]
def getConfigValue(self, key, default):
if self.config and key in self.config:
return self.config[key]
else:
return default
def evaluateMiz(self):
# check if we have the miz file
@@ -116,3 +126,35 @@ class Scenario:
class Forces:
def __init__(self, path, filename, config=None):
self.path = path
self.filename = filename
self.basename = filename.removesuffix('.miz')
self.name = filename.removesuffix('.miz')
self.author = "unknown"
if config:
if 'name' in config:
self.name = config["name"]
if 'author' in config:
self.author = config["author"]
class Import:
def __init__(self, path, filename, config=None):
self.path = path
self.filename = filename
self.name = filename.removesuffix('.miz')
self.author = "unknown"
if config:
if 'name' in config:
self.name = config["name"]
if 'author' in config:
self.author = config["author"]

View File

@@ -34,7 +34,7 @@ class Ui_MainWindow(object):
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.logistics_crates_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.logistics_crates_checkBox.setGeometry(QtCore.QRect(990, 211, 251, 28))
self.logistics_crates_checkBox.setGeometry(QtCore.QRect(980, 211, 251, 28))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(False)
@@ -42,7 +42,7 @@ class Ui_MainWindow(object):
self.logistics_crates_checkBox.setChecked(True)
self.logistics_crates_checkBox.setObjectName("logistics_crates_checkBox")
self.zone_sams_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.zone_sams_checkBox.setGeometry(QtCore.QRect(990, 320, 241, 28))
self.zone_sams_checkBox.setGeometry(QtCore.QRect(980, 320, 241, 28))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(False)
@@ -79,9 +79,9 @@ class Ui_MainWindow(object):
self.description_textBrowser.setObjectName("description_textBrowser")
self.defense_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.defense_checkBox.setEnabled(True)
self.defense_checkBox.setGeometry(QtCore.QRect(470, 120, 156, 28))
self.defense_checkBox.setGeometry(QtCore.QRect(470, 130, 156, 28))
font = QtGui.QFont()
font.setPointSize(10)
font.setPointSize(11)
font.setBold(False)
self.defense_checkBox.setFont(font)
self.defense_checkBox.setCheckable(True)
@@ -116,7 +116,7 @@ class Ui_MainWindow(object):
self.scenario_label_8.setFont(font)
self.scenario_label_8.setObjectName("scenario_label_8")
self.slot_template_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.slot_template_comboBox.setGeometry(QtCore.QRect(960, 384, 271, 33))
self.slot_template_comboBox.setGeometry(QtCore.QRect(980, 474, 271, 33))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(False)
@@ -216,7 +216,7 @@ class Ui_MainWindow(object):
self.e_attack_helos_spinBox.setKeyboardTracking(True)
self.e_attack_helos_spinBox.setMinimum(0)
self.e_attack_helos_spinBox.setMaximum(8)
self.e_attack_helos_spinBox.setProperty("value", 2)
self.e_attack_helos_spinBox.setProperty("value", 1)
self.e_attack_helos_spinBox.setObjectName("e_attack_helos_spinBox")
self.scenario_label_7 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_7.setGeometry(QtCore.QRect(570, 180, 271, 24))
@@ -226,20 +226,20 @@ class Ui_MainWindow(object):
self.scenario_label_7.setFont(font)
self.scenario_label_7.setObjectName("scenario_label_7")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(840, 390, 111, 24))
self.label_2.setGeometry(QtCore.QRect(860, 480, 111, 24))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(False)
self.label_2.setFont(font)
self.label_2.setObjectName("label_2")
self.scenario_label_9 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_9.setGeometry(QtCore.QRect(490, 450, 251, 23))
self.scenario_label_9.setGeometry(QtCore.QRect(480, 401, 251, 23))
font = QtGui.QFont()
font.setPointSize(10)
self.scenario_label_9.setFont(font)
self.scenario_label_9.setObjectName("scenario_label_9")
self.awacs_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.awacs_checkBox.setGeometry(QtCore.QRect(990, 246, 241, 28))
self.awacs_checkBox.setGeometry(QtCore.QRect(980, 246, 241, 28))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(False)
@@ -247,7 +247,7 @@ class Ui_MainWindow(object):
self.awacs_checkBox.setChecked(True)
self.awacs_checkBox.setObjectName("awacs_checkBox")
self.tankers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.tankers_checkBox.setGeometry(QtCore.QRect(990, 282, 241, 28))
self.tankers_checkBox.setGeometry(QtCore.QRect(980, 282, 241, 28))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(False)
@@ -255,21 +255,21 @@ class Ui_MainWindow(object):
self.tankers_checkBox.setChecked(True)
self.tankers_checkBox.setObjectName("tankers_checkBox")
self.voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.voiceovers_checkBox.setGeometry(QtCore.QRect(960, 517, 171, 24))
self.voiceovers_checkBox.setGeometry(QtCore.QRect(500, 594, 171, 31))
font = QtGui.QFont()
font.setPointSize(9)
self.voiceovers_checkBox.setFont(font)
self.voiceovers_checkBox.setChecked(True)
self.voiceovers_checkBox.setObjectName("voiceovers_checkBox")
self.smoke_pickup_zone_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.smoke_pickup_zone_checkBox.setGeometry(QtCore.QRect(960, 460, 271, 24))
self.smoke_pickup_zone_checkBox.setGeometry(QtCore.QRect(500, 541, 231, 20))
font = QtGui.QFont()
font.setPointSize(9)
self.smoke_pickup_zone_checkBox.setFont(font)
self.smoke_pickup_zone_checkBox.setChecked(False)
self.smoke_pickup_zone_checkBox.setObjectName("smoke_pickup_zone_checkBox")
self.game_status_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.game_status_checkBox.setGeometry(QtCore.QRect(960, 490, 271, 24))
self.game_status_checkBox.setGeometry(QtCore.QRect(500, 570, 221, 21))
font = QtGui.QFont()
font.setPointSize(9)
self.game_status_checkBox.setFont(font)
@@ -277,24 +277,24 @@ class Ui_MainWindow(object):
self.game_status_checkBox.setTristate(False)
self.game_status_checkBox.setObjectName("game_status_checkBox")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(570, 380, 261, 23))
self.label.setGeometry(QtCore.QRect(570, 340, 261, 23))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(False)
self.label.setFont(font)
self.label.setObjectName("label")
self.inf_spawn_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.inf_spawn_spinBox.setGeometry(QtCore.QRect(510, 380, 47, 31))
self.inf_spawn_spinBox.setGeometry(QtCore.QRect(510, 340, 51, 31))
font = QtGui.QFont()
font.setPointSize(12)
self.inf_spawn_spinBox.setFont(font)
self.inf_spawn_spinBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.PlusMinus)
self.inf_spawn_spinBox.setMinimum(0)
self.inf_spawn_spinBox.setMaximum(20)
self.inf_spawn_spinBox.setProperty("value", 2)
self.inf_spawn_spinBox.setProperty("value", 0)
self.inf_spawn_spinBox.setObjectName("inf_spawn_spinBox")
self.troop_drop_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.troop_drop_spinBox.setGeometry(QtCore.QRect(510, 330, 47, 31))
self.troop_drop_spinBox.setGeometry(QtCore.QRect(510, 300, 51, 31))
font = QtGui.QFont()
font.setPointSize(12)
self.troop_drop_spinBox.setFont(font)
@@ -303,23 +303,23 @@ class Ui_MainWindow(object):
self.troop_drop_spinBox.setMaximum(10)
self.troop_drop_spinBox.setProperty("value", 4)
self.troop_drop_spinBox.setObjectName("troop_drop_spinBox")
self.force_offroad_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.force_offroad_checkBox.setGeometry(QtCore.QRect(960, 548, 161, 24))
self.random_weather_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.random_weather_checkBox.setGeometry(QtCore.QRect(980, 420, 211, 24))
font = QtGui.QFont()
font.setPointSize(9)
self.force_offroad_checkBox.setFont(font)
self.force_offroad_checkBox.setChecked(False)
self.force_offroad_checkBox.setTristate(False)
self.force_offroad_checkBox.setObjectName("force_offroad_checkBox")
self.random_weather_checkBox.setFont(font)
self.random_weather_checkBox.setChecked(False)
self.random_weather_checkBox.setTristate(False)
self.random_weather_checkBox.setObjectName("random_weather_checkBox")
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setGeometry(QtCore.QRect(570, 330, 281, 23))
self.label_3.setGeometry(QtCore.QRect(570, 300, 281, 23))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(False)
self.label_3.setFont(font)
self.label_3.setObjectName("label_3")
self.apcs_spawn_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(990, 180, 251, 27))
self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(980, 180, 251, 27))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(False)
@@ -328,7 +328,7 @@ class Ui_MainWindow(object):
self.apcs_spawn_checkBox.setObjectName("apcs_spawn_checkBox")
self.generateButton = QtWidgets.QPushButton(self.centralwidget)
self.generateButton.setEnabled(True)
self.generateButton.setGeometry(QtCore.QRect(710, 600, 231, 51))
self.generateButton.setGeometry(QtCore.QRect(750, 600, 231, 51))
font = QtGui.QFont()
font.setPointSize(8)
font.setBold(True)
@@ -336,7 +336,7 @@ class Ui_MainWindow(object):
self.generateButton.setStyleSheet("")
self.generateButton.setObjectName("generateButton")
self.farp_always = QtWidgets.QRadioButton(self.centralwidget)
self.farp_always.setGeometry(QtCore.QRect(510, 480, 261, 24))
self.farp_always.setGeometry(QtCore.QRect(500, 431, 261, 24))
font = QtGui.QFont()
font.setPointSize(9)
self.farp_always.setFont(font)
@@ -345,14 +345,14 @@ class Ui_MainWindow(object):
self.farp_buttonGroup.setObjectName("farp_buttonGroup")
self.farp_buttonGroup.addButton(self.farp_always)
self.farp_never = QtWidgets.QRadioButton(self.centralwidget)
self.farp_never.setGeometry(QtCore.QRect(510, 540, 271, 24))
self.farp_never.setGeometry(QtCore.QRect(500, 491, 271, 24))
font = QtGui.QFont()
font.setPointSize(9)
self.farp_never.setFont(font)
self.farp_never.setObjectName("farp_never")
self.farp_buttonGroup.addButton(self.farp_never)
self.farp_gunits = QtWidgets.QRadioButton(self.centralwidget)
self.farp_gunits.setGeometry(QtCore.QRect(510, 509, 261, 24))
self.farp_gunits.setGeometry(QtCore.QRect(500, 460, 261, 24))
font = QtGui.QFont()
font.setPointSize(9)
self.farp_gunits.setFont(font)
@@ -397,7 +397,7 @@ class Ui_MainWindow(object):
self.rateButton1.setText("")
self.rateButton1.setObjectName("rateButton1")
self.hotstart_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.hotstart_checkBox.setGeometry(QtCore.QRect(960, 430, 271, 24))
self.hotstart_checkBox.setGeometry(QtCore.QRect(980, 520, 271, 24))
font = QtGui.QFont()
font.setPointSize(9)
self.hotstart_checkBox.setFont(font)
@@ -440,6 +440,21 @@ class Ui_MainWindow(object):
self.rateButton5.setStyleSheet("border-image:url(\'../assets/star_full.png\');")
self.rateButton5.setText("")
self.rateButton5.setObjectName("rateButton5")
self.time_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.time_comboBox.setGeometry(QtCore.QRect(980, 370, 161, 33))
font = QtGui.QFont()
font.setPointSize(10)
font.setBold(False)
self.time_comboBox.setFont(font)
self.time_comboBox.setObjectName("time_comboBox")
self.farp_spawn_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.farp_spawn_checkBox.setGeometry(QtCore.QRect(980, 550, 271, 24))
font = QtGui.QFont()
font.setPointSize(9)
self.farp_spawn_checkBox.setFont(font)
self.farp_spawn_checkBox.setChecked(False)
self.farp_spawn_checkBox.setTristate(False)
self.farp_spawn_checkBox.setObjectName("farp_spawn_checkBox")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1280, 29))
@@ -564,10 +579,10 @@ class Ui_MainWindow(object):
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "RotorOps Mission Generator"))
self.logistics_crates_checkBox.setStatusTip(_translate("MainWindow", "Enable CTLD logistics crates for building ground units and air defenses. Pickup logistics containers to create new logistics sites."))
self.logistics_crates_checkBox.setText(_translate("MainWindow", "Logistics"))
self.zone_sams_checkBox.setStatusTip(_translate("MainWindow", "Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed."))
self.zone_sams_checkBox.setText(_translate("MainWindow", "Inactive Zone SAMs"))
self.logistics_crates_checkBox.setStatusTip(_translate("MainWindow", "Enable a base or FARP near the start position that can spawn CTLD crates for building ground units and air defenses. Sling load the logistics containers to create new logistics sites."))
self.logistics_crates_checkBox.setText(_translate("MainWindow", "Logistics Base"))
self.zone_sams_checkBox.setStatusTip(_translate("MainWindow", "Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed. No effect if Blue on defense."))
self.zone_sams_checkBox.setText(_translate("MainWindow", "Protect Inactive Zones"))
self.red_forces_label.setText(_translate("MainWindow", "Red Forces:"))
self.scenario_comboBox.setStatusTip(_translate("MainWindow", "Tip: You can create your own templates that include mission options like kneeboards, briefings, weather, static units, triggers, scripts, etc."))
self.description_textBrowser.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
@@ -575,6 +590,7 @@ class Ui_MainWindow(object):
"p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Segoe UI\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:10pt;\">Provide close air support for our convoys as we take back Las Vegas from the enemy!</span></p></body></html>"))
self.defense_checkBox.setStatusTip(_translate("MainWindow", "Turn the tables and defend your zones against the enemy\'s attack."))
self.defense_checkBox.setText(_translate("MainWindow", "Blue on Defense"))
self.redqty_spinBox.setStatusTip(_translate("MainWindow", "Red vehicle groups per staging or conflict zone."))
self.redforces_comboBox.setStatusTip(_translate("MainWindow", "Tip: You can create your own custom ground forces groups to be automatically generated."))
@@ -602,20 +618,20 @@ class Ui_MainWindow(object):
self.tankers_checkBox.setText(_translate("MainWindow", "Friendly Tankers"))
self.voiceovers_checkBox.setStatusTip(_translate("MainWindow", "Voiceovers from the ground commander. Helps keep focus on the active zone."))
self.voiceovers_checkBox.setText(_translate("MainWindow", "Voiceovers"))
self.smoke_pickup_zone_checkBox.setStatusTip(_translate("MainWindow", "Infinite troop pickup zones will be marked with blue smoke."))
self.smoke_pickup_zone_checkBox.setStatusTip(_translate("MainWindow", "Troop pickup zones and FARPs will be marked with blue smoke."))
self.smoke_pickup_zone_checkBox.setText(_translate("MainWindow", "Smoke at Troop Pickup Zones"))
self.game_status_checkBox.setStatusTip(_translate("MainWindow", "Enable an onscreen zone status display. This helps keep focus on the active conflict zone."))
self.game_status_checkBox.setText(_translate("MainWindow", "Game Status Display"))
self.label.setStatusTip(_translate("MainWindow", "This value is multiplied by the number of spawn zones in the mission template."))
self.label.setText(_translate("MainWindow", "Infantry Spawns per zone"))
self.label.setStatusTip(_translate("MainWindow", "Total number of infantry groups to spawn per game."))
self.label.setText(_translate("MainWindow", "Infantry Spawns"))
self.inf_spawn_spinBox.setStatusTip(_translate("MainWindow", "This value is multiplied by the number of spawn zones in the mission template."))
self.troop_drop_spinBox.setStatusTip(_translate("MainWindow", "The number of troop drops per transport helicopter flight."))
self.force_offroad_checkBox.setStatusTip(_translate("MainWindow", "May help prevent long travel times or pathfinding issues. "))
self.force_offroad_checkBox.setText(_translate("MainWindow", "Force Offroad"))
self.random_weather_checkBox.setStatusTip(_translate("MainWindow", "Random weather preset will be applied."))
self.random_weather_checkBox.setText(_translate("MainWindow", "Random Weather"))
self.label_3.setStatusTip(_translate("MainWindow", "The number of troop drops per transport helicopter flight."))
self.label_3.setText(_translate("MainWindow", "Transport Drop Points"))
self.apcs_spawn_checkBox.setStatusTip(_translate("MainWindow", "Friendly/enemy APCs will drop infantry when reaching a new conflict zone. Disables infinite troop pickups from conflict zones (you must pick up existing troops)."))
self.apcs_spawn_checkBox.setText(_translate("MainWindow", "Dynamic Troops"))
self.apcs_spawn_checkBox.setStatusTip(_translate("MainWindow", "Friendly/enemy APCs will drop infantry when reaching a new conflict zone. "))
self.apcs_spawn_checkBox.setText(_translate("MainWindow", "APCs Spawn Infantry"))
self.generateButton.setStatusTip(_translate("MainWindow", "Click to generate mission."))
self.generateButton.setText(_translate("MainWindow", "GENERATE MISSION"))
self.farp_always.setStatusTip(_translate("MainWindow", "Always spawn a FARP in defeated conflict zones."))
@@ -627,12 +643,15 @@ class Ui_MainWindow(object):
self.nextScenario_pushButton.setText(_translate("MainWindow", ">"))
self.prevScenario_pushButton.setText(_translate("MainWindow", "<"))
self.rateButton1.setStatusTip(_translate("MainWindow", "Submit a review for this mission scenario."))
self.hotstart_checkBox.setStatusTip(_translate("MainWindow", "Player helicopters start with engines running on the ground. No effect if player slots says \'Locked to scenario\'"))
self.hotstart_checkBox.setStatusTip(_translate("MainWindow", "Player helicopters start with engines running on the ground. No effect for FARP spawns or if player slots says \'Locked to scenario\'"))
self.hotstart_checkBox.setText(_translate("MainWindow", "Player Hotstart"))
self.rateButton2.setStatusTip(_translate("MainWindow", "Submit a review for this mission scenario."))
self.rateButton3.setStatusTip(_translate("MainWindow", "Submit a review for this mission scenario."))
self.rateButton4.setStatusTip(_translate("MainWindow", "Submit a review for this mission scenario."))
self.rateButton5.setStatusTip(_translate("MainWindow", "Submit a review for this mission scenario."))
self.time_comboBox.setStatusTip(_translate("MainWindow", "Mission start time of day. \'Default\' is the start time as defined by the mission template designer."))
self.farp_spawn_checkBox.setStatusTip(_translate("MainWindow", "Add helicopter slots where zone FARPs will be built. Helicopters will be empty fuel, requiring the FARP to be established to refuel and rearm."))
self.farp_spawn_checkBox.setText(_translate("MainWindow", "Spawns at zone FARPs"))
self.menuMap.setTitle(_translate("MainWindow", "Map"))
self.menuFilter.setTitle(_translate("MainWindow", "Filter"))
self.menuPreferences.setTitle(_translate("MainWindow", "Preferences"))
@@ -658,8 +677,8 @@ class Ui_MainWindow(object):
self.action_downloadButton.setToolTip(_translate("MainWindow", "_downloadButton"))
self.action_rateButton1.setText(_translate("MainWindow", "_rateButton1"))
self.action_rateButton1.setToolTip(_translate("MainWindow", "_rateButton1"))
self.actionSingle_Player.setText(_translate("MainWindow", "Single-Player"))
self.actionCo_Op.setText(_translate("MainWindow", "Co-Op"))
self.actionSingle_Player.setText(_translate("MainWindow", "Single-Player Only"))
self.actionCo_Op.setText(_translate("MainWindow", "Co-Op Only"))
self.actionMapMenu.setText(_translate("MainWindow", "actionMapMenu"))
self.actionFilterMenu.setText(_translate("MainWindow", "FilterMenu"))
self.action_rateButton2.setText(_translate("MainWindow", "_rateButton2"))

View File

@@ -53,7 +53,7 @@
<widget class="QCheckBox" name="logistics_crates_checkBox">
<property name="geometry">
<rect>
<x>990</x>
<x>980</x>
<y>211</y>
<width>251</width>
<height>28</height>
@@ -66,10 +66,10 @@
</font>
</property>
<property name="statusTip">
<string>Enable CTLD logistics crates for building ground units and air defenses. Pickup logistics containers to create new logistics sites.</string>
<string>Enable a base or FARP near the start position that can spawn CTLD crates for building ground units and air defenses. Sling load the logistics containers to create new logistics sites.</string>
</property>
<property name="text">
<string>Logistics</string>
<string>Logistics Base</string>
</property>
<property name="checked">
<bool>true</bool>
@@ -78,7 +78,7 @@
<widget class="QCheckBox" name="zone_sams_checkBox">
<property name="geometry">
<rect>
<x>990</x>
<x>980</x>
<y>320</y>
<width>241</width>
<height>28</height>
@@ -91,10 +91,10 @@
</font>
</property>
<property name="statusTip">
<string>Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed.</string>
<string>Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed. No effect if Blue on defense.</string>
</property>
<property name="text">
<string>Inactive Zone SAMs</string>
<string>Protect Inactive Zones</string>
</property>
</widget>
<widget class="QLabel" name="red_forces_label">
@@ -191,17 +191,20 @@ p, li { white-space: pre-wrap; }
<property name="geometry">
<rect>
<x>470</x>
<y>120</y>
<y>130</y>
<width>156</width>
<height>28</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
<pointsize>11</pointsize>
<bold>false</bold>
</font>
</property>
<property name="statusTip">
<string>Turn the tables and defend your zones against the enemy's attack.</string>
</property>
<property name="text">
<string>Blue on Defense</string>
</property>
@@ -289,8 +292,8 @@ p, li { white-space: pre-wrap; }
<widget class="QComboBox" name="slot_template_comboBox">
<property name="geometry">
<rect>
<x>960</x>
<y>384</y>
<x>980</x>
<y>474</y>
<width>271</width>
<height>33</height>
</rect>
@@ -564,7 +567,7 @@ p, li { white-space: pre-wrap; }
<number>8</number>
</property>
<property name="value">
<number>2</number>
<number>1</number>
</property>
</widget>
<widget class="QLabel" name="scenario_label_7">
@@ -592,8 +595,8 @@ p, li { white-space: pre-wrap; }
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>840</x>
<y>390</y>
<x>860</x>
<y>480</y>
<width>111</width>
<height>24</height>
</rect>
@@ -611,8 +614,8 @@ p, li { white-space: pre-wrap; }
<widget class="QLabel" name="scenario_label_9">
<property name="geometry">
<rect>
<x>490</x>
<y>450</y>
<x>480</x>
<y>401</y>
<width>251</width>
<height>23</height>
</rect>
@@ -629,7 +632,7 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="awacs_checkBox">
<property name="geometry">
<rect>
<x>990</x>
<x>980</x>
<y>246</y>
<width>241</width>
<height>28</height>
@@ -654,7 +657,7 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="tankers_checkBox">
<property name="geometry">
<rect>
<x>990</x>
<x>980</x>
<y>282</y>
<width>241</width>
<height>28</height>
@@ -679,10 +682,10 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="voiceovers_checkBox">
<property name="geometry">
<rect>
<x>960</x>
<y>517</y>
<x>500</x>
<y>594</y>
<width>171</width>
<height>24</height>
<height>31</height>
</rect>
</property>
<property name="font">
@@ -703,10 +706,10 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="smoke_pickup_zone_checkBox">
<property name="geometry">
<rect>
<x>960</x>
<y>460</y>
<width>271</width>
<height>24</height>
<x>500</x>
<y>541</y>
<width>231</width>
<height>20</height>
</rect>
</property>
<property name="font">
@@ -715,7 +718,7 @@ p, li { white-space: pre-wrap; }
</font>
</property>
<property name="statusTip">
<string>Infinite troop pickup zones will be marked with blue smoke.</string>
<string>Troop pickup zones and FARPs will be marked with blue smoke.</string>
</property>
<property name="text">
<string>Smoke at Troop Pickup Zones</string>
@@ -727,10 +730,10 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="game_status_checkBox">
<property name="geometry">
<rect>
<x>960</x>
<y>490</y>
<width>271</width>
<height>24</height>
<x>500</x>
<y>570</y>
<width>221</width>
<height>21</height>
</rect>
</property>
<property name="font">
@@ -755,7 +758,7 @@ p, li { white-space: pre-wrap; }
<property name="geometry">
<rect>
<x>570</x>
<y>380</y>
<y>340</y>
<width>261</width>
<height>23</height>
</rect>
@@ -767,18 +770,18 @@ p, li { white-space: pre-wrap; }
</font>
</property>
<property name="statusTip">
<string>This value is multiplied by the number of spawn zones in the mission template.</string>
<string>Total number of infantry groups to spawn per game.</string>
</property>
<property name="text">
<string>Infantry Spawns per zone</string>
<string>Infantry Spawns</string>
</property>
</widget>
<widget class="QSpinBox" name="inf_spawn_spinBox">
<property name="geometry">
<rect>
<x>510</x>
<y>380</y>
<width>47</width>
<y>340</y>
<width>51</width>
<height>31</height>
</rect>
</property>
@@ -800,15 +803,15 @@ p, li { white-space: pre-wrap; }
<number>20</number>
</property>
<property name="value">
<number>2</number>
<number>0</number>
</property>
</widget>
<widget class="QSpinBox" name="troop_drop_spinBox">
<property name="geometry">
<rect>
<x>510</x>
<y>330</y>
<width>47</width>
<y>300</y>
<width>51</width>
<height>31</height>
</rect>
</property>
@@ -833,12 +836,12 @@ p, li { white-space: pre-wrap; }
<number>4</number>
</property>
</widget>
<widget class="QCheckBox" name="force_offroad_checkBox">
<widget class="QCheckBox" name="random_weather_checkBox">
<property name="geometry">
<rect>
<x>960</x>
<y>548</y>
<width>161</width>
<x>980</x>
<y>420</y>
<width>211</width>
<height>24</height>
</rect>
</property>
@@ -848,10 +851,10 @@ p, li { white-space: pre-wrap; }
</font>
</property>
<property name="statusTip">
<string>May help prevent long travel times or pathfinding issues. </string>
<string>Random weather preset will be applied.</string>
</property>
<property name="text">
<string>Force Offroad</string>
<string>Random Weather</string>
</property>
<property name="checked">
<bool>false</bool>
@@ -864,7 +867,7 @@ p, li { white-space: pre-wrap; }
<property name="geometry">
<rect>
<x>570</x>
<y>330</y>
<y>300</y>
<width>281</width>
<height>23</height>
</rect>
@@ -885,7 +888,7 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="apcs_spawn_checkBox">
<property name="geometry">
<rect>
<x>990</x>
<x>980</x>
<y>180</y>
<width>251</width>
<height>27</height>
@@ -898,10 +901,10 @@ p, li { white-space: pre-wrap; }
</font>
</property>
<property name="statusTip">
<string>Friendly/enemy APCs will drop infantry when reaching a new conflict zone. Disables infinite troop pickups from conflict zones (you must pick up existing troops).</string>
<string>Friendly/enemy APCs will drop infantry when reaching a new conflict zone. </string>
</property>
<property name="text">
<string>Dynamic Troops</string>
<string>APCs Spawn Infantry</string>
</property>
<property name="checked">
<bool>true</bool>
@@ -913,7 +916,7 @@ p, li { white-space: pre-wrap; }
</property>
<property name="geometry">
<rect>
<x>710</x>
<x>750</x>
<y>600</y>
<width>231</width>
<height>51</height>
@@ -938,8 +941,8 @@ p, li { white-space: pre-wrap; }
<widget class="QRadioButton" name="farp_always">
<property name="geometry">
<rect>
<x>510</x>
<y>480</y>
<x>500</x>
<y>431</y>
<width>261</width>
<height>24</height>
</rect>
@@ -962,8 +965,8 @@ p, li { white-space: pre-wrap; }
<widget class="QRadioButton" name="farp_never">
<property name="geometry">
<rect>
<x>510</x>
<y>540</y>
<x>500</x>
<y>491</y>
<width>271</width>
<height>24</height>
</rect>
@@ -986,8 +989,8 @@ p, li { white-space: pre-wrap; }
<widget class="QRadioButton" name="farp_gunits">
<property name="geometry">
<rect>
<x>510</x>
<y>509</y>
<x>500</x>
<y>460</y>
<width>261</width>
<height>24</height>
</rect>
@@ -1131,8 +1134,8 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="hotstart_checkBox">
<property name="geometry">
<rect>
<x>960</x>
<y>430</y>
<x>980</x>
<y>520</y>
<width>271</width>
<height>24</height>
</rect>
@@ -1143,7 +1146,7 @@ p, li { white-space: pre-wrap; }
</font>
</property>
<property name="statusTip">
<string>Player helicopters start with engines running on the ground. No effect if player slots says 'Locked to scenario'</string>
<string>Player helicopters start with engines running on the ground. No effect for FARP spawns or if player slots says 'Locked to scenario'</string>
</property>
<property name="text">
<string>Player Hotstart</string>
@@ -1263,6 +1266,52 @@ p, li { white-space: pre-wrap; }
<string/>
</property>
</widget>
<widget class="QComboBox" name="time_comboBox">
<property name="geometry">
<rect>
<x>980</x>
<y>370</y>
<width>161</width>
<height>33</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
<bold>false</bold>
</font>
</property>
<property name="statusTip">
<string>Mission start time of day. 'Default' is the start time as defined by the mission template designer.</string>
</property>
</widget>
<widget class="QCheckBox" name="farp_spawn_checkBox">
<property name="geometry">
<rect>
<x>980</x>
<y>550</y>
<width>271</width>
<height>24</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="statusTip">
<string>Add helicopter slots where zone FARPs will be built. Helicopters will be empty fuel, requiring the FARP to be established to refuel and rearm.</string>
</property>
<property name="text">
<string>Spawns at zone FARPs</string>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="tristate">
<bool>false</bool>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
@@ -1471,7 +1520,7 @@ p, li { white-space: pre-wrap; }
<bool>true</bool>
</property>
<property name="text">
<string>Single-Player</string>
<string>Single-Player Only</string>
</property>
</action>
<action name="actionCo_Op">
@@ -1482,7 +1531,7 @@ p, li { white-space: pre-wrap; }
<bool>true</bool>
</property>
<property name="text">
<string>Co-Op</string>
<string>Co-Op Only</string>
</property>
</action>
<action name="actionMapMenu">

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,6 @@ def triggerSetup(rops, options):
# Add the first trigger
trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Scripts")
trig.rules.append(dcs.condition.TimeAfter(1))
#trig.actions.append(dcs.action.DoScriptFile(rops.scripts["mist_4_4_90.lua"]))
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["mist_4_5_107_grimm.lua"]))
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["Splash_Damage_2_0.lua"]))
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["CTLD.lua"]))
@@ -29,11 +28,13 @@ def triggerSetup(rops, options):
"RotorOps.voice_overs = " + lb("voiceovers") + "\n\n" +
"RotorOps.zone_status_display = " + lb("game_display") + "\n\n" +
"RotorOps.inf_spawn_messages = true\n\n" +
"RotorOps.inf_spawns_per_zone = " + lb("inf_spawn_qty") + "\n\n" +
"RotorOps.inf_spawns_total = " + lb("inf_spawn_qty") + "\n\n" +
"RotorOps.apcs_spawn_infantry = " + lb("apc_spawns_inf") + " \n\n")
if not options["smoke_pickup_zones"]:
script = script + 'RotorOps.pickup_zone_smoke = "none"\n\n'
trig.actions.append(dcs.action.DoScript(dcs.action.String((script))))
if options["script"]:
trig.actions.append(dcs.action.DoScript(dcs.action.String((options["script"]))))
rops.m.triggerrules.triggers.append(trig)
# Add the second trigger
@@ -50,11 +51,12 @@ def triggerSetup(rops, options):
rops.m.triggerrules.triggers.append(trig)
# Add the third trigger
trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict Start")
trig.rules.append(dcs.condition.TimeAfter(10))
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.startConflict(100)")))
rops.m.triggerrules.triggers.append(trig)
# Add the start trigger
if options["start_trigger"] is not False:
trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict Start")
trig.rules.append(dcs.condition.TimeAfter(10))
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.startConflict(100)")))
rops.m.triggerrules.triggers.append(trig)
# Add generic zone-based triggers
for index, zone_name in enumerate(rops.conflict_zones):
@@ -81,6 +83,19 @@ def triggerSetup(rops, options):
dcs.action.String("Group.destroy(Group.getByName('Static " + zone_name + " Protection SAM'))")))
rops.m.triggerrules.triggers.append(z_sams_trig)
# Deactivate zone FARPs and player slots in defensive mode:
# this will also deactivate players already in the air.
# if options["defending"]:
# for index, zone_name in enumerate(rops.conflict_zones):
# z_farps_trig = dcs.triggers.TriggerOnce(comment="Deactivate " + zone_name + " FARP")
# z_farps_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
# z_farps_trig.actions.append(dcs.action.DeactivateGroup(rops.m.country(jtf_blue).find_group(zone_name + " FARP Static").id))
# for group in rops.all_zones[zone_name].player_helo_spawns:
# z_farps_trig.actions.append(
# dcs.action.DeactivateGroup(
# group.id))
# rops.m.triggerrules.triggers.append(z_farps_trig)
# Zone FARPS always
if options["zone_farps"] == "farp_always" and not options["defending"]:
for index, zone_name in enumerate(rops.conflict_zones):
@@ -92,9 +107,13 @@ def triggerSetup(rops, options):
z_farps_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_farps_trig.actions.append(
dcs.action.ActivateGroup(rops.m.country(jtf_blue).find_group(previous_zone + " FARP Static").id))
# z_farps_trig.actions.append(dcs.action.SoundToAll(str(rops.res_map['forward_base_established.ogg'])))
# Activate late-activated helicopters at FARPs. Doesn't work consistently
# for group in rops.all_zones[previous_zone].player_helo_spawns:
# z_farps_trig.actions.append(
# dcs.action.ActivateGroup(
# group.id))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"RotorOps.farpEstablished(" + str(index) + ")")))
"RotorOps.farpEstablished(" + str(index) + ", '" + previous_zone + "_FARP')")))
rops.m.triggerrules.triggers.append(z_farps_trig)
# Zone FARPS conditional on staged units remaining
@@ -111,9 +130,13 @@ def triggerSetup(rops, options):
"--The 100 flag indicates which zone is active. The 111 flag value is the percentage of staged units remaining")))
z_farps_trig.actions.append(
dcs.action.ActivateGroup(rops.m.country(jtf_blue).find_group(previous_zone + " FARP Static").id))
# z_farps_trig.actions.append(dcs.action.SoundToAll(str(rops.res_map['forward_base_established.ogg'])))
# Activate late-activated helicopters at FARPs. Doesn't work consistently
# for group in rops.all_zones[previous_zone].player_helo_spawns:
# z_farps_trig.actions.append(
# dcs.action.ActivateGroup(
# group.id))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"RotorOps.farpEstablished(" + str(index) + ")")))
"RotorOps.farpEstablished(" + str(index) + ", '" + previous_zone + "_FARP')")))
rops.m.triggerrules.triggers.append(z_farps_trig)
# Add attack helos triggers
@@ -156,17 +179,23 @@ def triggerSetup(rops, options):
rops.m.triggerrules.triggers.append(z_weak_trig)
# Add game won/lost triggers
trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict WON")
trig.rules.append(dcs.condition.FlagEquals(game_flag, 99))
trig.actions.append(
dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is WON")))
trig.actions.append(
dcs.action.DoScript(dcs.action.String("RotorOps.gameMsg(RotorOps.gameMsgs.success)")))
rops.m.triggerrules.triggers.append(trig)
trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict LOST")
trig.rules.append(dcs.condition.FlagEquals(game_flag, 98))
trig.actions.append(
dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is LOST")))
trig.actions.append(
dcs.action.DoScript(dcs.action.String("RotorOps.gameMsg(RotorOps.gameMsgs.failure)")))
rops.m.triggerrules.triggers.append(trig)
# Add game won triggers
trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict WON")
trig.rules.append(dcs.condition.FlagEquals(game_flag, 99))
trig.actions.append(
dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is WON")))
if options["end_trigger"] is not False:
trig.actions.append(
dcs.action.DoScript(dcs.action.String("RotorOps.gameMsg(RotorOps.gameMsgs.success)")))
rops.m.triggerrules.triggers.append(trig)
# Add game lost triggers
trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict LOST")
trig.rules.append(dcs.condition.FlagEquals(game_flag, 98))
trig.actions.append(
dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is LOST")))
if options["end_trigger"] is not False:
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.gameMsg(RotorOps.gameMsgs.failure)")))
rops.m.triggerrules.triggers.append(trig)

View File

@@ -1,12 +1,15 @@
import math
import dcs
from MissionGenerator import logger
import os
class ImportObjects:
def __init__(self, mizfile):
self.pad_unit = True #todo: use this to hold a unit for helicopter placement on ships ie flight_group_from_unit
self.pad_unit = True # todo: use this to hold a unit for helicopter placement on ships ie flight_group_from_unit
if not mizfile or not os.path.exists(mizfile):
raise Exception("Cannot find required file: " + str(mizfile))
logger.info("Importing objects from " + mizfile)
self.source_mission = dcs.mission.Mission()
self.source_mission.load_file(mizfile)
@@ -32,7 +35,6 @@ class ImportObjects:
self.copyVehicles(mission, dest_country_name, dest_name, dest_point, dest_heading), \
self.copyHelicopters(mission, dest_country_name, dest_name, dest_point, dest_heading)
def anchorByGroupName(self, group_name):
group = self.source_mission.find_group(group_name)
if group:
@@ -49,24 +51,26 @@ class ImportObjects:
coalition = self.source_mission.coalition.get(side)
for country_name in coalition.countries:
group_types = [coalition.countries[country_name].static_group, coalition.countries[country_name].vehicle_group, coalition.countries[country_name].helicopter_group, coalition.countries[country_name].plane_group,
group_types = [coalition.countries[country_name].static_group,
coalition.countries[country_name].vehicle_group,
coalition.countries[country_name].helicopter_group,
coalition.countries[country_name].plane_group,
coalition.countries[country_name].ship_group]
for index, group_type in enumerate(group_types):
for group in group_type:
if index == 0: # Statics
if index == 0: # Statics
self.statics.append(group)
elif index == 1: # Vehicles
self.vehicles.append(group)
elif index == 2: # Helicopters
elif index == 2: # Helicopters
self.helicopters.append(group)
elif index == 3:
logger.warn(group.name + ": Planes not available for import")
elif index == 4:
logger.warn(group.name + ": Ships not available for import")
def copyStatics(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
logger.info("Copying " + str(len(self.statics)) + " static objects as " + dest_name)
new_groups = []
@@ -74,13 +78,11 @@ class ImportObjects:
if not dest_point:
dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
#Statics
# Statics
statics_copy = self.statics.copy()
for group in statics_copy:
self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
class temp(dcs.unittype.StaticType):
id = group.units[0].type
name = group.units[0].name
@@ -89,7 +91,6 @@ class ImportObjects:
can_cargo = group.units[0].can_cargo
mass = group.units[0].mass
ng = mission.static_group(mission.country(dest_country_name),
dest_name + " " + group.name,
temp,
@@ -104,9 +105,6 @@ class ImportObjects:
return new_groups
def copyVehicles(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
logger.info("Copying " + str(len(self.vehicles)) + " vehicle groups as " + dest_name)
new_groups = []
@@ -122,30 +120,30 @@ class ImportObjects:
for i, unit in enumerate(group.units):
if i == 0:
ng = mission.vehicle_group(mission.country(dest_country_name),
dest_name + " " + group.name,
dcs.vehicles.vehicle_map[group.units[0].type],
group.units[0].position,
group.units[0].heading)
dest_name + " " + group.name,
dcs.vehicles.vehicle_map[group.units[0].type],
group.units[0].position,
group.units[0].heading)
new_groups.append(ng) # will this hold units we add later?
# ng.units[0].livery_id = group.units[0].livery_id
new_groups.append(ng)
else:
u = mission.vehicle(dest_name + " " + group.units[i].name, dcs.vehicles.vehicle_map[group.units[i].type])
u.position = group.units[i].position
u.heading = group.units[i].heading
ng.add_unit(u)
u = mission.vehicle(dest_name + " " + group.units[i].name,
dcs.vehicles.vehicle_map[group.units[i].type])
u.position = group.units[i].position
u.heading = group.units[i].heading
# u.livery_id = group.units[i].livery_id
ng.add_unit(u)
return new_groups
def copyHelicopters(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
def copyHelicopters(self, mission, dest_country_name, dest_name, dest_point, dest_heading=0,
start_type=dcs.mission.StartType.Cold):
logger.info("Copying " + str(len(self.helicopters)) + " helicopters as " + dest_name)
new_groups = []
if not dest_point:
dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
helicopters_copy = self.helicopters.copy()
for group in helicopters_copy:
@@ -158,39 +156,46 @@ class ImportObjects:
# trying to move the units into position after adding the flight group moves the 2D graphic of the helicopter, but the unit marker remains stacked on top
# of the unit marker in ME
# farp = mission.country(country_name).find_group(self.pad_unit.name)
#
# farp = mission.farp(mission.country(dest_country_name), dest_name + " " + group.name + " Pad", group.units[0].position, hidden=True, dead=False,
# farp_type=dcs.unit.InvisibleFARP)
#
#
# ng = mission.flight_group_from_unit(mission.country(dest_country_name),
# dest_name + " " + group.name,
# dcs.helicopters.helicopter_map[group.units[0].type],
# farp,
# group_size=1, start_type=start_type)
ng = mission.flight_group(mission.country(dest_country_name),
dest_name + " " + group.name,
dcs.helicopters.helicopter_map[group.units[0].type],
airport=None,
position=group.units[0].position,
group_size=1, start_type=start_type)
farp = mission.farp(mission.country(dest_country_name), dest_name + " " + group.name + " Pad", group.units[0].position, hidden=True, dead=False,
farp_type=dcs.unit.InvisibleFARP)
ng = mission.flight_group_from_unit(mission.country(dest_country_name),
dest_name + " " + group.name,
dcs.helicopters.helicopter_map[group.units[0].type],
farp,
group_size=1)
ng.points[0].action = dcs.point.PointAction.FromGroundArea
ng.points[0].type = "TakeOffGround"
if start_type == dcs.mission.StartType.Warm:
ng.points[0].action = dcs.point.PointAction.FromGroundAreaHot
ng.points[0].type = "TakeOffGroundHot"
else:
ng.points[0].action = dcs.point.PointAction.FromGroundArea
ng.points[0].type = "TakeOffGround"
ng.units[0].heading = group.units[0].heading
ng.units[0].skill = group.units[0].skill
ng.units[0].livery_id = group.units[0].livery_id
ng.units[0].pylons = group.units[0].pylons
ng.units[0].fuel = group.units[0].fuel
ng.units[0].gun = group.units[0].gun
ng.units[0].hardpoint_racks = group.units[0].hardpoint_racks
new_groups.append(ng)
else:
logger.warn("No pad unit (ie FARP, carrier) found, so can't add helicopters.")
return new_groups
def copyVehiclesAsGroup(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
def copyVehiclesAsGroup(self, mission, dest_country_name, dest_name, dest_point, dest_heading=0):
logger.info("Copying " + str(len(self.vehicles)) + " vehicle groups as single group name: " + dest_name)
new_group = None
if not dest_point:
dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
unit_count = 0
vehicles_copy = self.vehicles.copy()
for group in vehicles_copy:
@@ -198,29 +203,32 @@ class ImportObjects:
for i, unit in enumerate(group.units):
if unit_count == 0:
print("Group:" + group.name)
# print("Group:" + group.name)
new_group = mission.vehicle_group(mission.country(dest_country_name),
dest_name,
dcs.vehicles.vehicle_map[group.units[0].type],
group.units[0].position,
group.units[0].heading)
unit_count = unit_count + 1
# new_group.units[0].livery_id = group.units[0].livery_id
else:
print("Unit:" + group.units[i].name)
u = mission.vehicle(dest_name + " " + group.units[i].name, dcs.vehicles.vehicle_map[group.units[i].type])
# print("Unit:" + group.units[i].name)
u = mission.vehicle(dest_name + " " + group.units[i].name,
dcs.vehicles.vehicle_map[group.units[i].type])
u.position = group.units[i].position
u.heading = group.units[i].heading
# u.livery_id = group.units[i].livery_id
new_group.add_unit(u)
unit_count = unit_count + 1
print("Made a group with units: " + str(unit_count))
print("group actually has units: " + str(len(new_group.units)))
# print("group actually has units: " + str(len(new_group.units)))
return new_group
@staticmethod
def groupToPoint(group, src_point, dest_point, src_heading=0, dest_heading=0):
for unit in group.units:
@@ -230,4 +238,4 @@ class ImportObjects:
unit_distance = src_point.distance_to_point(unit.position)
unit.position = dest_point.point_from_heading(new_heading_to_unit, unit_distance)
unit.heading = unit.heading + dest_heading
return group
return group

File diff suppressed because it is too large Load Diff

Binary file not shown.

11
Generator/tests.py Normal file
View File

@@ -0,0 +1,11 @@
import dcs
import dcs.cloud_presets
testm = dcs.mission.Mission()
# testCloudPresets
for i in range(0, len(dcs.cloud_presets.CLOUD_PRESETS)):
preset_name = list(dcs.cloud_presets.CLOUD_PRESETS)[i]
cloud_preset = dcs.weather.CloudPreset.by_name(preset_name)
testm.weather.clouds_preset = cloud_preset
print("Cloud preset = " + cloud_preset.ui_name)