Merge pull request #26 from spencershepard/develop

Develop
This commit is contained in:
spencershepard 2022-03-20 11:16:49 -07:00 committed by GitHub
commit 8dfe96069e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
49 changed files with 11841 additions and 1284 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,17 @@
You can put .miz files in this folder to be copied into the generated mission at marker points. This feature is currently very 'alpha' and may produce errors. Currently, this doesn't work for ship groups or plane groups.
1) Make an empty mission on Cauacasus.
2) Place units/objects on the map.
3) Make one unit group name: 'ANCHOR' This will represent the point of insertion into the target mission.
4) In a Scenario template, place a static object (flag, etc) and call it "IMPORT-[filename of .miz created in first step]" Country should be CJTF Red, CJTF Blue, or UN Peacekeepers.
5) Change the unit name of the object created in the previous step. This unit name might be used for spawn names, so you should call the unit name something like "North Base" so players know where they'll be spawning when choosing a slot.
Tips:
-You can change the heading of the imported group by changing the heading of the insertion object.
-For multiple imports of the same template, the import object group name should end with '-01' or '-whatever'.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -2,17 +2,26 @@ import math
import sys
import os
import dcs
from PyQt5.QtCore import QCoreApplication
from PyQt5.uic.properties import QtCore
import RotorOpsMission as ROps
import RotorOpsUtils
import RotorOpsUnits
import logging
import json
import yaml
import requests
from PyQt5.QtWidgets import (
QApplication, QDialog, QMainWindow, QMessageBox
)
from PyQt5 import QtGui
from PyQt5 import Qt, QtCore
from MissionGeneratorUI import Ui_MainWindow
import qtmodern.styles
import qtmodern.windows
#Setup logfile and exception handler
logger = logging.getLogger(__name__)
@ -20,6 +29,30 @@ logging.basicConfig(filename='generator.log', encoding='utf-8', level=logging.DE
handler = logging.StreamHandler(stream=sys.stdout)
logger.addHandler(handler)
user_files_url = 'https://dcs-helicopters.com/user-files/'
class directories:
home_dir = scenarios = forces = scripts = sound = output = assets = imports = None
@classmethod
def find(cls):
current_dir = os.getcwd()
if os.path.basename(os.getcwd()) == "Generator":
os.chdir("..")
cls.home_dir = os.getcwd()
cls.scenarios = cls.home_dir + "\Generator\Scenarios"
cls.forces = cls.home_dir + "\Generator\Forces"
cls.scripts = cls.home_dir
cls.sound = cls.home_dir + "\sound\embedded"
cls.output = cls.home_dir + "\Generator\Output"
cls.assets = cls.home_dir + "\Generator/assets"
cls.imports = cls.home_dir + "\Generator\Imports"
os.chdir(current_dir)
directories.find()
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)
@ -28,15 +61,15 @@ def handle_exception(exc_type, exc_value, exc_traceback):
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
msg = QMessageBox()
msg.setWindowTitle("Uncaught exception")
msg.setText("Oops, there was a problem. Please check the log file or post it in the RotorOps discord where some helpful people will have a look.")
msg.setText("Oops, there was a problem. Please check the log file for more details or post it in the RotorOps discord where some helpful people will have a look. \n\n" + str(exc_value))
x = msg.exec_()
sys.excepthook = handle_exception
maj_version = 0
minor_version = 4
build = 1
maj_version = 1
minor_version = 1
version_string = str(maj_version) + "." + str(minor_version)
scenarios = []
red_forces_files = []
@ -54,8 +87,8 @@ class Window(QMainWindow, Ui_MainWindow):
if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
logger.info('running in a PyInstaller bundle')
home_dir = os.getcwd()
os.chdir(home_dir + "/Generator")
qtmodern.styles._STYLESHEET = directories.assets + '/style.qss'
qtmodern.windows._FL_STYLESHEET = directories.assets + '/frameless.qss'
else:
logger.info('running in a normal Python process')
@ -68,9 +101,9 @@ class Window(QMainWindow, Ui_MainWindow):
self.populateForces("blue", self.blueforces_comboBox, blue_forces_files)
self.populateSlotSelection()
self.blue_forces_label.setText(attackers_text)
self.red_forces_label.setText(defenders_text)
self.background_label.setPixmap(QtGui.QPixmap(self.m.assets_dir + "/background.PNG"))
# self.blue_forces_label.setText(attackers_text)
# self.red_forces_label.setText(defenders_text)
self.background_label.setPixmap(QtGui.QPixmap(directories.assets + "/rotorops-dkgray.png"))
self.statusbar.setStyleSheet(
"QStatusBar{padding-left:5px;color:black;font-weight:bold;}")
@ -81,9 +114,11 @@ class Window(QMainWindow, Ui_MainWindow):
self.action_generateMission.triggered.connect(self.generateMissionAction)
self.action_scenarioSelected.triggered.connect(self.scenarioChanged)
self.action_defensiveModeChanged.triggered.connect(self.defensiveModeChanged)
self.action_nextScenario.triggered.connect(self.nextScenario)
self.action_prevScenario.triggered.connect(self.prevScenario)
def populateScenarios(self):
os.chdir(self.m.scenarios_dir)
os.chdir(directories.scenarios)
path = os.getcwd()
dir_list = os.listdir(path)
logger.info("Looking for mission files in " + path)
@ -94,8 +129,8 @@ class Window(QMainWindow, Ui_MainWindow):
self.scenario_comboBox.addItem(filename.removesuffix('.miz'))
def populateForces(self, side, combobox, files_list):
os.chdir(self.m.home_dir)
os.chdir(self.m.forces_dir + "/" + side)
os.chdir(directories.home_dir)
os.chdir(directories.forces + "/" + side)
path = os.getcwd()
dir_list = os.listdir(path)
logger.info("Looking for " + side + " Forces files in '" + path)
@ -109,18 +144,63 @@ class Window(QMainWindow, Ui_MainWindow):
self.slot_template_comboBox.addItem("Multiple Slots")
for type in RotorOpsUnits.client_helos:
self.slot_template_comboBox.addItem(type.id)
self.slot_template_comboBox.addItem("None")
def defensiveModeChanged(self):
if self.defense_checkBox.isChecked():
self.red_forces_label.setText(attackers_text)
self.blue_forces_label.setText(defenders_text)
else:
self.red_forces_label.setText(defenders_text)
self.blue_forces_label.setText(attackers_text)
# if self.defense_checkBox.isChecked():
# self.red_forces_label.setText(attackers_text)
# self.blue_forces_label.setText(defenders_text)
# else:
# self.red_forces_label.setText(defenders_text)
# self.blue_forces_label.setText(attackers_text)
self.applyScenarioConfig()
def loadScenarioConfig(self, filename):
try:
j = open(filename)
config = json.load(j)
j.close()
return config
except:
return None
def lockedSlot(self):
return self.slot_template_comboBox.findText("Locked to Scenario")
def clearScenarioConfig(self):
# reset default states
self.defense_checkBox.setEnabled(True)
if self.lockedSlot():
self.slot_template_comboBox.removeItem(self.lockedSlot())
self.slot_template_comboBox.setEnabled(True)
self.slot_template_comboBox.setCurrentIndex(0)
def applyScenarioConfig(self):
if not self.config:
return
if self.config['defense']['allowed'] == False:
self.defense_checkBox.setChecked(False)
self.defense_checkBox.setEnabled(False)
elif self.config['offense']['allowed'] == False:
self.defense_checkBox.setChecked(True)
self.defense_checkBox.setEnabled(False)
if self.config['defense']['player_spawn'] == "fixed":
self.slot_template_comboBox.addItem("Locked to Scenario")
self.slot_template_comboBox.setCurrentIndex(self.lockedSlot())
self.slot_template_comboBox.setEnabled(False)
def scenarioChanged(self):
os.chdir(self.m.scenarios_dir)
os.chdir(directories.scenarios)
filename = scenarios[self.scenario_comboBox.currentIndex()]
source_mission = dcs.mission.Mission()
source_mission.load_file(filename)
@ -136,6 +216,14 @@ class Window(QMainWindow, Ui_MainWindow):
friendly_airports = True
enemy_airports = True
self.clearScenarioConfig()
config_filename = filename.removesuffix(".miz") + ".json"
self.config = self.loadScenarioConfig(config_filename)
if self.config:
self.applyScenarioConfig()
self.m.setConfig(self.config)
for zone in zones:
if zone.name == "STAGING":
staging_zones += 1
@ -174,14 +262,23 @@ class Window(QMainWindow, Ui_MainWindow):
+ "\n== BRIEFING ==\n\n"
+ source_mission.description_text()
)
#self.description_textBrowser.setText("File error occured.")
path = directories.scenarios + "/" + filename.removesuffix(".miz") + ".jpg"
if os.path.isfile(path):
self.missionImage.setPixmap(QtGui.QPixmap(path))
else:
self.missionImage.setPixmap(QtGui.QPixmap(directories.assets + "/briefing1.png"))
def generateMissionAction(self):
red_forces_filename = red_forces_files[self.redforces_comboBox.currentIndex()]
blue_forces_filename = blue_forces_files[self.blueforces_comboBox.currentIndex()]
scenario_filename = scenarios[self.scenario_comboBox.currentIndex()]
source = "offline"
data = {
"source": source,
"scenario_filename": scenario_filename,
"red_forces_filename": red_forces_filename,
"blue_forces_filename": blue_forces_filename,
@ -206,7 +303,7 @@ class Window(QMainWindow, Ui_MainWindow):
"transport_drop_qty": self.troop_drop_spinBox.value(),
"smoke_pickup_zones": self.smoke_pickup_zone_checkBox.isChecked(),
}
os.chdir(self.m.home_dir + '/Generator')
os.chdir(directories.home_dir + '/Generator')
n = ROps.RotorOpsMission()
result = n.generateMission(data)
logger.info("Generating mission with options:")
@ -222,7 +319,7 @@ class Window(QMainWindow, Ui_MainWindow):
msg = QMessageBox()
msg.setWindowTitle("Mission Generated")
msg.setText("Awesome, your mission is ready! It's located in this directory: \n" +
self.m.output_dir + "\n" +
directories.output + "\n" +
"\n" +
"Next, you should use the DCS Mission Editor to fine tune unit placements. Don't be afraid to edit the missions that this generator produces. \n" +
"\n" +
@ -242,13 +339,90 @@ class Window(QMainWindow, Ui_MainWindow):
msg.setText(result["failure_msg"])
x = msg.exec_()
def prevScenario(self):
self.scenario_comboBox.setCurrentIndex((self.scenario_comboBox.currentIndex() - 1))
def nextScenario(self):
self.scenario_comboBox.setCurrentIndex((self.scenario_comboBox.currentIndex() + 1))
def checkVersion(self):
try:
url = user_files_url + 'versions.yaml'
r = requests.get(url, allow_redirects=False)
v = yaml.safe_load(r.content)
print(v["build"])
avail_build = v["build"]
if avail_build > build:
msg = QMessageBox()
msg.setWindowTitle("Update Available")
msg.setText(v["description"])
x = msg.exec_()
except:
logger.error("Online version check failed.")
def loadOnlineContent(self):
url = user_files_url + 'directory.yaml'
r = requests.get(url, allow_redirects=False)
user_files = yaml.safe_load(r.content)
count = 0
# Download scenarios files
os.chdir(directories.scenarios)
if user_files["scenarios"]["files"]:
for filename in user_files["scenarios"]["files"]:
url = user_files_url + user_files["scenarios"]["dir"] + '/' + filename
r = requests.get(url, allow_redirects=False)
open(filename, 'wb').write(r.content)
count = count + 1
# Download blue forces files
os.chdir(directories.forces + '/blue')
if user_files["forces_blue"]["files"]:
for filename in user_files["forces_blue"]["files"]:
url = user_files_url + user_files["forces_blue"]["dir"] + '/' + filename
r = requests.get(url, allow_redirects=False)
open(filename, 'wb').write(r.content)
count = count + 1
# Download red forces files
os.chdir(directories.forces + '/red')
if user_files["forces_red"]["files"]:
for filename in user_files["forces_red"]["files"]:
url = user_files_url + user_files["forces_red"]["dir"] + '/' + filename
r = requests.get(url, allow_redirects=False)
open(filename, 'wb').write(r.content)
count = count + 1
# Download imports files
os.chdir(directories.imports)
if user_files["imports"]["files"]:
for filename in user_files["imports"]["files"]:
url = user_files_url + user_files["imports"]["dir"] + '/' + filename
r = requests.get(url, allow_redirects=False)
open(filename, 'wb').write(r.content)
count = count + 1
msg = QMessageBox()
msg.setWindowTitle("Downloaded Files")
msg.setText("We've downloaded " + str(count) + " new files!")
x = msg.exec_()
if __name__ == "__main__":
# os.environ["QT_AUTO_SCREEN_SCALE_FACTOR"] = "1"
app = QApplication(sys.argv)
# QCoreApplication.setAttribute(QtCore.Qt.AA_DisableHighDpiScaling)
win = Window()
win.show()
# win.show()
# win.loadOnlineContent()
win.checkVersion()
qtmodern.styles.dark(app)
mw = qtmodern.windows.ModernWindow(win)
mw.show()
sys.exit(app.exec())

View File

@ -39,3 +39,4 @@ exe = EXE(pyz,
target_arch=None,
codesign_identity=None,
entitlements_file=None )

View File

@ -14,7 +14,14 @@ from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1209, 900)
MainWindow.resize(1280, 720)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(MainWindow.sizePolicy().hasHeightForWidth())
MainWindow.setSizePolicy(sizePolicy)
MainWindow.setMinimumSize(QtCore.QSize(1280, 720))
MainWindow.setMaximumSize(QtCore.QSize(1280, 720))
font = QtGui.QFont()
font.setPointSize(10)
MainWindow.setFont(font)
@ -23,353 +30,479 @@ class Ui_MainWindow(object):
MainWindow.setWindowIcon(icon)
MainWindow.setWindowOpacity(4.0)
MainWindow.setAutoFillBackground(False)
MainWindow.setStyleSheet("background-color: white;")
MainWindow.setStyleSheet("/*-----QScrollBar-----*/\n"
"QScrollBar:horizontal \n"
"{\n"
" background-color: transparent;\n"
" height: 8px;\n"
" margin: 0px;\n"
" padding: 0px;\n"
"\n"
"}\n"
"\n"
"\n"
"QScrollBar::handle:horizontal \n"
"{\n"
" border: none;\n"
" min-width: 100px;\n"
" background-color: #9b9b9b;\n"
"\n"
"}\n"
"\n"
"\n"
"QScrollBar::add-line:horizontal, \n"
"QScrollBar::sub-line:horizontal,\n"
"QScrollBar::add-page:horizontal, \n"
"QScrollBar::sub-page:horizontal \n"
"{\n"
" width: 0px;\n"
" background-color: transparent;\n"
"\n"
"}\n"
"\n"
"\n"
"QScrollBar:vertical \n"
"{\n"
" background-color: transparent;\n"
" width: 8px;\n"
" margin: 0;\n"
"\n"
"}\n"
"\n"
"\n"
"QScrollBar::handle:vertical \n"
"{\n"
" border: none;\n"
" min-height: 100px;\n"
" background-color: #9b9b9b;\n"
"\n"
"}\n"
"\n"
"\n"
"QScrollBar::add-line:vertical, \n"
"QScrollBar::sub-line:vertical,\n"
"QScrollBar::add-page:vertical, \n"
"QScrollBar::sub-page:vertical \n"
"{\n"
" height: 0px;\n"
" background-color: transparent;\n"
"\n"
"}")
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))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
self.logistics_crates_checkBox.setFont(font)
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))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
self.zone_sams_checkBox.setFont(font)
self.zone_sams_checkBox.setObjectName("zone_sams_checkBox")
self.red_forces_label = QtWidgets.QLabel(self.centralwidget)
self.red_forces_label.setGeometry(QtCore.QRect(470, 80, 171, 27))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
self.red_forces_label.setFont(font)
self.red_forces_label.setObjectName("red_forces_label")
self.scenario_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.scenario_comboBox.setGeometry(QtCore.QRect(270, 40, 361, 31))
self.scenario_comboBox.setGeometry(QtCore.QRect(30, 20, 371, 29))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(8)
font.setBold(True)
self.scenario_comboBox.setFont(font)
self.scenario_comboBox.setToolTip("")
self.scenario_comboBox.setToolTipDuration(-1)
self.scenario_comboBox.setWhatsThis("")
self.scenario_comboBox.setSizeAdjustPolicy(QtWidgets.QComboBox.AdjustToContentsOnFirstShow)
self.scenario_comboBox.setFrame(True)
self.scenario_comboBox.setObjectName("scenario_comboBox")
self.scenario_label = QtWidgets.QLabel(self.centralwidget)
self.scenario_label.setGeometry(QtCore.QRect(60, 30, 181, 41))
font = QtGui.QFont()
font.setPointSize(12)
self.scenario_label.setFont(font)
self.scenario_label.setObjectName("scenario_label")
self.generateButton = QtWidgets.QPushButton(self.centralwidget)
self.generateButton.setGeometry(QtCore.QRect(1020, 790, 141, 41))
self.generateButton.setStyleSheet("background-color: white;\n"
"border-style: outset;\n"
"border-width: 2px;\n"
"border-radius: 15px;\n"
"border-color: black;\n"
"padding: 4px;")
self.generateButton.setObjectName("generateButton")
self.description_textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
self.description_textBrowser.setGeometry(QtCore.QRect(670, 30, 501, 131))
self.description_textBrowser.setGeometry(QtCore.QRect(40, 410, 361, 251))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.description_textBrowser.setFont(font)
self.description_textBrowser.setStyleSheet("border-radius: 5px; color: gray")
self.description_textBrowser.setStyleSheet("padding: 5px;")
self.description_textBrowser.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.description_textBrowser.setFrameShadow(QtWidgets.QFrame.Plain)
self.description_textBrowser.setLineWidth(1)
self.description_textBrowser.setObjectName("description_textBrowser")
self.blueforces_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.blueforces_comboBox.setGeometry(QtCore.QRect(790, 230, 291, 31))
self.blueforces_comboBox.setObjectName("blueforces_comboBox")
self.blue_forces_label = QtWidgets.QLabel(self.centralwidget)
self.blue_forces_label.setGeometry(QtCore.QRect(690, 180, 241, 31))
self.defense_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.defense_checkBox.setEnabled(True)
self.defense_checkBox.setGeometry(QtCore.QRect(470, 120, 156, 28))
font = QtGui.QFont()
font.setPointSize(12)
self.blue_forces_label.setFont(font)
self.blue_forces_label.setObjectName("blue_forces_label")
self.red_forces_label = QtWidgets.QLabel(self.centralwidget)
self.red_forces_label.setGeometry(QtCore.QRect(60, 180, 261, 31))
font = QtGui.QFont()
font.setPointSize(12)
self.red_forces_label.setFont(font)
self.red_forces_label.setObjectName("red_forces_label")
self.redforces_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.redforces_comboBox.setGeometry(QtCore.QRect(170, 230, 291, 31))
self.redforces_comboBox.setObjectName("redforces_comboBox")
self.background_label = QtWidgets.QLabel(self.centralwidget)
self.background_label.setGeometry(QtCore.QRect(-40, 490, 801, 371))
self.background_label.setAutoFillBackground(False)
self.background_label.setStyleSheet("")
self.background_label.setText("")
self.background_label.setPixmap(QtGui.QPixmap("assets/background.PNG"))
self.background_label.setObjectName("background_label")
self.scenario_hint_label = QtWidgets.QLabel(self.centralwidget)
self.scenario_hint_label.setGeometry(QtCore.QRect(250, 80, 381, 16))
self.scenario_hint_label.setAlignment(QtCore.Qt.AlignCenter)
self.scenario_hint_label.setObjectName("scenario_hint_label")
self.forces_hint_label = QtWidgets.QLabel(self.centralwidget)
self.forces_hint_label.setGeometry(QtCore.QRect(130, 270, 381, 16))
self.forces_hint_label.setAlignment(QtCore.Qt.AlignCenter)
self.forces_hint_label.setObjectName("forces_hint_label")
self.blueqty_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.blueqty_spinBox.setGeometry(QtCore.QRect(690, 230, 71, 31))
font = QtGui.QFont()
font.setPointSize(12)
self.blueqty_spinBox.setFont(font)
self.blueqty_spinBox.setMinimum(0)
self.blueqty_spinBox.setMaximum(8)
self.blueqty_spinBox.setProperty("value", 3)
self.blueqty_spinBox.setObjectName("blueqty_spinBox")
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
self.defense_checkBox.setFont(font)
self.defense_checkBox.setCheckable(True)
self.defense_checkBox.setObjectName("defense_checkBox")
self.redqty_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.redqty_spinBox.setGeometry(QtCore.QRect(70, 230, 71, 31))
self.redqty_spinBox.setGeometry(QtCore.QRect(1070, 80, 51, 31))
font = QtGui.QFont()
font.setPointSize(12)
self.redqty_spinBox.setFont(font)
self.redqty_spinBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.PlusMinus)
self.redqty_spinBox.setMinimum(0)
self.redqty_spinBox.setMaximum(8)
self.redqty_spinBox.setProperty("value", 2)
self.redqty_spinBox.setObjectName("redqty_spinBox")
self.scenario_label_4 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_4.setGeometry(QtCore.QRect(670, 260, 101, 31))
font = QtGui.QFont()
font.setPointSize(8)
self.scenario_label_4.setFont(font)
self.scenario_label_4.setAlignment(QtCore.Qt.AlignCenter)
self.scenario_label_4.setObjectName("scenario_label_4")
self.game_status_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.game_status_checkBox.setGeometry(QtCore.QRect(810, 760, 191, 16))
self.redforces_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.redforces_comboBox.setGeometry(QtCore.QRect(660, 80, 391, 33))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.redforces_comboBox.sizePolicy().hasHeightForWidth())
self.redforces_comboBox.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.game_status_checkBox.setFont(font)
self.game_status_checkBox.setChecked(True)
self.game_status_checkBox.setTristate(False)
self.game_status_checkBox.setObjectName("game_status_checkBox")
self.voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.voiceovers_checkBox.setGeometry(QtCore.QRect(810, 790, 191, 16))
font = QtGui.QFont()
font.setPointSize(9)
self.voiceovers_checkBox.setFont(font)
self.voiceovers_checkBox.setChecked(True)
self.voiceovers_checkBox.setObjectName("voiceovers_checkBox")
self.logistics_crates_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.logistics_crates_checkBox.setGeometry(QtCore.QRect(920, 320, 251, 31))
font = QtGui.QFont()
font.setPointSize(11)
self.logistics_crates_checkBox.setFont(font)
self.logistics_crates_checkBox.setChecked(True)
self.logistics_crates_checkBox.setObjectName("logistics_crates_checkBox")
self.awacs_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.awacs_checkBox.setGeometry(QtCore.QRect(920, 350, 251, 31))
font = QtGui.QFont()
font.setPointSize(11)
self.awacs_checkBox.setFont(font)
self.awacs_checkBox.setStatusTip("")
self.awacs_checkBox.setChecked(True)
self.awacs_checkBox.setObjectName("awacs_checkBox")
self.tankers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.tankers_checkBox.setGeometry(QtCore.QRect(920, 380, 251, 31))
font = QtGui.QFont()
font.setPointSize(11)
self.tankers_checkBox.setFont(font)
self.tankers_checkBox.setChecked(True)
self.tankers_checkBox.setObjectName("tankers_checkBox")
self.apcs_spawn_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(450, 420, 251, 31))
font.setBold(False)
self.redforces_comboBox.setFont(font)
self.redforces_comboBox.setObjectName("redforces_comboBox")
self.scenario_label_8 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_8.setGeometry(QtCore.QRect(570, 220, 271, 24))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.apcs_spawn_checkBox.setFont(font)
self.apcs_spawn_checkBox.setChecked(True)
self.apcs_spawn_checkBox.setObjectName("apcs_spawn_checkBox")
self.inf_spawn_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.inf_spawn_spinBox.setGeometry(QtCore.QRect(670, 340, 51, 31))
font.setBold(False)
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))
font = QtGui.QFont()
font.setPointSize(12)
self.inf_spawn_spinBox.setFont(font)
self.inf_spawn_spinBox.setMinimum(0)
self.inf_spawn_spinBox.setMaximum(20)
self.inf_spawn_spinBox.setProperty("value", 2)
self.inf_spawn_spinBox.setObjectName("inf_spawn_spinBox")
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
self.slot_template_comboBox.setFont(font)
self.slot_template_comboBox.setObjectName("slot_template_comboBox")
self.scenario_label_5 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_5.setGeometry(QtCore.QRect(50, 260, 101, 31))
self.scenario_label_5.setGeometry(QtCore.QRect(1130, 40, 131, 18))
font = QtGui.QFont()
font.setPointSize(8)
self.scenario_label_5.setFont(font)
self.scenario_label_5.setAlignment(QtCore.Qt.AlignCenter)
self.scenario_label_5.setObjectName("scenario_label_5")
self.forces_hint_label_2 = QtWidgets.QLabel(self.centralwidget)
self.forces_hint_label_2.setGeometry(QtCore.QRect(790, 270, 311, 20))
self.forces_hint_label_2.setAlignment(QtCore.Qt.AlignCenter)
self.forces_hint_label_2.setObjectName("forces_hint_label_2")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(450, 340, 211, 21))
self.blue_forces_label = QtWidgets.QLabel(self.centralwidget)
self.blue_forces_label.setGeometry(QtCore.QRect(470, 30, 161, 27))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.label.setFont(font)
self.label.setObjectName("label")
self.slot_template_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.slot_template_comboBox.setGeometry(QtCore.QRect(870, 640, 291, 31))
self.slot_template_comboBox.setObjectName("slot_template_comboBox")
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(750, 640, 111, 31))
font.setBold(False)
self.blue_forces_label.setFont(font)
self.blue_forces_label.setObjectName("blue_forces_label")
self.blueqty_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.blueqty_spinBox.setGeometry(QtCore.QRect(1070, 30, 51, 31))
font = QtGui.QFont()
font.setPointSize(11)
self.label_2.setFont(font)
self.label_2.setObjectName("label_2")
self.force_offroad_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.force_offroad_checkBox.setGeometry(QtCore.QRect(810, 820, 191, 16))
font.setPointSize(12)
self.blueqty_spinBox.setFont(font)
self.blueqty_spinBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.PlusMinus)
self.blueqty_spinBox.setMinimum(0)
self.blueqty_spinBox.setMaximum(8)
self.blueqty_spinBox.setProperty("value", 3)
self.blueqty_spinBox.setObjectName("blueqty_spinBox")
self.blueforces_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.blueforces_comboBox.setGeometry(QtCore.QRect(660, 30, 391, 33))
font = QtGui.QFont()
font.setFamily("Arial")
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.defense_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.defense_checkBox.setGeometry(QtCore.QRect(60, 90, 181, 31))
font.setBold(False)
self.blueforces_comboBox.setFont(font)
self.blueforces_comboBox.setObjectName("blueforces_comboBox")
self.scenario_label_4 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_4.setGeometry(QtCore.QRect(1130, 90, 131, 18))
font = QtGui.QFont()
font.setPointSize(11)
self.defense_checkBox.setFont(font)
self.defense_checkBox.setObjectName("defense_checkBox")
font.setPointSize(8)
self.scenario_label_4.setFont(font)
self.scenario_label_4.setAlignment(QtCore.Qt.AlignCenter)
self.scenario_label_4.setObjectName("scenario_label_4")
self.version_label = QtWidgets.QLabel(self.centralwidget)
self.version_label.setGeometry(QtCore.QRect(1140, 650, 111, 20))
self.version_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.version_label.setObjectName("version_label")
self.scenario_label_10 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_10.setGeometry(QtCore.QRect(570, 260, 271, 24))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
self.scenario_label_10.setFont(font)
self.scenario_label_10.setObjectName("scenario_label_10")
self.e_transport_helos_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.e_transport_helos_spinBox.setGeometry(QtCore.QRect(510, 260, 51, 31))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.e_transport_helos_spinBox.sizePolicy().hasHeightForWidth())
self.e_transport_helos_spinBox.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(12)
self.e_transport_helos_spinBox.setFont(font)
self.e_transport_helos_spinBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.PlusMinus)
self.e_transport_helos_spinBox.setMinimum(0)
self.e_transport_helos_spinBox.setMaximum(8)
self.e_transport_helos_spinBox.setProperty("value", 1)
self.e_transport_helos_spinBox.setObjectName("e_transport_helos_spinBox")
self.e_attack_planes_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.e_attack_planes_spinBox.setGeometry(QtCore.QRect(510, 220, 51, 31))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.e_attack_planes_spinBox.sizePolicy().hasHeightForWidth())
self.e_attack_planes_spinBox.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(12)
self.e_attack_planes_spinBox.setFont(font)
self.e_attack_planes_spinBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.PlusMinus)
self.e_attack_planes_spinBox.setMinimum(0)
self.e_attack_planes_spinBox.setMaximum(8)
self.e_attack_planes_spinBox.setProperty("value", 1)
self.e_attack_planes_spinBox.setObjectName("e_attack_planes_spinBox")
self.e_attack_helos_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.e_attack_helos_spinBox.setGeometry(QtCore.QRect(70, 330, 51, 31))
self.e_attack_helos_spinBox.setGeometry(QtCore.QRect(510, 180, 51, 31))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.e_attack_helos_spinBox.sizePolicy().hasHeightForWidth())
self.e_attack_helos_spinBox.setSizePolicy(sizePolicy)
font = QtGui.QFont()
font.setPointSize(12)
self.e_attack_helos_spinBox.setFont(font)
self.e_attack_helos_spinBox.setReadOnly(False)
self.e_attack_helos_spinBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.PlusMinus)
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.setObjectName("e_attack_helos_spinBox")
self.scenario_label_7 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_7.setGeometry(QtCore.QRect(140, 330, 211, 31))
self.scenario_label_7.setGeometry(QtCore.QRect(570, 180, 271, 24))
font = QtGui.QFont()
font.setPointSize(11)
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
self.scenario_label_7.setFont(font)
self.scenario_label_7.setObjectName("scenario_label_7")
self.scenario_label_8 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_8.setGeometry(QtCore.QRect(140, 370, 201, 31))
self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(840, 390, 111, 24))
font = QtGui.QFont()
font.setPointSize(11)
self.scenario_label_8.setFont(font)
self.scenario_label_8.setObjectName("scenario_label_8")
self.e_attack_planes_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.e_attack_planes_spinBox.setGeometry(QtCore.QRect(70, 370, 51, 31))
font = QtGui.QFont()
font.setPointSize(12)
self.e_attack_planes_spinBox.setFont(font)
self.e_attack_planes_spinBox.setMinimum(0)
self.e_attack_planes_spinBox.setMaximum(8)
self.e_attack_planes_spinBox.setProperty("value", 1)
self.e_attack_planes_spinBox.setObjectName("e_attack_planes_spinBox")
self.zone_sams_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.zone_sams_checkBox.setGeometry(QtCore.QRect(920, 410, 201, 31))
font = QtGui.QFont()
font.setPointSize(11)
self.zone_sams_checkBox.setFont(font)
self.zone_sams_checkBox.setObjectName("zone_sams_checkBox")
font.setFamily("Arial")
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(810, 450, 171, 31))
self.scenario_label_9.setGeometry(QtCore.QRect(490, 450, 251, 23))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
self.scenario_label_9.setFont(font)
self.scenario_label_9.setObjectName("scenario_label_9")
self.inf_spawn_voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.inf_spawn_voiceovers_checkBox.setGeometry(QtCore.QRect(810, 720, 251, 31))
self.awacs_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.awacs_checkBox.setGeometry(QtCore.QRect(990, 246, 241, 28))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
self.awacs_checkBox.setFont(font)
self.awacs_checkBox.setStatusTip("")
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))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
self.tankers_checkBox.setFont(font)
self.tankers_checkBox.setChecked(True)
self.tankers_checkBox.setObjectName("tankers_checkBox")
self.inf_spawn_voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.inf_spawn_voiceovers_checkBox.setGeometry(QtCore.QRect(960, 455, 271, 24))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.inf_spawn_voiceovers_checkBox.setFont(font)
self.inf_spawn_voiceovers_checkBox.setChecked(True)
self.inf_spawn_voiceovers_checkBox.setObjectName("inf_spawn_voiceovers_checkBox")
self.farp_never = QtWidgets.QRadioButton(self.centralwidget)
self.farp_never.setGeometry(QtCore.QRect(950, 500, 95, 20))
self.voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.voiceovers_checkBox.setGeometry(QtCore.QRect(960, 517, 171, 24))
font = QtGui.QFont()
font.setFamily("Arial")
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, 424, 271, 24))
font = QtGui.QFont()
font.setFamily("Arial")
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, 486, 271, 24))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.game_status_checkBox.setFont(font)
self.game_status_checkBox.setChecked(True)
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))
font = QtGui.QFont()
font.setFamily("Arial")
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))
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.setObjectName("inf_spawn_spinBox")
self.troop_drop_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.troop_drop_spinBox.setGeometry(QtCore.QRect(510, 330, 47, 31))
font = QtGui.QFont()
font.setPointSize(12)
self.troop_drop_spinBox.setFont(font)
self.troop_drop_spinBox.setButtonSymbols(QtWidgets.QAbstractSpinBox.PlusMinus)
self.troop_drop_spinBox.setMinimum(0)
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))
font = QtGui.QFont()
font.setFamily("Arial")
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.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setGeometry(QtCore.QRect(570, 330, 281, 23))
font = QtGui.QFont()
font.setFamily("Arial")
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))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10)
font.setBold(False)
self.apcs_spawn_checkBox.setFont(font)
self.apcs_spawn_checkBox.setChecked(True)
self.apcs_spawn_checkBox.setObjectName("apcs_spawn_checkBox")
self.generateButton = QtWidgets.QPushButton(self.centralwidget)
self.generateButton.setGeometry(QtCore.QRect(710, 600, 231, 51))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(8)
font.setBold(True)
self.generateButton.setFont(font)
self.generateButton.setStyleSheet("background-color: gray;\n"
"color: rgb(255, 255, 255);\n"
"border-style: outset;\n"
"border-width: 1px;\n"
"border-radius: 5px;\n"
"border-color: black;\n"
"padding: 4px;")
self.generateButton.setObjectName("generateButton")
self.farp_always = QtWidgets.QRadioButton(self.centralwidget)
self.farp_always.setGeometry(QtCore.QRect(510, 480, 261, 24))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.farp_always.setFont(font)
self.farp_always.setObjectName("farp_always")
self.farp_buttonGroup = QtWidgets.QButtonGroup(MainWindow)
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))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.farp_never.setFont(font)
self.farp_never.setObjectName("farp_never")
self.farp_buttonGroup = QtWidgets.QButtonGroup(MainWindow)
self.farp_buttonGroup.setObjectName("farp_buttonGroup")
self.farp_buttonGroup.addButton(self.farp_never)
self.farp_gunits = QtWidgets.QRadioButton(self.centralwidget)
self.farp_gunits.setGeometry(QtCore.QRect(950, 530, 221, 21))
self.farp_gunits.setGeometry(QtCore.QRect(510, 509, 261, 24))
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
self.farp_gunits.setFont(font)
self.farp_gunits.setChecked(True)
self.farp_gunits.setObjectName("farp_gunits")
self.farp_buttonGroup.addButton(self.farp_gunits)
self.farp_always = QtWidgets.QRadioButton(self.centralwidget)
self.farp_always.setGeometry(QtCore.QRect(950, 560, 221, 21))
font = QtGui.QFont()
font.setPointSize(9)
self.farp_always.setFont(font)
self.farp_always.setObjectName("farp_always")
self.farp_buttonGroup.addButton(self.farp_always)
self.version_label = QtWidgets.QLabel(self.centralwidget)
self.version_label.setGeometry(QtCore.QRect(920, 840, 241, 21))
self.version_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.version_label.setObjectName("version_label")
self.scenario_label_10 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_10.setGeometry(QtCore.QRect(140, 410, 241, 31))
font = QtGui.QFont()
font.setPointSize(11)
self.scenario_label_10.setFont(font)
self.scenario_label_10.setObjectName("scenario_label_10")
self.e_transport_helos_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.e_transport_helos_spinBox.setGeometry(QtCore.QRect(70, 410, 51, 31))
font = QtGui.QFont()
font.setPointSize(12)
self.e_transport_helos_spinBox.setFont(font)
self.e_transport_helos_spinBox.setMinimum(0)
self.e_transport_helos_spinBox.setMaximum(8)
self.e_transport_helos_spinBox.setProperty("value", 1)
self.e_transport_helos_spinBox.setObjectName("e_transport_helos_spinBox")
self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setGeometry(QtCore.QRect(450, 380, 191, 31))
font = QtGui.QFont()
font.setPointSize(10)
self.label_3.setFont(font)
self.label_3.setObjectName("label_3")
self.troop_drop_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.troop_drop_spinBox.setGeometry(QtCore.QRect(670, 380, 51, 31))
font = QtGui.QFont()
font.setPointSize(12)
self.troop_drop_spinBox.setFont(font)
self.troop_drop_spinBox.setMinimum(0)
self.troop_drop_spinBox.setMaximum(10)
self.troop_drop_spinBox.setProperty("value", 4)
self.troop_drop_spinBox.setObjectName("troop_drop_spinBox")
self.smoke_pickup_zone_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.smoke_pickup_zone_checkBox.setGeometry(QtCore.QRect(810, 690, 251, 31))
font = QtGui.QFont()
font.setPointSize(9)
self.smoke_pickup_zone_checkBox.setFont(font)
self.smoke_pickup_zone_checkBox.setChecked(True)
self.smoke_pickup_zone_checkBox.setObjectName("smoke_pickup_zone_checkBox")
self.background_label.raise_()
self.scenario_comboBox.raise_()
self.scenario_label.raise_()
self.generateButton.raise_()
self.description_textBrowser.raise_()
self.blueforces_comboBox.raise_()
self.blue_forces_label.raise_()
self.red_forces_label.raise_()
self.redforces_comboBox.raise_()
self.scenario_hint_label.raise_()
self.forces_hint_label.raise_()
self.blueqty_spinBox.raise_()
self.redqty_spinBox.raise_()
self.scenario_label_4.raise_()
self.game_status_checkBox.raise_()
self.voiceovers_checkBox.raise_()
self.logistics_crates_checkBox.raise_()
self.awacs_checkBox.raise_()
self.tankers_checkBox.raise_()
self.apcs_spawn_checkBox.raise_()
self.inf_spawn_spinBox.raise_()
self.scenario_label_5.raise_()
self.forces_hint_label_2.raise_()
self.label.raise_()
self.slot_template_comboBox.raise_()
self.label_2.raise_()
self.force_offroad_checkBox.raise_()
self.defense_checkBox.raise_()
self.e_attack_helos_spinBox.raise_()
self.scenario_label_7.raise_()
self.scenario_label_8.raise_()
self.e_attack_planes_spinBox.raise_()
self.zone_sams_checkBox.raise_()
self.scenario_label_9.raise_()
self.inf_spawn_voiceovers_checkBox.raise_()
self.farp_never.raise_()
self.farp_gunits.raise_()
self.farp_always.raise_()
self.version_label.raise_()
self.scenario_label_10.raise_()
self.e_transport_helos_spinBox.raise_()
self.label_3.raise_()
self.troop_drop_spinBox.raise_()
self.smoke_pickup_zone_checkBox.raise_()
self.missionImage = QtWidgets.QLabel(self.centralwidget)
self.missionImage.setEnabled(True)
self.missionImage.setGeometry(QtCore.QRect(60, 80, 300, 300))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.missionImage.sizePolicy().hasHeightForWidth())
self.missionImage.setSizePolicy(sizePolicy)
self.missionImage.setMinimumSize(QtCore.QSize(300, 300))
self.missionImage.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.missionImage.setStyleSheet("")
self.missionImage.setText("")
self.missionImage.setPixmap(QtGui.QPixmap("assets/briefing1.png"))
self.missionImage.setScaledContents(True)
self.missionImage.setWordWrap(False)
self.missionImage.setObjectName("missionImage")
self.nextScenario_pushButton = QtWidgets.QPushButton(self.centralwidget)
self.nextScenario_pushButton.setGeometry(QtCore.QRect(370, 210, 31, 51))
self.nextScenario_pushButton.setObjectName("nextScenario_pushButton")
self.prevScenario_pushButton = QtWidgets.QPushButton(self.centralwidget)
self.prevScenario_pushButton.setGeometry(QtCore.QRect(20, 210, 31, 51))
self.prevScenario_pushButton.setObjectName("prevScenario_pushButton")
self.background_label = QtWidgets.QLabel(self.centralwidget)
self.background_label.setGeometry(QtCore.QRect(1020, 600, 241, 51))
self.background_label.setText("")
self.background_label.setPixmap(QtGui.QPixmap("assets/rotorops-dkgray.png"))
self.background_label.setScaledContents(True)
self.background_label.setObjectName("background_label")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1209, 26))
self.menubar.setGeometry(QtCore.QRect(0, 0, 1280, 26))
self.menubar.setObjectName("menubar")
self.menuMap = QtWidgets.QMenu(self.menubar)
self.menuMap.setObjectName("menuMap")
self.menuGametype_Filter = QtWidgets.QMenu(self.menubar)
self.menuGametype_Filter.setObjectName("menuGametype_Filter")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9)
font.setBold(False)
self.statusbar.setFont(font)
self.statusbar.setAcceptDrops(False)
self.statusbar.setStyleSheet("color: rgb(255, 255, 255);")
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.action_generateMission = QtWidgets.QAction(MainWindow)
@ -382,84 +515,131 @@ class Ui_MainWindow(object):
self.action_redforcesSelected.setObjectName("action_redforcesSelected")
self.action_defensiveModeChanged = QtWidgets.QAction(MainWindow)
self.action_defensiveModeChanged.setObjectName("action_defensiveModeChanged")
self.action_nextScenario = QtWidgets.QAction(MainWindow)
self.action_nextScenario.setObjectName("action_nextScenario")
self.action_prevScenario = QtWidgets.QAction(MainWindow)
self.action_prevScenario.setObjectName("action_prevScenario")
self.actionCaucasus = QtWidgets.QAction(MainWindow)
self.actionCaucasus.setObjectName("actionCaucasus")
self.actionPersian_Gulf = QtWidgets.QAction(MainWindow)
self.actionPersian_Gulf.setObjectName("actionPersian_Gulf")
self.actionMarianas = QtWidgets.QAction(MainWindow)
self.actionMarianas.setObjectName("actionMarianas")
self.actionNevada = QtWidgets.QAction(MainWindow)
self.actionNevada.setObjectName("actionNevada")
self.actionSyria = QtWidgets.QAction(MainWindow)
self.actionSyria.setObjectName("actionSyria")
self.actionAll = QtWidgets.QAction(MainWindow)
self.actionAll.setCheckable(True)
self.actionAll.setChecked(True)
self.actionAll.setObjectName("actionAll")
self.actionMultiplayer = QtWidgets.QAction(MainWindow)
self.actionMultiplayer.setCheckable(False)
self.actionMultiplayer.setObjectName("actionMultiplayer")
self.actionAll_2 = QtWidgets.QAction(MainWindow)
self.actionAll_2.setCheckable(True)
self.actionAll_2.setChecked(True)
self.actionAll_2.setObjectName("actionAll_2")
self.menuMap.addAction(self.actionAll_2)
self.menuMap.addAction(self.actionCaucasus)
self.menuMap.addAction(self.actionPersian_Gulf)
self.menuMap.addAction(self.actionMarianas)
self.menuMap.addAction(self.actionNevada)
self.menuMap.addAction(self.actionSyria)
self.menuGametype_Filter.addAction(self.actionAll)
self.menuGametype_Filter.addAction(self.actionMultiplayer)
self.menubar.addAction(self.menuMap.menuAction())
self.menubar.addAction(self.menuGametype_Filter.menuAction())
self.retranslateUi(MainWindow)
self.generateButton.clicked.connect(self.action_generateMission.trigger)
self.scenario_comboBox.currentIndexChanged['int'].connect(self.action_scenarioSelected.trigger)
self.defense_checkBox.stateChanged['int'].connect(self.action_defensiveModeChanged.trigger)
self.nextScenario_pushButton.clicked.connect(self.action_nextScenario.trigger)
self.prevScenario_pushButton.clicked.connect(self.action_prevScenario.trigger)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
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.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.scenario_label.setText(_translate("MainWindow", "Scenario Template:"))
self.generateButton.setText(_translate("MainWindow", "Generate Mission"))
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"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n"
"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"
"</style></head><body style=\" font-family:\'Arial\'; 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.blueforces_comboBox.setStatusTip(_translate("MainWindow", "Tip: You can create your own custom ground forces groups to be automatically generated."))
self.blue_forces_label.setText(_translate("MainWindow", "Friendly Forces:"))
self.red_forces_label.setText(_translate("MainWindow", "Enemy Forces:"))
self.redforces_comboBox.setStatusTip(_translate("MainWindow", "Tip: You can create your own custom ground forces groups to be automatically generated."))
self.scenario_hint_label.setText(_translate("MainWindow", "Scenario templates are .miz files in \'Generator/Scenarios\'"))
self.forces_hint_label.setText(_translate("MainWindow", "Forces templates are .miz files in \'Generator/Forces\'"))
self.blueqty_spinBox.setStatusTip(_translate("MainWindow", "How many groups should we generate?"))
self.defense_checkBox.setText(_translate("MainWindow", "Blue on Defense"))
self.redqty_spinBox.setStatusTip(_translate("MainWindow", "How many groups should we generate?"))
self.scenario_label_4.setText(_translate("MainWindow", "Groups Per Zone"))
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.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.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.awacs_checkBox.setText(_translate("MainWindow", "Friendly AWACS"))
self.tankers_checkBox.setText(_translate("MainWindow", "Friendly Tankers"))
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", "APCs Spawn Infantry"))
self.inf_spawn_spinBox.setStatusTip(_translate("MainWindow", "This value is multiplied by the number of spawn zones in the mission template."))
self.scenario_label_5.setText(_translate("MainWindow", "Groups Per Zone"))
self.forces_hint_label_2.setText(_translate("MainWindow", "Forces templates are .miz files in \'Generator/Forces\'"))
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.slot_template_comboBox.setStatusTip(_translate("MainWindow", "Default player/client spawn locations at a friendly airport."))
self.label_2.setText(_translate("MainWindow", "Player Slots"))
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.defense_checkBox.setText(_translate("MainWindow", "Defensive Mode"))
self.e_attack_helos_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack helicopter group spawns."))
self.scenario_label_7.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack helicopter group spawns."))
self.scenario_label_7.setText(_translate("MainWindow", "Enemy Attack Helicopters"))
self.redforces_comboBox.setStatusTip(_translate("MainWindow", "Tip: You can create your own custom ground forces groups to be automatically generated."))
self.scenario_label_8.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack plane group spawns."))
self.scenario_label_8.setText(_translate("MainWindow", "Enemy Attack Planes"))
self.e_attack_planes_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack plane group spawns."))
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.scenario_label_9.setText(_translate("MainWindow", "Zone FARP Conditions:"))
self.inf_spawn_voiceovers_checkBox.setStatusTip(_translate("MainWindow", "Friendly/enemy APCs will drop infantry when reaching a new conflict zone."))
self.inf_spawn_voiceovers_checkBox.setText(_translate("MainWindow", "Voiceovers on Infantry Spawn"))
self.farp_never.setStatusTip(_translate("MainWindow", "Never spawn FARPs in defeated conflict zones."))
self.farp_never.setText(_translate("MainWindow", "Never"))
self.farp_gunits.setStatusTip(_translate("MainWindow", "Only spawn FARPs in defeated conflict zones if we have sufficient ground units remaining."))
self.farp_gunits.setText(_translate("MainWindow", "20% Ground Units Remaining"))
self.farp_always.setStatusTip(_translate("MainWindow", "Always spawn a FARP in defeated conflict zones."))
self.farp_always.setText(_translate("MainWindow", "Always"))
self.slot_template_comboBox.setStatusTip(_translate("MainWindow", "Default player/client spawn locations at a friendly airport."))
self.scenario_label_5.setText(_translate("MainWindow", "Groups Per Zone"))
self.blue_forces_label.setText(_translate("MainWindow", "Blue Forces:"))
self.blueqty_spinBox.setStatusTip(_translate("MainWindow", "How many groups should we generate?"))
self.blueforces_comboBox.setStatusTip(_translate("MainWindow", "Tip: You can create your own custom ground forces groups to be automatically generated."))
self.scenario_label_4.setText(_translate("MainWindow", "Groups Per Zone"))
self.version_label.setText(_translate("MainWindow", "Version string"))
self.scenario_label_10.setStatusTip(_translate("MainWindow", "Approximate number of enemy transport helicopter spawns."))
self.scenario_label_10.setText(_translate("MainWindow", "Enemy Transport Helicopters"))
self.e_transport_helos_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy transport helicopter spawns."))
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.troop_drop_spinBox.setStatusTip(_translate("MainWindow", "The number of troop drops per transport helicopter flight."))
self.e_attack_planes_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack plane group spawns."))
self.e_attack_helos_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack helicopter group spawns."))
self.scenario_label_7.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack helicopter group spawns."))
self.scenario_label_7.setText(_translate("MainWindow", "Enemy Attack Helicopters"))
self.label_2.setText(_translate("MainWindow", "Player Slots:"))
self.scenario_label_9.setText(_translate("MainWindow", "Zone FARP Conditions:"))
self.awacs_checkBox.setText(_translate("MainWindow", "Friendly AWACS"))
self.tankers_checkBox.setText(_translate("MainWindow", "Friendly Tankers"))
self.inf_spawn_voiceovers_checkBox.setStatusTip(_translate("MainWindow", "Friendly/enemy APCs will drop infantry when reaching a new conflict zone."))
self.inf_spawn_voiceovers_checkBox.setText(_translate("MainWindow", "Voiceovers on Infantry Spawn"))
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.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.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.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", "APCs Spawn Infantry"))
self.generateButton.setText(_translate("MainWindow", "GENERATE MISSION"))
self.farp_always.setStatusTip(_translate("MainWindow", "Always spawn a FARP in defeated conflict zones."))
self.farp_always.setText(_translate("MainWindow", "Always"))
self.farp_never.setStatusTip(_translate("MainWindow", "Never spawn FARPs in defeated conflict zones."))
self.farp_never.setText(_translate("MainWindow", "Never"))
self.farp_gunits.setStatusTip(_translate("MainWindow", "Only spawn FARPs in defeated conflict zones if we have sufficient ground units remaining."))
self.farp_gunits.setText(_translate("MainWindow", "20% Ground Units Remaining"))
self.nextScenario_pushButton.setText(_translate("MainWindow", ">"))
self.prevScenario_pushButton.setText(_translate("MainWindow", "<"))
self.menuMap.setTitle(_translate("MainWindow", "Map Filter"))
self.menuGametype_Filter.setTitle(_translate("MainWindow", "Gametype Filter"))
self.action_generateMission.setText(_translate("MainWindow", "_generateMission"))
self.action_scenarioSelected.setText(_translate("MainWindow", "_scenarioSelected"))
self.action_blueforcesSelected.setText(_translate("MainWindow", "_blueforcesSelected"))
self.action_redforcesSelected.setText(_translate("MainWindow", "_redforcesSelected"))
self.action_defensiveModeChanged.setText(_translate("MainWindow", "_defensiveModeChanged"))
self.action_nextScenario.setText(_translate("MainWindow", "_nextScenario"))
self.action_prevScenario.setText(_translate("MainWindow", "_prevScenario"))
self.actionCaucasus.setText(_translate("MainWindow", "Caucasus"))
self.actionPersian_Gulf.setText(_translate("MainWindow", "Persian Gulf"))
self.actionMarianas.setText(_translate("MainWindow", "Marianas"))
self.actionNevada.setText(_translate("MainWindow", "Nevada"))
self.actionSyria.setText(_translate("MainWindow", "Syria"))
self.actionAll.setText(_translate("MainWindow", "All"))
self.actionMultiplayer.setText(_translate("MainWindow", "Multiplayer"))
self.actionAll_2.setText(_translate("MainWindow", "All"))
if __name__ == "__main__":

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,159 @@
import dcs
import random
jtf_red = "Combined Joint Task Forces Red"
jtf_blue = "Combined Joint Task Forces Blue"
def triggerSetup(rops, options):
# get the boolean value from ui option and convert to lua string
def lb(var):
return str(options[var]).lower()
game_flag = 100
# 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"]))
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["RotorOps.lua"]))
script = ""
script = ("--OPTIONS HERE!\n\n" +
"RotorOps.CTLD_crates = " + lb("crates") + "\n\n" +
"RotorOps.CTLD_sound_effects = true\n\n" +
"RotorOps.force_offroad = " + lb("force_offroad") + "\n\n" +
"RotorOps.voice_overs = " + lb("voiceovers") + "\n\n" +
"RotorOps.zone_status_display = " + lb("game_display") + "\n\n" +
"RotorOps.inf_spawn_messages = " + lb("inf_spawn_msgs") + "\n\n" +
"RotorOps.inf_spawns_per_zone = " + 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))))
rops.m.triggerrules.triggers.append(trig)
# Add the second trigger
trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Zones")
trig.rules.append(dcs.condition.TimeAfter(2))
for s_zone in rops.staging_zones:
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.stagingZone('" + s_zone + "')")))
for c_zone in rops.conflict_zones:
zone_flag = rops.conflict_zones[c_zone].flag
trig.actions.append(
dcs.action.DoScript(dcs.action.String("RotorOps.addZone('" + c_zone + "'," + str(zone_flag) + ")")))
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.setupConflict('" + str(game_flag) + "')")))
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 generic zone-based triggers
for index, zone_name in enumerate(rops.conflict_zones):
z_active_trig = dcs.triggers.TriggerOnce(comment=zone_name + " Active")
z_active_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_active_trig.actions.append(dcs.action.DoScript(dcs.action.String("--Add any action you want here!")))
rops.m.triggerrules.triggers.append(z_active_trig)
# Zone protection SAMs
if options["zone_protect_sams"]:
for index, zone_name in enumerate(rops.conflict_zones):
z_sams_trig = dcs.triggers.TriggerOnce(comment="Deactivate " + zone_name + " SAMs")
z_sams_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_sams_trig.actions.append(dcs.action.DoScript(
dcs.action.String("Group.destroy(Group.getByName('Static " + zone_name + " Protection SAM'))")))
rops.m.triggerrules.triggers.append(z_sams_trig)
# Zone FARPS always
if options["zone_farps"] == "farp_always" and not options["defending"]:
for index, zone_name in enumerate(rops.conflict_zones):
if index > 0:
previous_zone = list(rops.conflict_zones)[index - 1]
if not rops.m.country(jtf_blue).find_group(previous_zone + " FARP Static"):
continue
z_farps_trig = dcs.triggers.TriggerOnce(comment="Activate " + previous_zone + " FARP")
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'])))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"RotorOps.farpEstablished(" + str(index) + ")")))
rops.m.triggerrules.triggers.append(z_farps_trig)
# Zone FARPS conditional on staged units remaining
if options["zone_farps"] == "farp_gunits" and not options["defending"]:
for index, zone_name in enumerate(rops.conflict_zones):
if index > 0:
previous_zone = list(rops.conflict_zones)[index - 1]
if not rops.m.country(jtf_blue).find_group(previous_zone + " FARP Static"):
continue
z_farps_trig = dcs.triggers.TriggerOnce(comment="Activate " + previous_zone + " FARP")
z_farps_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_farps_trig.rules.append(dcs.condition.FlagIsMore(111, 20))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"--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'])))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"RotorOps.farpEstablished(" + str(index) + ")")))
rops.m.triggerrules.triggers.append(z_farps_trig)
# Add attack helos triggers
for index in range(options["e_attack_helos"]):
random_zone_obj = random.choice(list(rops.conflict_zones.items()))
zone = random_zone_obj[1]
z_weak_trig = dcs.triggers.TriggerOnce(comment=zone.name + " Attack Helo")
z_weak_trig.rules.append(dcs.condition.FlagIsMore(zone.flag, 1))
z_weak_trig.rules.append(dcs.condition.FlagIsLess(zone.flag, random.randrange(20, 90)))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag " + str(
zone.flag) + " value represents the percentage of defending ground units remaining in zone. ")))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.spawnAttackHelos()")))
rops.m.triggerrules.triggers.append(z_weak_trig)
# Add attack plane triggers
for index in range(options["e_attack_planes"]):
random_zone_obj = random.choice(list(rops.conflict_zones.items()))
zone = random_zone_obj[1]
z_weak_trig = dcs.triggers.TriggerOnce(comment=zone.name + " Attack Plane")
z_weak_trig.rules.append(dcs.condition.FlagIsMore(zone.flag, 1))
z_weak_trig.rules.append(dcs.condition.FlagIsLess(zone.flag, random.randrange(20, 90)))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag " + str(
zone.flag) + " value represents the percentage of defending ground units remaining in zone. ")))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.spawnAttackPlanes()")))
rops.m.triggerrules.triggers.append(z_weak_trig)
# Add transport helos triggers
for index in range(options["e_transport_helos"]):
random_zone_index = random.randrange(1, len(rops.conflict_zones))
random_zone_obj = list(rops.conflict_zones.items())[random_zone_index]
zone = random_zone_obj[1]
z_weak_trig = dcs.triggers.TriggerOnce(comment=zone.name + " Transport Helo")
z_weak_trig.rules.append(dcs.condition.FlagEquals(game_flag, random_zone_index + 1))
z_weak_trig.rules.append(dcs.condition.FlagIsLess(zone.flag, random.randrange(20, 100)))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"---Flag " + str(game_flag) + " value represents the index of the active zone. ")))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag " + str(
zone.flag) + " value represents the percentage of defending ground units remaining in zone. ")))
z_weak_trig.actions.append(dcs.action.DoScript(
dcs.action.String("RotorOps.spawnTranspHelos(8," + str(options["transport_drop_qty"]) + ")")))
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")))
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")))
rops.m.triggerrules.triggers.append(trig)

View File

@ -25,7 +25,7 @@ class VehicleTemplate:
dcs.vehicles.Unarmed.M_818,
dcs.vehicles.AirDefence.Vulcan,
dcs.vehicles.Unarmed.Ural_375,
dcs.vehicles.Unarmed.M978_HEMTT_Tanker
dcs.vehicles.Unarmed.M978_HEMTT_Tanker,
],
position.point_from_heading(45, 7),
heading=random.randint(0, 359),

233
Generator/RotorOpsImport.py Normal file
View File

@ -0,0 +1,233 @@
import math
import dcs
from MissionGenerator import logger
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
logger.info("Importing objects from " + mizfile)
self.source_mission = dcs.mission.Mission()
self.source_mission.load_file(mizfile)
self.source_heading = None
self.source_point = None
self.statics = []
self.vehicles = []
self.helicopters = []
self.extractUnits()
def getStatics(self):
return self.statics
def getVehicles(self):
return self.vehicles
def getHelicopters(self):
return self.helicopters
def copyAll(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
return self.copyStatics(mission, dest_country_name, dest_name, dest_point, dest_heading), \
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:
self.source_point = group.units[0].position
self.source_heading = group.units[0].heading
else:
logger.warning("Unable to find group for anchor.")
raise Exception(
"Import template file error: " + self.mizfile + " does not contain a group called " + group_name)
def extractUnits(self):
for side in "red", "blue", "neutrals":
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,
coalition.countries[country_name].ship_group]
for index, group_type in enumerate(group_types):
for group in group_type:
if index == 0: # Statics
self.statics.append(group)
elif index == 1: # Vehicles
self.vehicles.append(group)
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 = []
if not dest_point:
dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
#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
shape_name = group.units[0].shape_name
rate = group.units[0].rate
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,
group.units[0].position,
group.units[0].heading,
hidden=False)
ng.units[0].name = group.units[0].name
new_groups.append(ng)
# if ng.units[0].type == "Invisible FARP":
# self.pad_unit = ng
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 = []
if not dest_point:
dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
vehicles_copy = self.vehicles
for group in vehicles_copy:
self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
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)
new_groups.append(ng) # will this hold units we add later?
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)
return new_groups
def copyHelicopters(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
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:
self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
if self.pad_unit:
if group.units[0].skill == dcs.unit.Skill.Client or group.units[0].skill == dcs.unit.Skill.Player:
# we'll create a new FARP for each helicopter. we've tried adding the flight group to an existing FARP, but they stack on top of each other
# 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)
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
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):
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:
self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
for i, unit in enumerate(group.units):
if unit_count == 0:
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
else:
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
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)))
return new_group
@staticmethod
def groupToPoint(group, src_point, dest_point, src_heading=0, dest_heading=0):
for unit in group.units:
heading_to_unit = dcs.mapping.heading_between_points(src_point.x, src_point.y, unit.position.x,
unit.position.y)
new_heading_to_unit = dest_heading + heading_to_unit
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

View File

@ -4,31 +4,39 @@ import dcs
import os
import random
import RotorOpsGroups
import RotorOpsUnits
import RotorOpsUtils
import RotorOpsConflict
from RotorOpsImport import ImportObjects
import time
from MissionGenerator import logger
from MissionGenerator import directories
jtf_red = "Combined Joint Task Forces Red"
jtf_blue = "Combined Joint Task Forces Blue"
class RotorOpsMission:
def __init__(self):
self.m = dcs.mission.Mission()
os.chdir("../")
self.home_dir = os.getcwd()
self.scenarios_dir = self.home_dir + "\Generator\Scenarios"
self.forces_dir = self.home_dir + "\Generator\Forces"
self.script_directory = self.home_dir
self.sound_directory = self.home_dir + "\sound\embedded"
self.output_dir = self.home_dir + "\Generator\Output"
self.assets_dir = self.home_dir + "\Generator/assets"
# os.chdir("../")
# directories.home_dir = os.getcwd()
# directories.scenarios = directories.home_dir + "\Generator\Scenarios"
# directories.forces = directories.home_dir + "\Generator\Forces"
# directories.scripts = directories.home_dir
# directories.sound = directories.home_dir + "\sound\embedded"
# directories.output = directories.home_dir + "\Generator\Output"
# directories.assets = directories.home_dir + "\Generator/assets"
# directories.imports = directories.home_dir + "\Generator\Imports"
self.conflict_zones = {}
self.staging_zones = {}
self.spawn_zones = {}
self.scripts = {}
self.res_map = {}
self.config = None
class RotorOpsZone:
def __init__(self, name: str, flag: int, position: dcs.point, size: int):
@ -37,9 +45,13 @@ class RotorOpsMission:
self.position = position
self.size = size
def getMission(self):
return self.m
def setConfig(self,config):
self.config = config
def addZone(self, zone_dict, zone: RotorOpsZone):
zone_dict[zone.name] = zone
@ -79,8 +91,8 @@ class RotorOpsMission:
attack_planes = []
fighter_planes = []
os.chdir(self.home_dir)
os.chdir(self.forces_dir + "/" + side)
os.chdir(directories.home_dir)
os.chdir(directories.forces + "/" + side)
logger.info("Looking for " + side + " Forces files in '" + os.getcwd())
source_mission = dcs.mission.Mission()
@ -114,13 +126,20 @@ class RotorOpsMission:
logger.error("Failed to load units from " + filename)
def generateMission(self, options):
os.chdir(self.scenarios_dir)
os.chdir(directories.scenarios)
logger.info("Looking for mission files in " + os.getcwd())
self.m.load_file(options["scenario_filename"])
if not self.m.country("Combined Joint Task Forces Red") or not self.m.country("Combined Joint Task Forces Blue"):
failure_msg = "You must include a CombinedJointTaskForcesBlue and CombinedJointTaskForcesRed unit in the scenario template. See the instructions in " + self.scenarios_dir
self.importObjects()
#todo: test
self.m.coalition.get("neutrals").add_country(dcs.countries.UnitedNationsPeacekeepers())
if not self.m.country(jtf_red) or not self.m.country(jtf_blue) or not self.m.country(dcs.countries.UnitedNationsPeacekeepers.name):
failure_msg = "You must include a CombinedJointTaskForcesBlue and CombinedJointTaskForcesRed unit in the scenario template. See the instructions in " + directories.scenarios
return {"success": False, "failure_msg": failure_msg}
red_forces = self.getUnitsFromMiz(options["red_forces_filename"], "red")
@ -129,10 +148,11 @@ class RotorOpsMission:
# Add coalitions (we may be able to add CJTF here instead of requiring templates to have objects of those coalitions)
self.m.coalition.get("red").add_country(dcs.countries.Russia())
self.m.coalition.get("blue").add_country(dcs.countries.USA())
# blue = self.m.coalition.get("blue")
# blue.add_country(dcs.countries.CombinedJointTaskForcesBlue())
self.m.add_picture_blue(self.assets_dir + '/briefing1.png')
self.m.add_picture_blue(self.assets_dir + '/briefing2.png')
self.m.add_picture_blue(directories.assets + '/briefing1.png')
self.m.add_picture_blue(directories.assets + '/briefing2.png')
# add zones to target mission
@ -163,20 +183,49 @@ class RotorOpsMission:
#Populate Red zones with ground units
for zone_name in red_zones:
if red_forces["vehicles"]:
self.addGroundGroups(red_zones[zone_name], self.m.country('Combined Joint Task Forces Red'), red_forces["vehicles"], options["red_quantity"])
self.addGroundGroups(red_zones[zone_name], self.m.country(jtf_red), red_forces["vehicles"], options["red_quantity"])
#Add red FARPS
if options["zone_farps"] != "farp_never" and not options["defending"]:
RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.zone_farp(self.m, self.m.country('Combined Joint Task Forces Blue'),
self.m.country('Combined Joint Task Forces Blue'),
red_zones[zone_name].position,
180, zone_name + " FARP", late_activation=True)
# RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.zone_farp(self.m, self.m.country(jtf_blue),
# self.m.country(jtf_blue),
# red_zones[zone_name].position,
# 180, zone_name + " FARP", late_activation=True)
#new_statics, new_vehicles, new_helicopters = i.copyAll(self.m, dcs.countries.UnitedNationsPeacekeepers.name, zone_name, red_zones[zone_name].position)
farp_flag = self.m.find_group(zone_name)
if farp_flag:
farp_position = farp_flag.units[0].position
farp_heading = farp_flag.units[0].heading
else:
farp_position = red_zones[zone_name].position
farp_heading = 0
farp = self.m.farp(self.m.country(jtf_blue), zone_name + " FARP", farp_position,
hidden=False, dead=False,
farp_type=dcs.unit.InvisibleFARP)
os.chdir(directories.imports)
if self.config and self.config["zone_farp_file"]:
filename = self.config["zone_farp_file"]
else:
filename = "FARP_DEFAULT_ZONE.miz"
i = ImportObjects(filename)
i.anchorByGroupName("ANCHOR")
farp_group = i.copyVehiclesAsGroup(self.m, jtf_blue, zone_name + " FARP Static", farp_position, farp_heading)
farp_group.late_activation = True
if options["zone_protect_sams"]:
self.m.vehicle_group(
self.m.country('Combined Joint Task Forces Red'),
self.m.country(jtf_red),
"Static " + zone_name + " Protection SAM",
random.choice(RotorOpsUnits.e_zone_sams),
red_zones[zone_name].position,
@ -190,20 +239,35 @@ class RotorOpsMission:
#Populate Blue zones with ground units
for zone_name in blue_zones:
if blue_forces["vehicles"]:
self.addGroundGroups(blue_zones[zone_name], self.m.country('Combined Joint Task Forces Blue'), blue_forces["vehicles"],
self.addGroundGroups(blue_zones[zone_name], self.m.country(jtf_blue), blue_forces["vehicles"],
options["blue_quantity"])
#Add blue FARPS
if options["zone_farps"] != "farp_never" and options["defending"]:
RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.zone_farp(self.m, self.m.country('Combined Joint Task Forces Blue'),
self.m.country('Combined Joint Task Forces Blue'),
RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.zone_farp(self.m, self.m.country(jtf_blue),
self.m.country(jtf_blue),
blue_zones[zone_name].position,
180, zone_name + " FARP", late_activation=False)
#add logistics sites
if options["crates"] and zone_name in self.staging_zones:
RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.logistics_site(self.m, self.m.country('Combined Joint Task Forces Blue'),
blue_zones[zone_name].position,
180, zone_name)
# RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.logistics_site(self.m, self.m.country(jtf_blue),
# blue_zones[zone_name].position,
# 180, zone_name)
os.chdir(directories.imports)
staging_flag = self.m.find_group(zone_name)
if staging_flag:
staging_position = staging_flag.units[0].position
staging_heading = staging_flag.units[0].heading
else:
staging_position = blue_zones[zone_name].position
staging_heading = 0
i = ImportObjects("STAGING_LOGISTIC_HUB.miz")
i.anchorByGroupName("ANCHOR")
i.copyAll(self.m, jtf_blue, "Staging Logistics Zone",
staging_position, staging_heading)
@ -211,7 +275,7 @@ class RotorOpsMission:
if options["zone_protect_sams"] and options["defending"]:
vg = self.m.vehicle_group(
self.m.country('Combined Joint Task Forces Blue'),
self.m.country(jtf_blue),
"Static " + zone_name + " Protection SAM",
random.choice(RotorOpsUnits.e_zone_sams),
blue_zones[zone_name].position,
@ -222,7 +286,8 @@ class RotorOpsMission:
#Add player slots
self.addPlayerHelos(options)
if options["slots"] != "Locked to Scenario" and options["slots"] != "None":
self.addPlayerHelos(options)
#Add AI Flights
self.addFlights(options, red_forces, blue_forces)
@ -232,14 +297,15 @@ class RotorOpsMission:
self.m.map.zoom = 100000
#add files and triggers necessary for RotorOps.lua script
self.addResources(self.sound_directory, self.script_directory)
self.scriptTriggerSetup(options)
self.addResources(directories.sound, directories.scripts)
RotorOpsConflict.triggerSetup(self, options)
#Save the mission file
os.chdir(self.output_dir)
os.chdir(directories.output)
output_filename = options["scenario_filename"].removesuffix('.miz') + " " + time.strftime('%a%H%M%S') + '.miz'
success = self.m.save(output_filename)
return {"success": success, "filename": output_filename, "directory": self.output_dir} #let the UI know the result
return {"success": success, "filename": output_filename, "directory": directories.output} #let the UI know the result
def addGroundGroups(self, zone, _country, groups, quantity):
for a in range(0, quantity):
@ -282,12 +348,15 @@ class RotorOpsMission:
def getParking(self, airport, aircraft, alt_airports=None, group_size=1):
if len(airport.free_parking_slots(aircraft)) >= group_size:
if not (aircraft.id in dcs.planes.plane_map and len(airport.runways) == 0):
if not (aircraft.id in dcs.planes.plane_map and (len(airport.runways) == 0 or airport.runways[0].ils is None)):
return airport
for airport in alt_airports:
if len(airport.free_parking_slots(aircraft)) >= group_size:
if not (aircraft.id in dcs.planes.plane_map and len(airport.runways) == 0):
return airport
if alt_airports:
for airport in alt_airports:
if len(airport.free_parking_slots(aircraft)) >= group_size:
if not (aircraft.id in dcs.planes.plane_map and len(airport.runways) == 0):
return airport
logger.warn("No parking available for " + aircraft.id)
return None
@ -309,8 +378,8 @@ class RotorOpsMission:
for airport in red_airports:
self.m.terrain.airports[airport.name].set_blue()
combinedJointTaskForcesBlue = self.m.country("Combined Joint Task Forces Blue")
combinedJointTaskForcesRed = self.m.country("Combined Joint Task Forces Red")
combinedJointTaskForcesBlue = self.m.country(jtf_blue)
combinedJointTaskForcesRed = self.m.country(jtf_red)
#Swap ships
@ -393,13 +462,13 @@ class RotorOpsMission:
client_helos = [dcs.helicopters.helicopter_map[helicopter]]
#find friendly carriers and farps
carrier = self.m.country("Combined Joint Task Forces Blue").find_ship_group(name="HELO_CARRIER")
carrier = self.m.country(jtf_blue).find_ship_group(name="HELO_CARRIER")
if not carrier:
carrier = self.m.country("Combined Joint Task Forces Blue").find_ship_group(name="HELO_CARRIER_1")
carrier = self.m.country(jtf_blue).find_ship_group(name="HELO_CARRIER_1")
farp = self.m.country("Combined Joint Task Forces Blue").find_static_group("HELO_FARP")
farp = self.m.country(jtf_blue).find_static_group("HELO_FARP")
if not farp:
farp = self.m.country("Combined Joint Task Forces Blue").find_static_group("HELO_FARP_1")
farp = self.m.country(jtf_blue).find_static_group("HELO_FARP_1")
friendly_airports, primary_f_airport = self.getCoalitionAirports("blue")
@ -410,20 +479,20 @@ class RotorOpsMission:
for helotype in client_helos:
if carrier:
fg = self.m.flight_group_from_unit(self.m.country('Combined Joint Task Forces Blue'), "CARRIER " + helotype.id, helotype, carrier,
fg = self.m.flight_group_from_unit(self.m.country(jtf_blue), "CARRIER " + helotype.id, helotype, carrier,
dcs.task.CAS, group_size=group_size)
elif farp:
fg = self.m.flight_group_from_unit(self.m.country('Combined Joint Task Forces Blue'), "FARP " + helotype.id, helotype, farp,
fg = self.m.flight_group_from_unit(self.m.country(jtf_blue), "FARP " + helotype.id, helotype, farp,
dcs.task.CAS, group_size=group_size)
#invisible farps need manual unit placement for multiple units
if farp.units[0].type == 'Invisible FARP':
fg.points[0].action = dcs.point.PointAction.FromGroundArea
fg.points[0].type = "TakeOffGround"
fg.units[0].position = fg.units[0].position.point_from_heading(heading, 30)
fg.units[0].position = fg.units[0].position.point_from_heading(heading, 20)
heading += 90
else:
fg = self.m.flight_group_from_airport(self.m.country('Combined Joint Task Forces Blue'), primary_f_airport.name + " " + helotype.id, helotype,
fg = self.m.flight_group_from_airport(self.m.country(jtf_blue), primary_f_airport.name + " " + helotype.id, helotype,
self.getParking(primary_f_airport, helotype), group_size=group_size)
fg.units[0].set_client()
fg.load_task_default_loadout(dcs.task.CAS)
@ -445,12 +514,12 @@ class RotorOpsMission:
return dcs.mapping.Point(x1, y1), heading, race_dist
@staticmethod
def perpRacetrack(enemy_heading, friendly_pt):
def perpRacetrack(enemy_heading, friendly_pt, terrain):
heading = enemy_heading + random.randrange(70,110)
race_dist = random.randrange(40 * 1000, 80 * 1000)
center_pt = dcs.mapping.point_from_heading(friendly_pt.x, friendly_pt.y, enemy_heading - random.randrange(140, 220), 10000)
pt1 = dcs.mapping.point_from_heading(center_pt[0], center_pt[1], enemy_heading - 90, random.randrange(20 * 1000, 40 * 1000))
return dcs.mapping.Point(pt1[0], pt1[1]), heading, race_dist
return dcs.mapping.Point(pt1[0], pt1[1], terrain), heading, race_dist
def addFlights(self, options, red_forces, blue_forces):
combinedJointTaskForcesBlue = self.m.country(dcs.countries.CombinedJointTaskForcesBlue.name)
@ -459,13 +528,13 @@ class RotorOpsMission:
enemy_airports, primary_e_airport = self.getCoalitionAirports("red")
#find enemy carriers and farps
carrier = self.m.country("Combined Joint Task Forces Red").find_ship_group(name="HELO_CARRIER")
carrier = self.m.country(jtf_red).find_ship_group(name="HELO_CARRIER")
if not carrier:
carrier = self.m.country("Combined Joint Task Forces Red").find_ship_group(name="HELO_CARRIER_1")
carrier = self.m.country(jtf_red).find_ship_group(name="HELO_CARRIER_1")
farp = self.m.country("Combined Joint Task Forces Red").find_static_group("HELO_FARP")
farp = self.m.country(jtf_red).find_static_group("HELO_FARP")
if not farp:
farp = self.m.country("Combined Joint Task Forces Red").find_static_group("HELO_FARP_1")
farp = self.m.country(jtf_red).find_static_group("HELO_FARP_1")
e_airport_heading = dcs.mapping.heading_between_points(
friendly_airports[0].position.x, friendly_airports[0].position.y, enemy_airports[0].position.x, primary_e_airport.position.y
@ -480,7 +549,7 @@ class RotorOpsMission:
awacs_name = "AWACS"
awacs_freq = 266
#pos, heading, race_dist = self.TrainingScenario.random_orbit(orbit_rect)
pos, heading, race_dist = self.TrainingScenario.perpRacetrack(e_airport_heading, primary_f_airport.position)
pos, heading, race_dist = self.TrainingScenario.perpRacetrack(e_airport_heading, primary_f_airport.position, self.m.terrain)
awacs = self.m.awacs_flight(
combinedJointTaskForcesBlue,
awacs_name,
@ -502,7 +571,7 @@ class RotorOpsMission:
awacs_escort = self.m.escort_flight(
combinedJointTaskForcesBlue, "AWACS Escort",
plane_type,
airport=self.getParking(primary_f_airport, plane_type, friendly_airports),
airport=self.getParking(primary_f_airport, plane_type, friendly_airports, group_size=2),
group_to_escort=awacs,
group_size=2)
@ -526,7 +595,7 @@ class RotorOpsMission:
t2_freq = 256
t2_tac = "101Y"
#pos, heading, race_dist = self.TrainingScenario.random_orbit(orbit_rect)
pos, heading, race_dist = self.TrainingScenario.perpRacetrack(e_airport_heading, primary_f_airport.position)
pos, heading, race_dist = self.TrainingScenario.perpRacetrack(e_airport_heading, primary_f_airport.position, self.m.terrain)
refuel_net = self.m.refuel_flight(
combinedJointTaskForcesBlue,
t1_name,
@ -542,7 +611,7 @@ class RotorOpsMission:
tacanchannel=t1_tac)
#pos, heading, race_dist = self.TrainingScenario.random_orbit(orbit_rect)
pos, heading, race_dist = self.TrainingScenario.perpRacetrack(e_airport_heading, primary_f_airport.position)
pos, heading, race_dist = self.TrainingScenario.perpRacetrack(e_airport_heading, primary_f_airport.position, self.m.terrain)
refuel_rod = self.m.refuel_flight(
combinedJointTaskForcesBlue,
t2_name,
@ -695,149 +764,33 @@ class RotorOpsMission:
unit.pylons = source_helo.pylons
unit.livery_id = source_helo.livery_id
def scriptTriggerSetup(self, options):
#get the boolean value from ui option and convert to lua string
def lb(var):
return str(options[var]).lower()
game_flag = 100
#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(self.scripts["mist_4_4_90.lua"]))
trig.actions.append(dcs.action.DoScriptFile(self.scripts["Splash_Damage_2_0.lua"]))
trig.actions.append(dcs.action.DoScriptFile(self.scripts["CTLD.lua"]))
trig.actions.append(dcs.action.DoScriptFile(self.scripts["RotorOps.lua"]))
script = ""
script = ("--OPTIONS HERE!\n\n" +
"RotorOps.CTLD_crates = " + lb("crates") + "\n\n" +
"RotorOps.CTLD_sound_effects = true\n\n" +
"RotorOps.force_offroad = " + lb("force_offroad") + "\n\n" +
"RotorOps.voice_overs = " + lb("voiceovers") + "\n\n" +
"RotorOps.zone_status_display = " + lb("game_display") + "\n\n" +
"RotorOps.inf_spawn_messages = " + lb("inf_spawn_msgs") + "\n\n" +
"RotorOps.inf_spawns_per_zone = " + 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))))
self.m.triggerrules.triggers.append(trig)
#Add the second trigger
trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Zones")
trig.rules.append(dcs.condition.TimeAfter(2))
for s_zone in self.staging_zones:
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.stagingZone('" + s_zone + "')")))
for c_zone in self.conflict_zones:
zone_flag = self.conflict_zones[c_zone].flag
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.addZone('" + c_zone + "'," + str(zone_flag) + ")")))
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.setupConflict('" + str(game_flag) + "')")))
self.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)")))
self.m.triggerrules.triggers.append(trig)
#Add generic zone-based triggers
for index, zone_name in enumerate(self.conflict_zones):
z_active_trig = dcs.triggers.TriggerOnce(comment= zone_name + " Active")
z_active_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_active_trig.actions.append(dcs.action.DoScript(dcs.action.String("--Add any action you want here!")))
self.m.triggerrules.triggers.append(z_active_trig)
#Zone protection SAMs
if options["zone_protect_sams"]:
for index, zone_name in enumerate(self.conflict_zones):
z_sams_trig = dcs.triggers.TriggerOnce(comment="Deactivate " + zone_name + " SAMs")
z_sams_trig.actions.append(dcs.action.DoScript(dcs.action.String("Group.destroy(Group.getByName('" + zone_name + " Protection SAM'))")))
self.m.triggerrules.triggers.append(z_sams_trig)
#Zone FARPS always
if options["zone_farps"] == "farp_always" and not options["defending"]:
for index, zone_name in enumerate(self.conflict_zones):
if index > 0:
previous_zone = list(self.conflict_zones)[index - 1]
if not self.m.country("Combined Joint Task Forces Blue").find_group(previous_zone + " FARP Static"):
continue
z_farps_trig = dcs.triggers.TriggerOnce(comment="Activate " + previous_zone + " FARP")
z_farps_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_farps_trig.actions.append(dcs.action.ActivateGroup(self.m.country("Combined Joint Task Forces Blue").find_group(previous_zone + " FARP Static").id))
#z_farps_trig.actions.append(dcs.action.SoundToAll(str(self.res_map['forward_base_established.ogg'])))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"RotorOps.farpEstablished(" + str(index) + ")")))
self.m.triggerrules.triggers.append(z_farps_trig)
#Zone FARPS conditional on staged units remaining
if options["zone_farps"] == "farp_gunits" and not options["defending"]:
for index, zone_name in enumerate(self.conflict_zones):
if index > 0:
previous_zone = list(self.conflict_zones)[index - 1]
if not self.m.country("Combined Joint Task Forces Blue").find_group(previous_zone + " FARP Static"):
continue
z_farps_trig = dcs.triggers.TriggerOnce(comment= "Activate " + previous_zone + " FARP")
z_farps_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_farps_trig.rules.append(dcs.condition.FlagIsMore(111, 20))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String("--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(self.m.country("Combined Joint Task Forces Blue").find_group(previous_zone + " FARP Static").id))
#z_farps_trig.actions.append(dcs.action.SoundToAll(str(self.res_map['forward_base_established.ogg'])))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"RotorOps.farpEstablished(" + str(index) + ")")))
self.m.triggerrules.triggers.append(z_farps_trig)
def importObjects(self):
os.chdir(directories.imports)
logger.info("Looking for import .miz files in '" + os.getcwd())
for side in "red", "blue", "neutrals":
coalition = self.m.coalition.get(side)
for country_name in coalition.countries:
for group in self.m.country(country_name).static_group:
prefix = "IMPORT-"
if group.name.find(prefix) == 0:
if group.units[0].name.find('IMPORT-') == 0:
logger.error(
group.units[0].name + " IMPORT group's unit name cannot start with 'IMPORT'. Check the scenario template.")
raise Exception("Scenario file error: " + group.units[0].name + " IMPORT group's unit name cannot start with 'IMPORT'")
# trim the groupname to our filename convention
filename = group.name.removeprefix(prefix)
i = filename.find('-')
if i > 8:
filename = filename[0:i]
print(filename)
#Add attack helos triggers
for index in range(options["e_attack_helos"]):
random_zone_obj = random.choice(list(self.conflict_zones.items()))
zone = random_zone_obj[1]
z_weak_trig = dcs.triggers.TriggerOnce(comment=zone.name + " Attack Helo")
z_weak_trig.rules.append(dcs.condition.FlagIsMore(zone.flag, 1))
z_weak_trig.rules.append(dcs.condition.FlagIsLess(zone.flag, random.randrange(20, 90)))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag " + str(zone.flag) + " value represents the percentage of defending ground units remaining in zone. ")))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.spawnAttackHelos()")))
self.m.triggerrules.triggers.append(z_weak_trig)
#Add attack plane triggers
for index in range(options["e_attack_planes"]):
random_zone_obj = random.choice(list(self.conflict_zones.items()))
zone = random_zone_obj[1]
z_weak_trig = dcs.triggers.TriggerOnce(comment=zone.name + " Attack Plane")
z_weak_trig.rules.append(dcs.condition.FlagIsMore(zone.flag, 1))
z_weak_trig.rules.append(dcs.condition.FlagIsLess(zone.flag, random.randrange(20, 90)))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag " + str(zone.flag) + " value represents the percentage of defending ground units remaining in zone. ")))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.spawnAttackPlanes()")))
self.m.triggerrules.triggers.append(z_weak_trig)
#Add transport helos triggers
for index in range(options["e_transport_helos"]):
random_zone_index = random.randrange(1, len(self.conflict_zones))
random_zone_obj = list(self.conflict_zones.items())[random_zone_index]
zone = random_zone_obj[1]
z_weak_trig = dcs.triggers.TriggerOnce(comment=zone.name + " Transport Helo")
z_weak_trig.rules.append(dcs.condition.FlagEquals(game_flag, random_zone_index + 1))
z_weak_trig.rules.append(dcs.condition.FlagIsLess(zone.flag, random.randrange(20, 100)))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"---Flag " + str(game_flag) + " value represents the index of the active zone. ")))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag " + str(zone.flag) + " value represents the percentage of defending ground units remaining in zone. ")))
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.spawnTranspHelos(8," + str(options["transport_drop_qty"]) + ")")))
self.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")))
self.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")))
self.m.triggerrules.triggers.append(trig)
filename = filename + ".miz"
i = ImportObjects(filename)
i.anchorByGroupName("ANCHOR")
new_statics, new_vehicles, new_helicopters = i.copyAll(self.m, country_name, group.units[0].name, group.units[0].position, group.units[0].heading)

View File

@ -2,7 +2,7 @@ import dcs
client_helos = [
dcs.helicopters.UH_1H,
dcs.helicopters.Mi_8MT,
dcs.helicopters.AH_64D_BLK_II,
dcs.helicopters.Mi_24P,
dcs.helicopters.Ka_50,
]

View File

@ -1,5 +1,6 @@
import math
import dcs
from MissionGenerator import logger
def getDistance(point1=dcs.Point, point2=dcs.Point):
@ -15,3 +16,167 @@ def getDistance(point1=dcs.Point, point2=dcs.Point):
def convertMeterToNM(meters=int):
nm = meters / 1852
return nm
#
#
# class ImportObjects:
#
# def __init__(self, mizfile, source_point=None, source_heading=0):
# self.pad_unit = None
# logger.info("Importing objects from " + mizfile)
# self.source_mission = dcs.mission.Mission()
# self.source_mission.load_file(mizfile)
# self.source_heading = source_heading
# if source_point:
# self.source_point = source_point
# else:
# self.source_point = dcs.Point(self.source_mission.terrain.bullseye_blue["x"], self.source_mission.terrain.bullseye_blue["y"])
#
#
# def anchorByGroupName(self, group_name):
# group = self.source_mission.find_group(group_name)
# if group:
# self.source_point = group.units[0].position
# self.source_heading = group.units[0].heading
# else:
# logger.warning("Unable to find group for anchor.")
#
#
# def copyTo(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
# logger.info("Copying objects as " + dest_name)
#
# if not dest_point:
# dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
#
# for side in "red", "blue", "neutrals":
# 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,
# coalition.countries[country_name].ship_group]
#
#
#
# for index, group_type in enumerate(group_types):
# for group in group_type:
# self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
#
# # add the country to the destination mission if it doesn't exist already
# # if not mission.country(country_name):
# # print(country_name + " not found in destination mission")
# # for index, c in enumerate(dcs.countries.country_dict):
# # if dcs.countries.country_dict[c].name == country_name:
# #
# # mission.coalition.get(side).add_country(dcs.countries.country_dict[c]())
# # print(country_name + " added to " + side)
#
#
#
#
# if index == 0: # Statics
# type_name = group.units[0].type
# type_maps = [dcs.statics.cargo_map, dcs.statics.warehouse_map, dcs.statics.groundobject_map, dcs.statics.fortification_map]
# classed = False
# for type_map in type_maps:
# if type_name in type_map:
# classed = True
# unit_type = type_map[type_name]
# ng = mission.static_group(mission.country(dest_country_name),
# group.name,
# unit_type,
# group.units[0].position,
# group.units[0].heading,
# hidden=False)
#
#
#
# if not classed:
# print("No pydcs class for " + type_name)
#
#
# class temp(dcs.unittype.StaticType):
# id = group.units[0].type
# name = group.units[0].name
# shape_name = group.units[0].shape_name
# rate = group.units[0].rate
#
#
# ng = mission.static_group(mission.country(dest_country_name),
# group.name,
# temp,
# group.units[0].position,
# group.units[0].heading,
# hidden=False)
#
# if ng.units[0].type == "Invisible FARP":
# self.pad_unit = ng
#
# elif index == 1: # Vehicles
#
# for i, unit in enumerate(group.units):
# if i == 0:
# ng = mission.vehicle_group(mission.country(dest_country_name),
# group.name,
# dcs.vehicles.vehicle_map[group.units[0].type],
# group.units[0].position,
# group.units[0].heading)
#
#
# else:
#
# u = mission.vehicle(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)
#
# mission.country(dest_country_name).add_vehicle_group(ng)
#
#
# elif index == 2: # Helicopters
# if self.pad_unit:
# if group.units[0].skill == dcs.unit.Skill.Client or group.units[0].skill == dcs.unit.Skill.Player:
#
# # we'll create a new FARP for each helicopter. we've tried adding the flight group to an existing FARP, but they stack on top of each other
# # 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(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"
# 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
# else:
# logger.warn("No pad unit (ie FARP, carrier) found, so can't add helicopters.")
#
# elif index == 3:
# #mission.country(country).add_plane_group(group)
# print("not yet avail")
# elif index == 4:
# #mission.country(country).add_ship_group(group)
# print("not yet avail")
#
#
# @staticmethod
# def groupToPoint(group, src_point, dest_point, src_heading=0, dest_heading=0):
# for unit in group.units:
# heading_to_unit = dcs.mapping.heading_between_points(src_point.x, src_point.y, unit.position.x,
# unit.position.y)
# new_heading_to_unit = dest_heading + heading_to_unit
# 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

View File

@ -39,3 +39,8 @@ Tips:
-In "Defense" or with "Swap sides" option, USA and Russia ships, helicopters, planes, and ground units will swap countries. Static objects may not. Test it out.
-Turn off or limit civilian road traffic.
-Pay attention to rivers and bridges, as a far away bridge crossing may break routing if it's the only way across. See the testing notes above.
v0.6:
You can now control the FARP spawning location and heading by adding a static object (such as a mark flag) with group name 'ALPHA' etc. Same for staging area logistics site..but the group name should be 'STAGING'. Change the object heading to better align with roads or map objects. The flags for these must be CJTFB country.
You can dynamically insert complex arangements of objects such as large bases with multiplayer spawns. See the 'Imports' folder for more details.

View File

@ -0,0 +1,61 @@
#windowFrame {
border-radius: 5px 5px 5px 5px;
background-color: palette(Window);
}
#titleBar {
border: 0px none palette(base);
border-top-left-radius: 5px;
border-top-right-radius: 5px;
background-color: palette(Window);
height: 24px;
}
#btnClose, #btnRestore, #btnMaximize, #btnMinimize {
min-width: 14px;
min-height: 14px;
max-width: 14px;
max-height: 14px;
border-radius: 7px;
margin: 4px;
}
#btnRestore, #btnMaximize {
background-color: hsv(123, 204, 198);
}
#btnRestore::hover, #btnMaximize::hover {
background-color: hsv(123, 204, 148);
}
#btnRestore::pressed, #btnMaximize::pressed {
background-color: hsv(123, 204, 98);
}
#btnMinimize {
background-color: hsv(38, 218, 253);
}
#btnMinimize::hover {
background-color: hsv(38, 218, 203);
}
#btnMinimize::pressed {
background-color: hsv(38, 218, 153);
}
#btnClose {
background-color: hsv(0, 182, 252);
}
#btnClose::hover {
background-color: hsv(0, 182, 202);
}
#btnClose::pressed {
background-color: hsv(0, 182, 152);
}
#btnClose::disabled, #btnRestore::disabled, #btnMaximize::disabled, #btnMinimize::disabled {
background-color: palette(midlight);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

148
Generator/assets/style.qss Normal file
View File

@ -0,0 +1,148 @@
/*
* QGroupBox
*/
QGroupBox {
background-color: palette(alternate-base);
border: 1px solid palette(midlight);
margin-top: 25px;
}
QGroupBox::title {
background-color: transparent;
}
/*
* QToolBar
*/
QToolBar {
border: none;
}
/*
* QTabBar
*/
QTabBar{
background-color: transparent;
}
QTabBar::tab{
padding: 4px 6px;
background-color: transparent;
border-bottom: 2px solid transparent;
}
QTabBar::tab:selected, QTabBar::tab:hover {
color: palette(text);
border-bottom: 2px solid palette(highlight);
}
QTabBar::tab:selected:disabled {
border-bottom: 2px solid palette(light);
}
/*
* QScrollBar
*/
QScrollBar:vertical {
background: palette(base);
border-top-right-radius: 2px;
border-bottom-right-radius: 2px;
width: 16px;
margin: 0px;
}
QScrollBar::handle:vertical {
background-color: palette(midlight);
border-radius: 2px;
min-height: 20px;
margin: 2px 4px 2px 4px;
}
QScrollBar::handle:vertical:hover, QScrollBar::handle:horizontal:hover, QScrollBar::handle:vertical:pressed, QScrollBar::handle:horizontal:pressed {
background-color:palette(highlight);
}
QScrollBar::add-line:vertical {
background: none;
height: 0px;
subcontrol-position: right;
subcontrol-origin: margin;
}
QScrollBar::sub-line:vertical {
background: none;
height: 0px;
subcontrol-position: left;
subcontrol-origin: margin;
}
QScrollBar:horizontal{
background: palette(base);
height: 16px;
margin: 0px;
}
QScrollBar::handle:horizontal {
background-color: palette(midlight);
border-radius: 2px;
min-width: 20px;
margin: 4px 2px 4px 2px;
}
QScrollBar::add-line:horizontal {
background: none;
width: 0px;
subcontrol-position: bottom;
subcontrol-origin: margin;
}
QScrollBar::sub-line:horizontal {
background: none;
width: 0px;
subcontrol-position: top;
subcontrol-origin: margin;
}
/*
* QScrollArea
*/
QScrollArea {
border-style: none;
}
QScrollArea > QWidget > QWidget {
background-color: palette(alternate-base);
}
/*
* QSlider
*/
QSlider::handle:horizontal {
border-radius: 5px;
background-color: palette(light);
max-height: 20px;
}
QSlider::add-page:horizontal {
background: palette(base);
}
QSlider::sub-page:horizontal {
background: palette(highlight);
}
QSlider::sub-page:horizontal:disabled {
background-color: palette(light);
}
QTableView {
background-color: palette(link-visited);
alternate-background-color: palette(midlight);
}

Binary file not shown.

Binary file not shown.

View File

@ -1,3 +1,5 @@
![alt text](https://github.com/spencershepard/RotorOps/blob/main/Generator/assets/briefing1.png?raw=true)
# What is RotorOps?
RotorOps is a mission generator and gameplay script for DCS: World. At its heart is a game type called Conflict, which requires helicopter operations to win battles on the ground. This is a territory-capture game that promotes focus on individual 'conflict zones'.
@ -5,6 +7,7 @@ At the core of the RotorOps script are AI enhancements that provide a dynamic gr
![alt text](https://github.com/spencershepard/RotorOps/blob/main/documentation/images/rotorops%20ss%200_3.PNG?raw=true)
# Key Features:
- Unique helicopter-focused gameplay.
@ -58,26 +61,21 @@ Easily add your own templates for friendly/enemy ground units directly in the DC
Create your own scenarios for the RotorOps mission generator, using the DCS mission editor.
***
### Developers
We welcome contributors to this new project! Please get in touch on Discord with new ideas or pickup/create an issue in this repo.
### RotorOps Mission Creator Guide:
For more detailed information on how the script works, see this wiki:
https://github.com/spencershepard/RotorOps/wiki/RotorOps:-Mission-Creator-Guide
***
### Get in touch!
### Thanks to
https://discord.gg/HFqjrZV9xD
### Support Development
https://www.patreon.com/spencershepard
### Developers
We welcome contributors to this new project! Please get in touch on Discord with new ideas or pickup/create an issue in this repo.
***
### Much thanks to
RotorOps uses MIST and integrates CTLD:
https://github.com/mrSkortch/MissionScriptingTools
@ -87,3 +85,17 @@ https://github.com/ciribob/DCS-CTLD
The mission generator would not be possible without PyDCS:
https://github.com/pydcs/dcs
### Thanks to contributors
Shagrat: For amazing templates and testing for our FARPs, FOBs, and other mission assets.
Mr. Nobody: For awesome scenario and forces templates and helping to indroduce the DCS world to RotorOps.
***
# Join our Discord!
Chat about anything RotorOps or join up to fly!
https://discord.gg/HFqjrZV9xD

View File

@ -1,5 +1,5 @@
RotorOps = {}
RotorOps.version = "1.2.6"
RotorOps.version = "1.2.7"
local debug = true
@ -345,6 +345,7 @@ end
function RotorOps.isUnitInZone(unit, zone_name)
local zone = trigger.misc.getZone(zone_name)
local distance = getDistance(unit:getPoint(), zone.point)
--local distance = mist.utils.get2DDist(unit:getPoint(), zone.point)
if distance <= zone.radius then
return true
else
@ -746,11 +747,25 @@ function RotorOps.aiExecute(vars)
-- if vars.zone then zone = vars.zone end
if Group.isExist(Group.getByName(group_name)) ~= true or #Group.getByName(group_name):getUnits() < 1 then
--error after Apache update
-- if Group.isExist(Group.getByName(group_name)) ~= true or #Group.getByName(group_name):getUnits() < 1 then
-- debugMsg(group_name.." no longer exists")
-- RotorOps.ai_tasks[group_name] = nil
-- return
-- end
if Group.getByName(group_name) then
if Group.isExist(Group.getByName(group_name)) ~= true or #Group.getByName(group_name):getUnits() < 1 then
debugMsg(group_name.." no longer exists")
RotorOps.ai_tasks[group_name] = nil
return
end
else
debugMsg(group_name.." no longer exists")
RotorOps.ai_tasks[group_name] = nil
return
end
end
local same_zone = false
if zone ~= nil then
@ -1497,3 +1512,46 @@ function RotorOps.spawnTranspHelos(troops, max_drops)
end
--- USEFUL PUBLIC 'LUA PREDICATE' FUNCTIONS FOR MISSION EDITOR TRIGGERS (don't forget that DCS lua predicate functions should 'return' these function calls)
--determine if any human players are above a defined ceiling above ground level. If 'above' parameter is false, function will return true if no players above ceiling
function RotorOps.predPlayerMaxAGL(max_agl, above)
local players_above_ceiling = 0
for uName, uData in pairs(mist.DBs.humansByName) do
local player_unit = Unit.getByName(uData.unitName)
if player_unit then
local player_pos = player_unit:getPosition().p
local terrain_height = land.getHeight({x = player_pos.x, y = player_pos.z})
local player_agl = player_pos.y - terrain_height
if player_agl > max_agl then
players_above_ceiling = players_above_ceiling + 1
end
end
end
if players_above_ceiling > 0 then
return above
else
return not above
end
end
--determine if any human players are in a zone
function RotorOps.predPlayerInZone(zone_name)
local players_in_zone = 0
for uName, uData in pairs(mist.DBs.humansByName) do
local player_unit = Unit.getByName(uData.unitName)
if player_unit and RotorOps.isUnitInZone(player_unit, zone_name) then
players_in_zone = players_in_zone + 1
end
end
if players_in_zone > 0 then
return true
else
return false
end
end

9084
mist_4_5_107_grimm.lua Normal file

File diff suppressed because it is too large Load Diff