Merge pull request #29 from spencershepard/feature/updater

Feature/updater
This commit is contained in:
spencershepard 2022-04-14 15:25:47 -07:00 committed by GitHub
commit fdef308b57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
87 changed files with 10954 additions and 697 deletions

4
.gitignore vendored
View File

@ -13,3 +13,7 @@ incoming templates/
Generator/utils/extract units/source.miz Generator/utils/extract units/source.miz
Generator/utils/extract units/units.txt Generator/utils/extract units/units.txt
generator.log generator.log
templates/Scenarios/user
templates/Scenarios/downloaded
config/user-data.yaml
*.exe

View File

@ -1,18 +0,0 @@
You can add your own unit templates in this directory and they will appear in the mission generator.
1) Create an empty mission on Caucasus
2) Add ground unit groups.
3) Save the mission in this directory.
Optional:
4) Add helicopters with "CAS" main task for attack helicopters.
5) Add helicopters with "Transport" main task for transport helicopters.
6) Add planes with "CAS" main task for attack planes.
7) Add planes with "CAP" main task for fighters.
8) Configure loadouts, liveries, and skill for aircraft.
Tips:
-Drop your templates in the RotorOps Discord if you'd like to have them added in a release for everyone.
-The mission generator will only extract blue ground units from the template when selected from the "Blue Forces" menu, and vice versa.
-Only unit types are used from ground units. Liveries or other attributes are able to be copied.
-For aircraft, group size is currently capped at 2 units per group to help prevent issues with parking. Only the first unit in the group is used as a source.

View File

@ -1,17 +0,0 @@
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'.

File diff suppressed because it is too large Load Diff

View File

@ -27,7 +27,7 @@ exe = EXE(pyz,
a.datas, a.datas,
[], [],
name='MissionGenerator', name='MissionGenerator',
icon='assets\\icon.ico', icon='..\\assets\\icon.ico',
debug=False, debug=False,
bootloader_ignore_signals=False, bootloader_ignore_signals=False,
strip=False, strip=False,

View File

@ -0,0 +1,118 @@
from MissionGenerator import directories
import os
import RotorOpsUtils
import dcs
import math
from os.path import exists
class Scenario:
def __init__(self, path, name):
self.path = path
self.name = name
self.description = ""
# self.image_path = None
self.map_name = None
self.config = None
self.downloadable = False
self.tags = []
self.rating = None
self.rating_qty = None
self.packageID = None
self.local_rating = None
def applyConfig(self, config):
self.config = config
if 'description' in config:
self.description = config["description"]
if 'name' in config:
self.name = config["name"]
if 'map' in config:
self.map_name = config["map"]
if 'tags' in config:
for tag in config['tags']:
self.tags.append(tag)
def evaluateMiz(self):
# check if we have the miz file
if exists(self.path):
self.exists = True
else:
self.exists = False
return None
source_mission = dcs.mission.Mission()
source_mission.load_file(self.path)
zones = source_mission.triggers.zones()
conflict_zones = 0
staging_zones = 0
conflict_zone_size_sum = 0
conflict_zone_distance_sum = 0
spawn_zones = 0
conflict_zone_positions = []
#friendly_airports = source_mission.getCoalitionAirports("blue")
#enemy_airports = source_mission.getCoalitionAirports("red")
friendly_airports = True
enemy_airports = True
for zone in zones:
if zone.name.rfind("STAGING") == 0:
staging_zones += 1
if zone.name == "ALPHA" or zone.name == "BRAVO" or zone.name == "CHARLIE" or zone.name == "DELTA":
conflict_zones += 1
conflict_zone_size_sum += zone.radius
conflict_zone_positions.append(zone.position)
if zone.name.rfind("_SPAWN") > 0:
spawn_zones += 1
if conflict_zones > 1:
for index, position in enumerate(conflict_zone_positions):
if index > 0:
conflict_zone_distance_sum += RotorOpsUtils.getDistance(conflict_zone_positions[index], conflict_zone_positions[index - 1])
def validateTemplate():
valid = True
if len(staging_zones) < 1:
valid = False
if len(conflict_zones) < 1:
valid = False
if not friendly_airports:
valid = False
if not enemy_airports:
valid = False
return valid
description = ""
if self.rating:
description = description + "Rated " + str(self.rating) + "/5 based on " + str(self.rating_qty) + " reviews!\n"
if self.config:
if 'name' in self.config and self.config["name"] is not None:
description = description + '<h4>' + self.config["name"] + '</h4>'
if 'description' in self.config and self.config["description"] is not None:
description = description + self.config["description"] + "\n\n"
if conflict_zones and staging_zones :
average_zone_size = conflict_zone_size_sum / conflict_zones
description = (
description +
"Map: " + source_mission.terrain.name + "\n" +
"Conflict Zones: " + str(conflict_zones) + "\n" +
"Staging Zones: " + str(staging_zones) + "\n" +
"Average Zone Size: " + str(math.floor(average_zone_size)) + "m \n" +
"Infantry Spawn Zones: " + str(spawn_zones) + "\n" +
"Approx Distance: " + str(math.floor(RotorOpsUtils.convertMeterToNM(conflict_zone_distance_sum))) + "nm \n"
#"Validity Check:" + str(validateTemplate())
+ "\n== BRIEFING ==\n\n"
+ source_mission.description_text()
)
if self.packageID:
description = description + "\n\nScenario module ID: " + self.packageID
self.description = description.replace("\n", "<br />")

View File

@ -30,70 +30,12 @@ class Ui_MainWindow(object):
MainWindow.setWindowIcon(icon) MainWindow.setWindowIcon(icon)
MainWindow.setWindowOpacity(4.0) MainWindow.setWindowOpacity(4.0)
MainWindow.setAutoFillBackground(False) MainWindow.setAutoFillBackground(False)
MainWindow.setStyleSheet("/*-----QScrollBar-----*/\n" MainWindow.setStyleSheet("")
"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 = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget") self.centralwidget.setObjectName("centralwidget")
self.logistics_crates_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.logistics_crates_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.logistics_crates_checkBox.setGeometry(QtCore.QRect(990, 211, 251, 28)) self.logistics_crates_checkBox.setGeometry(QtCore.QRect(990, 211, 251, 28))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.logistics_crates_checkBox.setFont(font) self.logistics_crates_checkBox.setFont(font)
@ -102,7 +44,6 @@ class Ui_MainWindow(object):
self.zone_sams_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.zone_sams_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.zone_sams_checkBox.setGeometry(QtCore.QRect(990, 320, 241, 28)) self.zone_sams_checkBox.setGeometry(QtCore.QRect(990, 320, 241, 28))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.zone_sams_checkBox.setFont(font) self.zone_sams_checkBox.setFont(font)
@ -110,15 +51,13 @@ class Ui_MainWindow(object):
self.red_forces_label = QtWidgets.QLabel(self.centralwidget) self.red_forces_label = QtWidgets.QLabel(self.centralwidget)
self.red_forces_label.setGeometry(QtCore.QRect(470, 80, 171, 27)) self.red_forces_label.setGeometry(QtCore.QRect(470, 80, 171, 27))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.red_forces_label.setFont(font) self.red_forces_label.setFont(font)
self.red_forces_label.setObjectName("red_forces_label") self.red_forces_label.setObjectName("red_forces_label")
self.scenario_comboBox = QtWidgets.QComboBox(self.centralwidget) self.scenario_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.scenario_comboBox.setGeometry(QtCore.QRect(30, 20, 371, 29)) self.scenario_comboBox.setGeometry(QtCore.QRect(40, 10, 351, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(8) font.setPointSize(8)
font.setBold(True) font.setBold(True)
self.scenario_comboBox.setFont(font) self.scenario_comboBox.setFont(font)
@ -129,9 +68,8 @@ class Ui_MainWindow(object):
self.scenario_comboBox.setFrame(True) self.scenario_comboBox.setFrame(True)
self.scenario_comboBox.setObjectName("scenario_comboBox") self.scenario_comboBox.setObjectName("scenario_comboBox")
self.description_textBrowser = QtWidgets.QTextBrowser(self.centralwidget) self.description_textBrowser = QtWidgets.QTextBrowser(self.centralwidget)
self.description_textBrowser.setGeometry(QtCore.QRect(40, 410, 361, 251)) self.description_textBrowser.setGeometry(QtCore.QRect(30, 390, 371, 211))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
self.description_textBrowser.setFont(font) self.description_textBrowser.setFont(font)
self.description_textBrowser.setStyleSheet("padding: 5px;") self.description_textBrowser.setStyleSheet("padding: 5px;")
@ -143,7 +81,6 @@ class Ui_MainWindow(object):
self.defense_checkBox.setEnabled(True) self.defense_checkBox.setEnabled(True)
self.defense_checkBox.setGeometry(QtCore.QRect(470, 120, 156, 28)) self.defense_checkBox.setGeometry(QtCore.QRect(470, 120, 156, 28))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.defense_checkBox.setFont(font) self.defense_checkBox.setFont(font)
@ -167,7 +104,6 @@ class Ui_MainWindow(object):
sizePolicy.setHeightForWidth(self.redforces_comboBox.sizePolicy().hasHeightForWidth()) sizePolicy.setHeightForWidth(self.redforces_comboBox.sizePolicy().hasHeightForWidth())
self.redforces_comboBox.setSizePolicy(sizePolicy) self.redforces_comboBox.setSizePolicy(sizePolicy)
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
font.setBold(False) font.setBold(False)
self.redforces_comboBox.setFont(font) self.redforces_comboBox.setFont(font)
@ -175,7 +111,6 @@ class Ui_MainWindow(object):
self.scenario_label_8 = QtWidgets.QLabel(self.centralwidget) self.scenario_label_8 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_8.setGeometry(QtCore.QRect(570, 220, 271, 24)) self.scenario_label_8.setGeometry(QtCore.QRect(570, 220, 271, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.scenario_label_8.setFont(font) self.scenario_label_8.setFont(font)
@ -183,7 +118,6 @@ class Ui_MainWindow(object):
self.slot_template_comboBox = QtWidgets.QComboBox(self.centralwidget) self.slot_template_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.slot_template_comboBox.setGeometry(QtCore.QRect(960, 384, 271, 33)) self.slot_template_comboBox.setGeometry(QtCore.QRect(960, 384, 271, 33))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.slot_template_comboBox.setFont(font) self.slot_template_comboBox.setFont(font)
@ -198,7 +132,6 @@ class Ui_MainWindow(object):
self.blue_forces_label = QtWidgets.QLabel(self.centralwidget) self.blue_forces_label = QtWidgets.QLabel(self.centralwidget)
self.blue_forces_label.setGeometry(QtCore.QRect(470, 30, 161, 27)) self.blue_forces_label.setGeometry(QtCore.QRect(470, 30, 161, 27))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.blue_forces_label.setFont(font) self.blue_forces_label.setFont(font)
@ -216,7 +149,6 @@ class Ui_MainWindow(object):
self.blueforces_comboBox = QtWidgets.QComboBox(self.centralwidget) self.blueforces_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.blueforces_comboBox.setGeometry(QtCore.QRect(660, 30, 391, 33)) self.blueforces_comboBox.setGeometry(QtCore.QRect(660, 30, 391, 33))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
font.setBold(False) font.setBold(False)
self.blueforces_comboBox.setFont(font) self.blueforces_comboBox.setFont(font)
@ -235,7 +167,6 @@ class Ui_MainWindow(object):
self.scenario_label_10 = QtWidgets.QLabel(self.centralwidget) self.scenario_label_10 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_10.setGeometry(QtCore.QRect(570, 260, 271, 24)) self.scenario_label_10.setGeometry(QtCore.QRect(570, 260, 271, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.scenario_label_10.setFont(font) self.scenario_label_10.setFont(font)
@ -290,7 +221,6 @@ class Ui_MainWindow(object):
self.scenario_label_7 = QtWidgets.QLabel(self.centralwidget) self.scenario_label_7 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_7.setGeometry(QtCore.QRect(570, 180, 271, 24)) self.scenario_label_7.setGeometry(QtCore.QRect(570, 180, 271, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.scenario_label_7.setFont(font) self.scenario_label_7.setFont(font)
@ -298,7 +228,6 @@ class Ui_MainWindow(object):
self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(840, 390, 111, 24)) self.label_2.setGeometry(QtCore.QRect(840, 390, 111, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.label_2.setFont(font) self.label_2.setFont(font)
@ -306,57 +235,42 @@ class Ui_MainWindow(object):
self.scenario_label_9 = QtWidgets.QLabel(self.centralwidget) self.scenario_label_9 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_9.setGeometry(QtCore.QRect(490, 450, 251, 23)) self.scenario_label_9.setGeometry(QtCore.QRect(490, 450, 251, 23))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
self.scenario_label_9.setFont(font) self.scenario_label_9.setFont(font)
self.scenario_label_9.setObjectName("scenario_label_9") self.scenario_label_9.setObjectName("scenario_label_9")
self.awacs_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.awacs_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.awacs_checkBox.setGeometry(QtCore.QRect(990, 246, 241, 28)) self.awacs_checkBox.setGeometry(QtCore.QRect(990, 246, 241, 28))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.awacs_checkBox.setFont(font) self.awacs_checkBox.setFont(font)
self.awacs_checkBox.setStatusTip("")
self.awacs_checkBox.setChecked(True) self.awacs_checkBox.setChecked(True)
self.awacs_checkBox.setObjectName("awacs_checkBox") self.awacs_checkBox.setObjectName("awacs_checkBox")
self.tankers_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.tankers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.tankers_checkBox.setGeometry(QtCore.QRect(990, 282, 241, 28)) self.tankers_checkBox.setGeometry(QtCore.QRect(990, 282, 241, 28))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.tankers_checkBox.setFont(font) self.tankers_checkBox.setFont(font)
self.tankers_checkBox.setChecked(True) self.tankers_checkBox.setChecked(True)
self.tankers_checkBox.setObjectName("tankers_checkBox") 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.voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.voiceovers_checkBox.setGeometry(QtCore.QRect(960, 517, 171, 24)) self.voiceovers_checkBox.setGeometry(QtCore.QRect(960, 517, 171, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
self.voiceovers_checkBox.setFont(font) self.voiceovers_checkBox.setFont(font)
self.voiceovers_checkBox.setChecked(True) self.voiceovers_checkBox.setChecked(True)
self.voiceovers_checkBox.setObjectName("voiceovers_checkBox") self.voiceovers_checkBox.setObjectName("voiceovers_checkBox")
self.smoke_pickup_zone_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.smoke_pickup_zone_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.smoke_pickup_zone_checkBox.setGeometry(QtCore.QRect(960, 424, 271, 24)) self.smoke_pickup_zone_checkBox.setGeometry(QtCore.QRect(960, 460, 271, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
self.smoke_pickup_zone_checkBox.setFont(font) self.smoke_pickup_zone_checkBox.setFont(font)
self.smoke_pickup_zone_checkBox.setChecked(False) self.smoke_pickup_zone_checkBox.setChecked(False)
self.smoke_pickup_zone_checkBox.setObjectName("smoke_pickup_zone_checkBox") self.smoke_pickup_zone_checkBox.setObjectName("smoke_pickup_zone_checkBox")
self.game_status_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.game_status_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.game_status_checkBox.setGeometry(QtCore.QRect(960, 486, 271, 24)) self.game_status_checkBox.setGeometry(QtCore.QRect(960, 490, 271, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
self.game_status_checkBox.setFont(font) self.game_status_checkBox.setFont(font)
self.game_status_checkBox.setChecked(True) self.game_status_checkBox.setChecked(True)
@ -365,7 +279,6 @@ class Ui_MainWindow(object):
self.label = QtWidgets.QLabel(self.centralwidget) self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(570, 380, 261, 23)) self.label.setGeometry(QtCore.QRect(570, 380, 261, 23))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.label.setFont(font) self.label.setFont(font)
@ -393,7 +306,6 @@ class Ui_MainWindow(object):
self.force_offroad_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.force_offroad_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.force_offroad_checkBox.setGeometry(QtCore.QRect(960, 548, 161, 24)) self.force_offroad_checkBox.setGeometry(QtCore.QRect(960, 548, 161, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
self.force_offroad_checkBox.setFont(font) self.force_offroad_checkBox.setFont(font)
self.force_offroad_checkBox.setChecked(False) self.force_offroad_checkBox.setChecked(False)
@ -402,7 +314,6 @@ class Ui_MainWindow(object):
self.label_3 = QtWidgets.QLabel(self.centralwidget) self.label_3 = QtWidgets.QLabel(self.centralwidget)
self.label_3.setGeometry(QtCore.QRect(570, 330, 281, 23)) self.label_3.setGeometry(QtCore.QRect(570, 330, 281, 23))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.label_3.setFont(font) self.label_3.setFont(font)
@ -410,31 +321,23 @@ class Ui_MainWindow(object):
self.apcs_spawn_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.apcs_spawn_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(990, 180, 251, 27)) self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(990, 180, 251, 27))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(10) font.setPointSize(10)
font.setBold(False) font.setBold(False)
self.apcs_spawn_checkBox.setFont(font) self.apcs_spawn_checkBox.setFont(font)
self.apcs_spawn_checkBox.setChecked(True) self.apcs_spawn_checkBox.setChecked(True)
self.apcs_spawn_checkBox.setObjectName("apcs_spawn_checkBox") self.apcs_spawn_checkBox.setObjectName("apcs_spawn_checkBox")
self.generateButton = QtWidgets.QPushButton(self.centralwidget) self.generateButton = QtWidgets.QPushButton(self.centralwidget)
self.generateButton.setEnabled(True)
self.generateButton.setGeometry(QtCore.QRect(710, 600, 231, 51)) self.generateButton.setGeometry(QtCore.QRect(710, 600, 231, 51))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(8) font.setPointSize(8)
font.setBold(True) font.setBold(True)
self.generateButton.setFont(font) self.generateButton.setFont(font)
self.generateButton.setStyleSheet("background-color: gray;\n" self.generateButton.setStyleSheet("")
"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.generateButton.setObjectName("generateButton")
self.farp_always = QtWidgets.QRadioButton(self.centralwidget) self.farp_always = QtWidgets.QRadioButton(self.centralwidget)
self.farp_always.setGeometry(QtCore.QRect(510, 480, 261, 24)) self.farp_always.setGeometry(QtCore.QRect(510, 480, 261, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
self.farp_always.setFont(font) self.farp_always.setFont(font)
self.farp_always.setObjectName("farp_always") self.farp_always.setObjectName("farp_always")
@ -444,7 +347,6 @@ class Ui_MainWindow(object):
self.farp_never = QtWidgets.QRadioButton(self.centralwidget) self.farp_never = QtWidgets.QRadioButton(self.centralwidget)
self.farp_never.setGeometry(QtCore.QRect(510, 540, 271, 24)) self.farp_never.setGeometry(QtCore.QRect(510, 540, 271, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
self.farp_never.setFont(font) self.farp_never.setFont(font)
self.farp_never.setObjectName("farp_never") self.farp_never.setObjectName("farp_never")
@ -452,7 +354,6 @@ class Ui_MainWindow(object):
self.farp_gunits = QtWidgets.QRadioButton(self.centralwidget) self.farp_gunits = QtWidgets.QRadioButton(self.centralwidget)
self.farp_gunits.setGeometry(QtCore.QRect(510, 509, 261, 24)) self.farp_gunits.setGeometry(QtCore.QRect(510, 509, 261, 24))
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
self.farp_gunits.setFont(font) self.farp_gunits.setFont(font)
self.farp_gunits.setChecked(True) self.farp_gunits.setChecked(True)
@ -460,7 +361,7 @@ class Ui_MainWindow(object):
self.farp_buttonGroup.addButton(self.farp_gunits) self.farp_buttonGroup.addButton(self.farp_gunits)
self.missionImage = QtWidgets.QLabel(self.centralwidget) self.missionImage = QtWidgets.QLabel(self.centralwidget)
self.missionImage.setEnabled(True) self.missionImage.setEnabled(True)
self.missionImage.setGeometry(QtCore.QRect(60, 80, 300, 300)) self.missionImage.setGeometry(QtCore.QRect(60, 60, 310, 310))
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0) sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0) sizePolicy.setVerticalStretch(0)
@ -470,39 +371,93 @@ class Ui_MainWindow(object):
self.missionImage.setMaximumSize(QtCore.QSize(16777215, 16777215)) self.missionImage.setMaximumSize(QtCore.QSize(16777215, 16777215))
self.missionImage.setStyleSheet("") self.missionImage.setStyleSheet("")
self.missionImage.setText("") self.missionImage.setText("")
self.missionImage.setPixmap(QtGui.QPixmap("assets/briefing1.png")) self.missionImage.setPixmap(QtGui.QPixmap("../assets/briefing1.png"))
self.missionImage.setScaledContents(True) self.missionImage.setScaledContents(True)
self.missionImage.setWordWrap(False) self.missionImage.setWordWrap(False)
self.missionImage.setObjectName("missionImage") self.missionImage.setObjectName("missionImage")
self.nextScenario_pushButton = QtWidgets.QPushButton(self.centralwidget) self.nextScenario_pushButton = QtWidgets.QPushButton(self.centralwidget)
self.nextScenario_pushButton.setGeometry(QtCore.QRect(370, 210, 31, 51)) self.nextScenario_pushButton.setGeometry(QtCore.QRect(350, 620, 41, 31))
self.nextScenario_pushButton.setObjectName("nextScenario_pushButton") self.nextScenario_pushButton.setObjectName("nextScenario_pushButton")
self.prevScenario_pushButton = QtWidgets.QPushButton(self.centralwidget) self.prevScenario_pushButton = QtWidgets.QPushButton(self.centralwidget)
self.prevScenario_pushButton.setGeometry(QtCore.QRect(20, 210, 31, 51)) self.prevScenario_pushButton.setGeometry(QtCore.QRect(40, 620, 41, 31))
self.prevScenario_pushButton.setObjectName("prevScenario_pushButton") self.prevScenario_pushButton.setObjectName("prevScenario_pushButton")
self.background_label = QtWidgets.QLabel(self.centralwidget) self.background_label = QtWidgets.QLabel(self.centralwidget)
self.background_label.setGeometry(QtCore.QRect(1020, 600, 241, 51)) self.background_label.setGeometry(QtCore.QRect(1020, 600, 241, 51))
self.background_label.setText("") self.background_label.setText("")
self.background_label.setPixmap(QtGui.QPixmap("assets/rotorops-dkgray.png")) self.background_label.setPixmap(QtGui.QPixmap("../assets/rotorops-dkgray.png"))
self.background_label.setScaledContents(True) self.background_label.setScaledContents(True)
self.background_label.setObjectName("background_label") self.background_label.setObjectName("background_label")
self.rateButton1 = QtWidgets.QPushButton(self.centralwidget)
self.rateButton1.setEnabled(True)
self.rateButton1.setGeometry(QtCore.QRect(120, 620, 31, 31))
font = QtGui.QFont()
font.setPointSize(8)
self.rateButton1.setFont(font)
self.rateButton1.setStyleSheet("border-image:url(\'../assets/star_full.png\');")
self.rateButton1.setText("")
self.rateButton1.setObjectName("rateButton1")
self.hotstart_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.hotstart_checkBox.setGeometry(QtCore.QRect(960, 430, 271, 24))
font = QtGui.QFont()
font.setPointSize(9)
self.hotstart_checkBox.setFont(font)
self.hotstart_checkBox.setChecked(False)
self.hotstart_checkBox.setTristate(False)
self.hotstart_checkBox.setObjectName("hotstart_checkBox")
self.rateButton2 = QtWidgets.QPushButton(self.centralwidget)
self.rateButton2.setEnabled(True)
self.rateButton2.setGeometry(QtCore.QRect(160, 620, 31, 31))
font = QtGui.QFont()
font.setPointSize(8)
self.rateButton2.setFont(font)
self.rateButton2.setStyleSheet("border-image:url(\'../assets/star_full.png\');")
self.rateButton2.setText("")
self.rateButton2.setObjectName("rateButton2")
self.rateButton3 = QtWidgets.QPushButton(self.centralwidget)
self.rateButton3.setEnabled(True)
self.rateButton3.setGeometry(QtCore.QRect(200, 620, 31, 31))
font = QtGui.QFont()
font.setPointSize(8)
self.rateButton3.setFont(font)
self.rateButton3.setStyleSheet("border-image:url(\'../assets/star_full.png\');")
self.rateButton3.setText("")
self.rateButton3.setObjectName("rateButton3")
self.rateButton4 = QtWidgets.QPushButton(self.centralwidget)
self.rateButton4.setEnabled(True)
self.rateButton4.setGeometry(QtCore.QRect(240, 620, 31, 31))
font = QtGui.QFont()
font.setPointSize(8)
self.rateButton4.setFont(font)
self.rateButton4.setStyleSheet("border-image:url(\'../assets/star_full.png\');")
self.rateButton4.setText("")
self.rateButton4.setObjectName("rateButton4")
self.rateButton5 = QtWidgets.QPushButton(self.centralwidget)
self.rateButton5.setEnabled(True)
self.rateButton5.setGeometry(QtCore.QRect(280, 620, 31, 31))
font = QtGui.QFont()
font.setPointSize(8)
self.rateButton5.setFont(font)
self.rateButton5.setStyleSheet("border-image:url(\'../assets/star_full.png\');")
self.rateButton5.setText("")
self.rateButton5.setObjectName("rateButton5")
MainWindow.setCentralWidget(self.centralwidget) MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1280, 26)) self.menubar.setGeometry(QtCore.QRect(0, 0, 1280, 29))
self.menubar.setObjectName("menubar") self.menubar.setObjectName("menubar")
self.menuMap = QtWidgets.QMenu(self.menubar) self.menuMap = QtWidgets.QMenu(self.menubar)
self.menuMap.setObjectName("menuMap") self.menuMap.setObjectName("menuMap")
self.menuGametype_Filter = QtWidgets.QMenu(self.menubar) self.menuFilter = QtWidgets.QMenu(self.menubar)
self.menuGametype_Filter.setObjectName("menuGametype_Filter") self.menuFilter.setObjectName("menuFilter")
self.menuPreferences = QtWidgets.QMenu(self.menubar)
self.menuPreferences.setObjectName("menuPreferences")
MainWindow.setMenuBar(self.menubar) MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar = QtWidgets.QStatusBar(MainWindow)
font = QtGui.QFont() font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(9) font.setPointSize(9)
font.setBold(False) font.setBold(False)
self.statusbar.setFont(font) self.statusbar.setFont(font)
self.statusbar.setAcceptDrops(False) self.statusbar.setAcceptDrops(False)
self.statusbar.setStyleSheet("color: rgb(255, 255, 255);") self.statusbar.setStyleSheet("")
self.statusbar.setObjectName("statusbar") self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar) MainWindow.setStatusBar(self.statusbar)
self.action_generateMission = QtWidgets.QAction(MainWindow) self.action_generateMission = QtWidgets.QAction(MainWindow)
@ -520,43 +475,90 @@ class Ui_MainWindow(object):
self.action_prevScenario = QtWidgets.QAction(MainWindow) self.action_prevScenario = QtWidgets.QAction(MainWindow)
self.action_prevScenario.setObjectName("action_prevScenario") self.action_prevScenario.setObjectName("action_prevScenario")
self.actionCaucasus = QtWidgets.QAction(MainWindow) self.actionCaucasus = QtWidgets.QAction(MainWindow)
self.actionCaucasus.setCheckable(True)
self.actionCaucasus.setChecked(True)
self.actionCaucasus.setObjectName("actionCaucasus") self.actionCaucasus.setObjectName("actionCaucasus")
self.actionPersian_Gulf = QtWidgets.QAction(MainWindow) self.actionPersian_Gulf = QtWidgets.QAction(MainWindow)
self.actionPersian_Gulf.setCheckable(True)
self.actionPersian_Gulf.setChecked(True)
self.actionPersian_Gulf.setObjectName("actionPersian_Gulf") self.actionPersian_Gulf.setObjectName("actionPersian_Gulf")
self.actionMarianas = QtWidgets.QAction(MainWindow) self.actionMarianas = QtWidgets.QAction(MainWindow)
self.actionMarianas.setCheckable(True)
self.actionMarianas.setChecked(True)
self.actionMarianas.setObjectName("actionMarianas") self.actionMarianas.setObjectName("actionMarianas")
self.actionNevada = QtWidgets.QAction(MainWindow) self.actionNevada = QtWidgets.QAction(MainWindow)
self.actionNevada.setCheckable(True)
self.actionNevada.setChecked(True)
self.actionNevada.setObjectName("actionNevada") self.actionNevada.setObjectName("actionNevada")
self.actionSyria = QtWidgets.QAction(MainWindow) self.actionSyria = QtWidgets.QAction(MainWindow)
self.actionSyria.setCheckable(True)
self.actionSyria.setChecked(True)
self.actionSyria.setObjectName("actionSyria") 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 = QtWidgets.QAction(MainWindow)
self.actionMultiplayer.setCheckable(False) self.actionMultiplayer.setCheckable(True)
self.actionMultiplayer.setChecked(True)
self.actionMultiplayer.setObjectName("actionMultiplayer") self.actionMultiplayer.setObjectName("actionMultiplayer")
self.actionAll_2 = QtWidgets.QAction(MainWindow) self.actionSave_Directory = QtWidgets.QAction(MainWindow)
self.actionAll_2.setCheckable(True) self.actionSave_Directory.setObjectName("actionSave_Directory")
self.actionAll_2.setChecked(True) self.action_slotChanged = QtWidgets.QAction(MainWindow)
self.actionAll_2.setObjectName("actionAll_2") self.action_slotChanged.setObjectName("action_slotChanged")
self.menuMap.addAction(self.actionAll_2) self.actionIncluded = QtWidgets.QAction(MainWindow)
self.actionIncluded.setCheckable(True)
self.actionIncluded.setChecked(True)
self.actionIncluded.setObjectName("actionIncluded")
self.actionUser = QtWidgets.QAction(MainWindow)
self.actionUser.setObjectName("actionUser")
self.actionDownloaded = QtWidgets.QAction(MainWindow)
self.actionDownloaded.setObjectName("actionDownloaded")
self.action_downloadButton = QtWidgets.QAction(MainWindow)
self.action_downloadButton.setObjectName("action_downloadButton")
self.action_rateButton1 = QtWidgets.QAction(MainWindow)
self.action_rateButton1.setObjectName("action_rateButton1")
self.actionSingle_Player = QtWidgets.QAction(MainWindow)
self.actionSingle_Player.setCheckable(True)
self.actionSingle_Player.setChecked(True)
self.actionSingle_Player.setObjectName("actionSingle_Player")
self.actionCo_Op = QtWidgets.QAction(MainWindow)
self.actionCo_Op.setCheckable(True)
self.actionCo_Op.setChecked(True)
self.actionCo_Op.setObjectName("actionCo_Op")
self.actionMapMenu = QtWidgets.QAction(MainWindow)
self.actionMapMenu.setObjectName("actionMapMenu")
self.actionFilterMenu = QtWidgets.QAction(MainWindow)
self.actionFilterMenu.setObjectName("actionFilterMenu")
self.action_rateButton2 = QtWidgets.QAction(MainWindow)
self.action_rateButton2.setObjectName("action_rateButton2")
self.action_rateButton3 = QtWidgets.QAction(MainWindow)
self.action_rateButton3.setObjectName("action_rateButton3")
self.action_rateButton4 = QtWidgets.QAction(MainWindow)
self.action_rateButton4.setObjectName("action_rateButton4")
self.action_rateButton5 = QtWidgets.QAction(MainWindow)
self.action_rateButton5.setObjectName("action_rateButton5")
self.menuMap.addAction(self.actionCaucasus) self.menuMap.addAction(self.actionCaucasus)
self.menuMap.addAction(self.actionPersian_Gulf) self.menuMap.addAction(self.actionPersian_Gulf)
self.menuMap.addAction(self.actionMarianas) self.menuMap.addAction(self.actionMarianas)
self.menuMap.addAction(self.actionNevada) self.menuMap.addAction(self.actionNevada)
self.menuMap.addAction(self.actionSyria) self.menuMap.addAction(self.actionSyria)
self.menuGametype_Filter.addAction(self.actionAll) self.menuFilter.addAction(self.actionMultiplayer)
self.menuGametype_Filter.addAction(self.actionMultiplayer) self.menuFilter.addAction(self.actionSingle_Player)
self.menuFilter.addAction(self.actionCo_Op)
self.menuPreferences.addAction(self.actionSave_Directory)
self.menubar.addAction(self.menuMap.menuAction()) self.menubar.addAction(self.menuMap.menuAction())
self.menubar.addAction(self.menuGametype_Filter.menuAction()) self.menubar.addAction(self.menuFilter.menuAction())
self.menubar.addAction(self.menuPreferences.menuAction())
self.retranslateUi(MainWindow) self.retranslateUi(MainWindow)
self.generateButton.clicked.connect(self.action_generateMission.trigger) 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) self.prevScenario_pushButton.clicked.connect(self.action_prevScenario.trigger)
self.defense_checkBox.clicked.connect(self.action_defensiveModeChanged.trigger)
self.slot_template_comboBox.activated['int'].connect(self.action_slotChanged.trigger)
self.scenario_comboBox.currentIndexChanged['int'].connect(self.action_scenarioSelected.trigger)
self.nextScenario_pushButton.clicked.connect(self.action_nextScenario.trigger)
self.rateButton1.clicked.connect(self.action_rateButton1.trigger)
self.rateButton2.clicked.connect(self.action_rateButton2.trigger)
self.rateButton3.clicked.connect(self.action_rateButton3.trigger)
self.rateButton4.clicked.connect(self.action_rateButton4.trigger)
self.rateButton5.clicked.connect(self.action_rateButton5.trigger)
QtCore.QMetaObject.connectSlotsByName(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow): def retranslateUi(self, MainWindow):
@ -571,17 +573,17 @@ class Ui_MainWindow(object):
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" 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" "<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n" "p, li { white-space: pre-wrap; }\n"
"</style></head><body style=\" font-family:\'Arial\'; font-size:9pt; font-weight:400; font-style:normal;\">\n" "</style></head><body style=\" font-family:\'Segoe UI\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
"<p align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:10pt;\">Provide close air support for our convoys as we take back Las Vegas from the enemy!</span></p></body></html>")) "<p align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:10pt;\">Provide close air support for our convoys as we take back Las Vegas from the enemy!</span></p></body></html>"))
self.defense_checkBox.setText(_translate("MainWindow", "Blue on Defense")) self.defense_checkBox.setText(_translate("MainWindow", "Blue on Defense"))
self.redqty_spinBox.setStatusTip(_translate("MainWindow", "How many groups should we generate?")) self.redqty_spinBox.setStatusTip(_translate("MainWindow", "Red vehicle groups per staging or conflict zone."))
self.redforces_comboBox.setStatusTip(_translate("MainWindow", "Tip: You can create your own custom ground forces groups to be automatically generated.")) 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.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack plane group spawns."))
self.scenario_label_8.setText(_translate("MainWindow", "Enemy Attack Planes")) self.scenario_label_8.setText(_translate("MainWindow", "Enemy Attack Planes"))
self.slot_template_comboBox.setStatusTip(_translate("MainWindow", "Default player/client spawn locations at a friendly airport.")) 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.scenario_label_5.setText(_translate("MainWindow", "Groups Per Zone"))
self.blue_forces_label.setText(_translate("MainWindow", "Blue Forces:")) self.blue_forces_label.setText(_translate("MainWindow", "Blue Forces:"))
self.blueqty_spinBox.setStatusTip(_translate("MainWindow", "How many groups should we generate?")) self.blueqty_spinBox.setStatusTip(_translate("MainWindow", "Blue vehicle groups per staging or conflict zone."))
self.blueforces_comboBox.setStatusTip(_translate("MainWindow", "Tip: You can create your own custom ground forces groups to be automatically generated.")) 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.scenario_label_4.setText(_translate("MainWindow", "Groups Per Zone"))
self.version_label.setText(_translate("MainWindow", "Version string")) self.version_label.setText(_translate("MainWindow", "Version string"))
@ -594,10 +596,10 @@ class Ui_MainWindow(object):
self.scenario_label_7.setText(_translate("MainWindow", "Enemy Attack Helicopters")) self.scenario_label_7.setText(_translate("MainWindow", "Enemy Attack Helicopters"))
self.label_2.setText(_translate("MainWindow", "Player Slots:")) self.label_2.setText(_translate("MainWindow", "Player Slots:"))
self.scenario_label_9.setText(_translate("MainWindow", "Zone FARP Conditions:")) self.scenario_label_9.setText(_translate("MainWindow", "Zone FARP Conditions:"))
self.awacs_checkBox.setText(_translate("MainWindow", "Friendly AWACS")) self.awacs_checkBox.setStatusTip(_translate("MainWindow", "Spawn a friendly AWACS with fighter escorts."))
self.awacs_checkBox.setText(_translate("MainWindow", "Friendly AWACS with escort"))
self.tankers_checkBox.setStatusTip(_translate("MainWindow", "Spawn friendly tankers for both boom and basket refueling."))
self.tankers_checkBox.setText(_translate("MainWindow", "Friendly Tankers")) 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.setStatusTip(_translate("MainWindow", "Voiceovers from the ground commander. Helps keep focus on the active zone."))
self.voiceovers_checkBox.setText(_translate("MainWindow", "Voiceovers")) self.voiceovers_checkBox.setText(_translate("MainWindow", "Voiceovers"))
self.smoke_pickup_zone_checkBox.setStatusTip(_translate("MainWindow", "Infinite troop pickup zones will be marked with blue smoke.")) self.smoke_pickup_zone_checkBox.setStatusTip(_translate("MainWindow", "Infinite troop pickup zones will be marked with blue smoke."))
@ -613,7 +615,8 @@ class Ui_MainWindow(object):
self.label_3.setStatusTip(_translate("MainWindow", "The number of troop drops per transport helicopter flight.")) 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.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.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.apcs_spawn_checkBox.setText(_translate("MainWindow", "Dynamic Troops"))
self.generateButton.setStatusTip(_translate("MainWindow", "Click to generate mission."))
self.generateButton.setText(_translate("MainWindow", "GENERATE MISSION")) self.generateButton.setText(_translate("MainWindow", "GENERATE MISSION"))
self.farp_always.setStatusTip(_translate("MainWindow", "Always spawn a FARP in defeated conflict zones.")) self.farp_always.setStatusTip(_translate("MainWindow", "Always spawn a FARP in defeated conflict zones."))
self.farp_always.setText(_translate("MainWindow", "Always")) self.farp_always.setText(_translate("MainWindow", "Always"))
@ -623,8 +626,16 @@ class Ui_MainWindow(object):
self.farp_gunits.setText(_translate("MainWindow", "20% Ground Units Remaining")) self.farp_gunits.setText(_translate("MainWindow", "20% Ground Units Remaining"))
self.nextScenario_pushButton.setText(_translate("MainWindow", ">")) self.nextScenario_pushButton.setText(_translate("MainWindow", ">"))
self.prevScenario_pushButton.setText(_translate("MainWindow", "<")) self.prevScenario_pushButton.setText(_translate("MainWindow", "<"))
self.menuMap.setTitle(_translate("MainWindow", "Map Filter")) self.rateButton1.setStatusTip(_translate("MainWindow", "Submit a review for this mission scenario."))
self.menuGametype_Filter.setTitle(_translate("MainWindow", "Gametype Filter")) self.hotstart_checkBox.setStatusTip(_translate("MainWindow", "Player helicopters start with engines running on the ground. No effect if player slots says \'Locked to scenario\'"))
self.hotstart_checkBox.setText(_translate("MainWindow", "Player Hotstart"))
self.rateButton2.setStatusTip(_translate("MainWindow", "Submit a review for this mission scenario."))
self.rateButton3.setStatusTip(_translate("MainWindow", "Submit a review for this mission scenario."))
self.rateButton4.setStatusTip(_translate("MainWindow", "Submit a review for this mission scenario."))
self.rateButton5.setStatusTip(_translate("MainWindow", "Submit a review for this mission scenario."))
self.menuMap.setTitle(_translate("MainWindow", "Map"))
self.menuFilter.setTitle(_translate("MainWindow", "Filter"))
self.menuPreferences.setTitle(_translate("MainWindow", "Preferences"))
self.action_generateMission.setText(_translate("MainWindow", "_generateMission")) self.action_generateMission.setText(_translate("MainWindow", "_generateMission"))
self.action_scenarioSelected.setText(_translate("MainWindow", "_scenarioSelected")) self.action_scenarioSelected.setText(_translate("MainWindow", "_scenarioSelected"))
self.action_blueforcesSelected.setText(_translate("MainWindow", "_blueforcesSelected")) self.action_blueforcesSelected.setText(_translate("MainWindow", "_blueforcesSelected"))
@ -637,9 +648,28 @@ class Ui_MainWindow(object):
self.actionMarianas.setText(_translate("MainWindow", "Marianas")) self.actionMarianas.setText(_translate("MainWindow", "Marianas"))
self.actionNevada.setText(_translate("MainWindow", "Nevada")) self.actionNevada.setText(_translate("MainWindow", "Nevada"))
self.actionSyria.setText(_translate("MainWindow", "Syria")) self.actionSyria.setText(_translate("MainWindow", "Syria"))
self.actionAll.setText(_translate("MainWindow", "All"))
self.actionMultiplayer.setText(_translate("MainWindow", "Multiplayer")) self.actionMultiplayer.setText(_translate("MainWindow", "Multiplayer"))
self.actionAll_2.setText(_translate("MainWindow", "All")) self.actionSave_Directory.setText(_translate("MainWindow", "Save Directory"))
self.action_slotChanged.setText(_translate("MainWindow", "_slotChanged"))
self.actionIncluded.setText(_translate("MainWindow", "Included"))
self.actionUser.setText(_translate("MainWindow", "User"))
self.actionDownloaded.setText(_translate("MainWindow", "Downloaded"))
self.action_downloadButton.setText(_translate("MainWindow", "_downloadButton"))
self.action_downloadButton.setToolTip(_translate("MainWindow", "_downloadButton"))
self.action_rateButton1.setText(_translate("MainWindow", "_rateButton1"))
self.action_rateButton1.setToolTip(_translate("MainWindow", "_rateButton1"))
self.actionSingle_Player.setText(_translate("MainWindow", "Single-Player"))
self.actionCo_Op.setText(_translate("MainWindow", "Co-Op"))
self.actionMapMenu.setText(_translate("MainWindow", "actionMapMenu"))
self.actionFilterMenu.setText(_translate("MainWindow", "FilterMenu"))
self.action_rateButton2.setText(_translate("MainWindow", "_rateButton2"))
self.action_rateButton2.setToolTip(_translate("MainWindow", "_rateButton2"))
self.action_rateButton3.setText(_translate("MainWindow", "_rateButton3"))
self.action_rateButton3.setToolTip(_translate("MainWindow", "_rateButton3"))
self.action_rateButton4.setText(_translate("MainWindow", "_rateButton4"))
self.action_rateButton4.setToolTip(_translate("MainWindow", "_rateButton4"))
self.action_rateButton5.setText(_translate("MainWindow", "_rateButton5"))
self.action_rateButton5.setToolTip(_translate("MainWindow", "_rateButton5"))
if __name__ == "__main__": if __name__ == "__main__":

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
from PyQt5.QtWidgets import QMessageBox
from MissionGenerator import directories, build, logger
import requests
import yaml
import os
modules_url = 'https://dcs-helicopters.com/user-files/modules/'
version_url = 'https://dcs-helicopters.com/app-updates/versions.yaml'
modules_map_url = 'https://dcs-helicopters.com/user-files/modules/modules.yaml'
def checkVersion(self):
try:
r = requests.get(version_url, allow_redirects=False, timeout=3)
v = yaml.safe_load(r.content)
print(v["build"])
avail_build = v["build"]
if avail_build > build:
msg = QMessageBox()
msg.setWindowTitle(v["title"])
msg.setText(v["description"])
x = msg.exec_()
except TimeoutError:
logger.error("Online version check failed: connection timed out.")
except ConnectionError:
logger.error("Online version check failed: connection error.")
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_()
# class Module:
#
# def __init__(self, remote_dir, local_dir):
# self.remote_dir = remote_dir
# self.local_dir = local_dir
#
# @classmethod
# def createFromFile(cls):

View File

@ -1 +0,0 @@
Your mission files will appear in this directory after using the mission generator!

View File

@ -5,11 +5,13 @@ jtf_red = "Combined Joint Task Forces Red"
jtf_blue = "Combined Joint Task Forces Blue" jtf_blue = "Combined Joint Task Forces Blue"
def triggerSetup(rops, options): def triggerSetup(rops, options):
# get the boolean value from ui option and convert to lua string # get the boolean value from ui option and convert to lua string
def lb(var): def lb(var):
return str(options[var]).lower() return str(options[var]).lower()
game_flag = 100 game_flag = 100
# Add the first trigger # Add the first trigger
trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Scripts") trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Scripts")
@ -26,7 +28,7 @@ def triggerSetup(rops, options):
"RotorOps.force_offroad = " + lb("force_offroad") + "\n\n" + "RotorOps.force_offroad = " + lb("force_offroad") + "\n\n" +
"RotorOps.voice_overs = " + lb("voiceovers") + "\n\n" + "RotorOps.voice_overs = " + lb("voiceovers") + "\n\n" +
"RotorOps.zone_status_display = " + lb("game_display") + "\n\n" + "RotorOps.zone_status_display = " + lb("game_display") + "\n\n" +
"RotorOps.inf_spawn_messages = " + lb("inf_spawn_msgs") + "\n\n" + "RotorOps.inf_spawn_messages = true\n\n" +
"RotorOps.inf_spawns_per_zone = " + lb("inf_spawn_qty") + "\n\n" + "RotorOps.inf_spawns_per_zone = " + lb("inf_spawn_qty") + "\n\n" +
"RotorOps.apcs_spawn_infantry = " + lb("apc_spawns_inf") + " \n\n") "RotorOps.apcs_spawn_infantry = " + lb("apc_spawns_inf") + " \n\n")
if not options["smoke_pickup_zones"]: if not options["smoke_pickup_zones"]:
@ -38,7 +40,7 @@ def triggerSetup(rops, options):
trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Zones") trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Zones")
trig.rules.append(dcs.condition.TimeAfter(2)) trig.rules.append(dcs.condition.TimeAfter(2))
for s_zone in rops.staging_zones: for s_zone in rops.staging_zones:
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.stagingZone('" + s_zone + "')"))) trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.addStagingZone('" + s_zone + "')")))
for c_zone in rops.conflict_zones: for c_zone in rops.conflict_zones:
zone_flag = rops.conflict_zones[c_zone].flag zone_flag = rops.conflict_zones[c_zone].flag
trig.actions.append( trig.actions.append(
@ -61,6 +63,15 @@ def triggerSetup(rops, options):
z_active_trig.actions.append(dcs.action.DoScript(dcs.action.String("--Add any action you want here!"))) 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) rops.m.triggerrules.triggers.append(z_active_trig)
# # Add CTLD beacons - this might be cool but we'd need to address placement of the 3D objects
# trig = dcs.triggers.TriggerOnce(comment="RotorOps CTLD Beacons")
# trig.rules.append(dcs.condition.TimeAfter(5))
# trig.actions.append(dcs.action.DoScript(dcs.action.String("ctld.createRadioBeaconAtZone('STAGING','blue', 1440,'STAGING/LOGISTICS')")))
# for c_zone in rops.conflict_zones:
# trig.actions.append(
# dcs.action.DoScript(dcs.action.String("ctld.createRadioBeaconAtZone('" + c_zone + "','blue', 1440,'" + c_zone + "')")))
# rops.m.triggerrules.triggers.append(trig)
# Zone protection SAMs # Zone protection SAMs
if options["zone_protect_sams"]: if options["zone_protect_sams"]:
for index, zone_name in enumerate(rops.conflict_zones): for index, zone_name in enumerate(rops.conflict_zones):
@ -131,11 +142,10 @@ def triggerSetup(rops, options):
# Add transport helos triggers # Add transport helos triggers
for index in range(options["e_transport_helos"]): for index in range(options["e_transport_helos"]):
random_zone_index = random.randrange(1, len(rops.conflict_zones)) random_zone_obj = random.choice(list(rops.conflict_zones.items()))
random_zone_obj = list(rops.conflict_zones.items())[random_zone_index]
zone = random_zone_obj[1] zone = random_zone_obj[1]
z_weak_trig = dcs.triggers.TriggerOnce(comment=zone.name + " Transport Helo") 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.FlagIsMore(zone.flag, 1))
z_weak_trig.rules.append(dcs.condition.FlagIsLess(zone.flag, random.randrange(20, 100))) 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( z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"---Flag " + str(game_flag) + " value represents the index of the active zone. "))) "---Flag " + str(game_flag) + " value represents the index of the active zone. ")))
@ -150,10 +160,13 @@ def triggerSetup(rops, options):
trig.rules.append(dcs.condition.FlagEquals(game_flag, 99)) trig.rules.append(dcs.condition.FlagEquals(game_flag, 99))
trig.actions.append( trig.actions.append(
dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is WON"))) dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is WON")))
trig.actions.append(
dcs.action.DoScript(dcs.action.String("RotorOps.gameMsg(RotorOps.gameMsgs.success)")))
rops.m.triggerrules.triggers.append(trig) rops.m.triggerrules.triggers.append(trig)
trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict LOST") trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict LOST")
trig.rules.append(dcs.condition.FlagEquals(game_flag, 98)) trig.rules.append(dcs.condition.FlagEquals(game_flag, 98))
trig.actions.append( trig.actions.append(
dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is LOST"))) dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is LOST")))
trig.actions.append(
dcs.action.DoScript(dcs.action.String("RotorOps.gameMsg(RotorOps.gameMsgs.failure)")))
rops.m.triggerrules.triggers.append(trig) rops.m.triggerrules.triggers.append(trig)

View File

@ -9,6 +9,7 @@ import RotorOpsGroups
import RotorOpsUnits import RotorOpsUnits
import RotorOpsUtils import RotorOpsUtils
import RotorOpsConflict import RotorOpsConflict
import aircraftMods
from RotorOpsImport import ImportObjects from RotorOpsImport import ImportObjects
import time import time
from MissionGenerator import logger from MissionGenerator import logger
@ -21,15 +22,6 @@ class RotorOpsMission:
def __init__(self): def __init__(self):
self.m = dcs.mission.Mission() self.m = dcs.mission.Mission()
# 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.conflict_zones = {}
self.staging_zones = {} self.staging_zones = {}
@ -38,6 +30,7 @@ class RotorOpsMission:
self.res_map = {} self.res_map = {}
self.config = None self.config = None
class RotorOpsZone: class RotorOpsZone:
def __init__(self, name: str, flag: int, position: dcs.point, size: int): def __init__(self, name: str, flag: int, position: dcs.point, size: int):
self.name = name self.name = name
@ -82,7 +75,7 @@ class RotorOpsMission:
logger.info("Adding script to mission: " + filename) logger.info("Adding script to mission: " + filename)
self.scripts[filename] = self.m.map_resource.add_resource_file(filename) self.scripts[filename] = self.m.map_resource.add_resource_file(filename)
def getUnitsFromMiz(self, filename, side): def getUnitsFromMiz(self, file, side='both'):
forces = {} forces = {}
vehicles = [] vehicles = []
@ -90,49 +83,53 @@ class RotorOpsMission:
transport_helos = [] transport_helos = []
attack_planes = [] attack_planes = []
fighter_planes = [] fighter_planes = []
helicopters = []
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() source_mission = dcs.mission.Mission()
try: try:
source_mission.load_file(filename) source_mission.load_file(file)
if side == 'both':
for country_name in source_mission.coalition.get(side).countries: sides = ['red', 'blue']
country_obj = source_mission.coalition.get(side).countries[country_name] else:
for vehicle_group in country_obj.vehicle_group: sides = [side]
vehicles.append(vehicle_group) for side in sides:
for helicopter_group in country_obj.helicopter_group: for country_name in source_mission.coalition.get(side).countries:
if helicopter_group.task == 'CAS': country_obj = source_mission.coalition.get(side).countries[country_name]
attack_helos.append(helicopter_group) for vehicle_group in country_obj.vehicle_group:
elif helicopter_group.task == 'Transport': vehicles.append(vehicle_group)
transport_helos.append(helicopter_group) for helicopter_group in country_obj.helicopter_group:
for plane_group in country_obj.plane_group: helicopters.append(helicopter_group)
if plane_group.task == 'CAS': if helicopter_group.task == 'CAS':
attack_planes.append(plane_group) attack_helos.append(helicopter_group)
elif plane_group.task == 'CAP': elif helicopter_group.task == 'Transport':
fighter_planes.append(plane_group) transport_helos.append(helicopter_group)
for plane_group in country_obj.plane_group:
if plane_group.task == 'CAS':
attack_planes.append(plane_group)
elif plane_group.task == 'CAP':
fighter_planes.append(plane_group)
forces["vehicles"] = vehicles forces["vehicles"] = vehicles
forces["attack_helos"] = attack_helos forces["attack_helos"] = attack_helos
forces["transport_helos"] = transport_helos forces["transport_helos"] = transport_helos
forces["attack_planes"] = attack_planes forces["attack_planes"] = attack_planes
forces["fighter_planes"] = fighter_planes forces["fighter_planes"] = fighter_planes
forces["helicopters"] = helicopters
return forces return forces
except: except:
logger.error("Failed to load units from " + filename) logger.error("Failed to load units from " + file)
def generateMission(self, window, options):
def generateMission(self, options):
os.chdir(directories.scenarios) os.chdir(directories.scenarios)
logger.info("Looking for mission files in " + os.getcwd()) logger.info("Looking for mission files in " + os.getcwd())
window.statusBar().showMessage("Loading scenario mission", 10000)
self.m.load_file(options["scenario_file"])
self.m.load_file(options["scenario_filename"]) self.addMods()
self.importObjects() self.importObjects()
#todo: test #todo: test
@ -142,8 +139,10 @@ class RotorOpsMission:
failure_msg = "You must include a CombinedJointTaskForcesBlue and CombinedJointTaskForcesRed unit in the scenario template. See the instructions in " + directories.scenarios 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} return {"success": False, "failure_msg": failure_msg}
red_forces = self.getUnitsFromMiz(options["red_forces_filename"], "red") # red_forces = self.getUnitsFromMiz(directories.forces + "/red/" + options["red_forces_filename"], "red")
blue_forces = self.getUnitsFromMiz(options["blue_forces_filename"], "blue") # blue_forces = self.getUnitsFromMiz(directories.forces + "/blue/" + options["blue_forces_filename"], "blue")
red_forces = self.getUnitsFromMiz(directories.forces + "/" + options["red_forces_filename"], "both")
blue_forces = self.getUnitsFromMiz(directories.forces + "/" + options["blue_forces_filename"], "both")
# Add coalitions (we may be able to add CJTF here instead of requiring templates to have objects of those coalitions) # 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("red").add_country(dcs.countries.Russia())
@ -183,6 +182,7 @@ class RotorOpsMission:
#Populate Red zones with ground units #Populate Red zones with ground units
window.statusBar().showMessage("Populating units into mission...", 10000)
for zone_name in red_zones: for zone_name in red_zones:
if red_forces["vehicles"]: if red_forces["vehicles"]:
@ -249,10 +249,7 @@ class RotorOpsMission:
180, zone_name + " FARP", late_activation=False) 180, zone_name + " FARP", late_activation=False)
#add logistics sites #add logistics sites
if options["crates"] and zone_name in self.staging_zones: if options["crates"] and zone_name == "STAGING":
# RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.logistics_site(self.m, self.m.country(jtf_blue),
# blue_zones[zone_name].position,
# 180, zone_name)
os.chdir(directories.imports) os.chdir(directories.imports)
staging_flag = self.m.find_group(zone_name) staging_flag = self.m.find_group(zone_name)
if staging_flag: if staging_flag:
@ -266,13 +263,6 @@ class RotorOpsMission:
i.copyAll(self.m, jtf_blue, "Staging Logistics Zone", i.copyAll(self.m, jtf_blue, "Staging Logistics Zone",
staging_position, staging_heading) staging_position, staging_heading)
if options["zone_protect_sams"] and options["defending"]: if options["zone_protect_sams"] and options["defending"]:
vg = self.m.vehicle_group( vg = self.m.vehicle_group(
self.m.country(jtf_blue), self.m.country(jtf_blue),
@ -286,6 +276,7 @@ class RotorOpsMission:
#Add player slots #Add player slots
window.statusBar().showMessage("Adding flights to mission...", 10000)
if options["slots"] != "Locked to Scenario" and options["slots"] != "None": if options["slots"] != "Locked to Scenario" and options["slots"] != "None":
self.addPlayerHelos(options) self.addPlayerHelos(options)
@ -297,15 +288,22 @@ class RotorOpsMission:
self.m.map.zoom = 100000 self.m.map.zoom = 100000
#add files and triggers necessary for RotorOps.lua script #add files and triggers necessary for RotorOps.lua script
window.statusBar().showMessage("Adding resources to mission...", 10000)
self.addResources(directories.sound, directories.scripts) self.addResources(directories.sound, directories.scripts)
RotorOpsConflict.triggerSetup(self, options) RotorOpsConflict.triggerSetup(self, options)
#Save the mission file #Save the mission file
os.chdir(directories.output) window.statusBar().showMessage("Saving mission...", 10000)
output_filename = options["scenario_filename"].removesuffix('.miz') + " " + time.strftime('%a%H%M%S') + '.miz' if window.user_output_dir:
output_dir = window.user_output_dir # if user has set output dir
else:
output_dir = directories.output # default dir
os.chdir(output_dir)
output_filename = options["scenario_name"] + " " + time.strftime('%a%H%M%S') + '.miz'
success = self.m.save(output_filename) success = self.m.save(output_filename)
return {"success": success, "filename": output_filename, "directory": directories.output} #let the UI know the result return {"success": success, "filename": output_filename, "directory": output_dir} #let the UI know the result
def addGroundGroups(self, zone, _country, groups, quantity): def addGroundGroups(self, zone, _country, groups, quantity):
for a in range(0, quantity): for a in range(0, quantity):
@ -459,7 +457,16 @@ class RotorOpsMission:
client_helos = RotorOpsUnits.client_helos client_helos = RotorOpsUnits.client_helos
for helicopter in dcs.helicopters.helicopter_map: for helicopter in dcs.helicopters.helicopter_map:
if helicopter == options["slots"]: if helicopter == options["slots"]:
client_helos = [dcs.helicopters.helicopter_map[helicopter]] client_helos = [dcs.helicopters.helicopter_map[helicopter]] #if out ui slot option matches a specific helicopter type name
# get loadouts from miz file and put into a simple dict
default_loadouts = {}
default_unit_groups = self.getUnitsFromMiz(directories.home_dir + "\\config\\blue_player_loadouts.miz", "blue")
for helicopter_group in default_unit_groups["helicopters"]:
default_loadouts[helicopter_group.units[0].unit_type.id] = {}
default_loadouts[helicopter_group.units[0].unit_type.id]["pylons"] = helicopter_group.units[0].pylons
default_loadouts[helicopter_group.units[0].unit_type.id]["livery_id"] = helicopter_group.units[0].livery_id
default_loadouts[helicopter_group.units[0].unit_type.id]["fuel"] = helicopter_group.units[0].fuel
#find friendly carriers and farps #find friendly carriers and farps
carrier = self.m.country(jtf_blue).find_ship_group(name="HELO_CARRIER") carrier = self.m.country(jtf_blue).find_ship_group(name="HELO_CARRIER")
@ -474,16 +481,33 @@ class RotorOpsMission:
heading = 0 heading = 0
group_size = 1 group_size = 1
player_helicopters = []
if options["slots"] == "Multiple Slots":
player_helicopters = options["player_slots"]
else:
player_helicopters.append(options["slots"]) # single helicopter type
if len(client_helos) == 1: if len(client_helos) == 1:
group_size = 2 #add a wingman if singleplayer group_size = 2 #add a wingman if singleplayer
for helotype in client_helos: start_type = dcs.mission.StartType.Cold
if options["player_hotstart"]:
start_type = dcs.mission.StartType.Warm
farp_helicopter_count = 1
for helicopter_id in player_helicopters:
helotype = None
if helicopter_id in dcs.helicopters.helicopter_map:
helotype = dcs.helicopters.helicopter_map[helicopter_id]
else:
continue
if carrier: if carrier:
fg = self.m.flight_group_from_unit(self.m.country(jtf_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) dcs.task.CAS, group_size=group_size, start_type=start_type)
elif farp: elif farp and farp_helicopter_count <= 4:
farp_helicopter_count = farp_helicopter_count + 1
fg = self.m.flight_group_from_unit(self.m.country(jtf_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) dcs.task.CAS, group_size=group_size, start_type=start_type)
#invisible farps need manual unit placement for multiple units #invisible farps need manual unit placement for multiple units
if farp.units[0].type == 'Invisible FARP': if farp.units[0].type == 'Invisible FARP':
@ -493,13 +517,20 @@ class RotorOpsMission:
heading += 90 heading += 90
else: else:
fg = self.m.flight_group_from_airport(self.m.country(jtf_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) self.getParking(primary_f_airport, helotype), group_size=group_size, start_type=start_type)
fg.units[0].set_client() fg.units[0].set_client()
fg.load_task_default_loadout(dcs.task.CAS) #fg.load_task_default_loadout(dcs.task.CAS)
if helotype.id in default_loadouts:
fg.units[0].pylons = default_loadouts[helotype.id]["pylons"]
fg.units[0].livery_id = default_loadouts[helotype.id]["livery_id"]
fg.units[0].fuel = default_loadouts[helotype.id]["fuel"]
#setup wingman for single player #setup wingman for single player
if len(fg.units) == 2: if len(fg.units) == 2:
fg.units[1].skill = dcs.unit.Skill.High fg.units[1].skill = dcs.unit.Skill.High
fg.units[1].pylons = fg.units[0].pylons
fg.units[1].livery_id = fg.units[0].livery_id
fg.units[1].fuel = fg.units[0].fuel
class TrainingScenario(): class TrainingScenario():
@ -683,7 +714,7 @@ class RotorOpsMission:
farp, farp,
maintask=dcs.task.CAS, maintask=dcs.task.CAS,
start_type=dcs.mission.StartType.Cold, start_type=dcs.mission.StartType.Cold,
group_size=group_size) group_size=1) # more than one spawn on top of each other, setting group size to one for now
zone_attack(afg, farp) zone_attack(afg, farp)
elif airport: elif airport:
@ -794,3 +825,6 @@ class RotorOpsMission:
i.anchorByGroupName("ANCHOR") 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) new_statics, new_vehicles, new_helicopters = i.copyAll(self.m, country_name, group.units[0].name, group.units[0].position, group.units[0].heading)
def addMods(self):
dcs.helicopters.helicopter_map["UH-60L"] = aircraftMods.UH_60L
self.m.country(jtf_blue).helicopters.append(aircraftMods.UH_60L)

View File

@ -1,12 +1,27 @@
import dcs import dcs
import aircraftMods
client_helos = [ client_helos = [
dcs.helicopters.UH_1H, dcs.helicopters.UH_1H,
#aircraftMods.UH_60L,
dcs.helicopters.AH_64D_BLK_II, dcs.helicopters.AH_64D_BLK_II,
dcs.helicopters.Mi_24P, dcs.helicopters.Mi_24P,
dcs.helicopters.Ka_50, dcs.helicopters.Ka_50,
] ]
player_helos = [
dcs.helicopters.AH_64D_BLK_II,
dcs.helicopters.Ka_50,
dcs.helicopters.Mi_8MT,
dcs.helicopters.Mi_24P,
dcs.helicopters.SA342M,
dcs.helicopters.SA342L,
dcs.helicopters.SA342Minigun,
dcs.helicopters.SA342Mistral,
dcs.helicopters.UH_1H,
aircraftMods.UH_60L,
]
e_attack_helos = [ e_attack_helos = [
dcs.helicopters.Mi_24P, dcs.helicopters.Mi_24P,
dcs.helicopters.Ka_50, dcs.helicopters.Ka_50,

View File

@ -1,46 +0,0 @@
You can add your own scenarios in this directory and they will appear in the mission generator. See the other scenario .miz files for examples of what to include in your template.
A scenario .miz file MUST have:
1) Between 1-4 circular trigger zones called "ALPHA", "BRAVO", "CHARLIE", "DELTA"
2) At least one trigger zone with a name that starts with "STAGING".
3) A blue airport (recommend somewhere near/on-side your staging zone).
4) A red airport (recommend somewhere near/on-side your last conflict zone).
5) At least one Russian unit or static object. Anything will work, even a cow. You can set "HIDDEN ON MAP".
6) At least one USA unit or static object. See previous point.
Optional:
7) USA FARP called "HELO_FARP" for automatic player placement. (Strongly suggest using immortal and invisible options for support vehicles, and add "static" to the group name to keep them from moving)
8) USA Carrier called "HELO_CARRIER" for automatic player placement.
9) Infantry spawn zones inside conflict zones. Add near buildings to simulate infantry hiding within. Name trigger zones like "ALPHA_SPAWN", "ALPHA_SPAWN_2, etc.
Testing:
You should test your scenarios to ensure that vehicals move between zones as you expect. In some circumstances, vehicles may not be able to calculate a valid route to the next zone, and they will stop. Make sure they can route correctly by testing your scenario in fast forward, with few defending units. You can also get a good idea as to how long your scenario will take to complete.
Tips:
-Position the center of conflict zones over an open area, as this position will be used to spawn units and FARPs.
-Position the center of staging zones over an open area of at least 1000 x 1000ft to provide space for logistics zones.
-For very scenery dense areas like forests or urban areas, smaller conflict zone sizes are highly recommended (eg 4000ft radius). A zone center near a roadway may also help keep units moving smoothly.
-The conflict game type can be played with blue forces on defense. In this mode the last conflict zone is the only troop pickup zone.
-Design your template so that it can be played in normal 'attacking' mode or 'defending' the conflict zone from enemy ground units starting from the staging zone.
-Keep the zones fairly close together, both for helicopter and ground unit travel times.
-You can place static objects and units in a scenario template.
-You can change mission briefing and other mission options in the template.
-Drop your templates in the RotorOps Discord if you'd like to have them added in a release for everyone. Maintain a similar naming convention and be sure to credit yourself in the .miz name.
-Airfields can be captured with ground units. You might consider placing conflict zones over neutral airfields for a rearming area, or perhaps unarmed client slots.
-Player/client slots are placed in this priority order: Carrier named "HELO_CARRIER", FARP named "HELO_FARP", and the blue airfield.
-Friendly AWACs and tankers will be placed at the blue airport if parking is available, otherwise they will start in the air.
-Enemy helicopters and planes will spawn at the red airport.
-Late activation FARPs might be useful for rearming far from the player spawn point.
-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.

23
Generator/aircraftMods.py Normal file
View File

@ -0,0 +1,23 @@
import dcs.task as task
from dcs.helicopters import HelicopterType
from typing import Set
# RotorOps class for UH-60L mod
class UH_60L(HelicopterType):
id = "UH-60L"
flyable = True
height = 5.13
width = 16.4
length = 19.76
fuel_max = 1362
max_speed = 300
chaff = 30
flare = 60
charge_total = 90
chaff_charge_size = 1
flare_charge_size = 1
pylons: Set[int] = {1, 2, 3, 4, 5, 6, 7}
tasks = [task.Transport]
task_default = task.Transport

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

View File

@ -1,5 +1,8 @@
#build UI files #build UI files
pyuic5 -x MissionGeneratorUI.ui -o MissionGeneratorUI.py pyuic5 -x MissionGeneratorUI.ui -o MissionGeneratorUI.py
#build resources
pyrcc5 -o resources.py resources.qrc
#build exe #build exe
pyinstaller MissionGenerator.spec --distpath ..\ -i='assets\icon.ico' pyinstaller MissionGenerator.spec --distpath ..\ -i='assets\icon.ico'

Binary file not shown.

View File

@ -0,0 +1,34 @@
for reference from here: https://installforge.net/forums/viewtopic.php?t=2
<InstallPath>
<AppName>
<ProgramVersion>
<Company>
<Website>
<Language>
<Username>
<Organisation>
<Serial>
<Windows>
<System>
<Temp>
<Font>
<ProgramFiles>
<Desktop>
<DesktopPublic>
<Startup>
<StartupPublic>
<Documents>
<DocumentsPublic>
<StartmenuPrograms>
<StartmenuProgramsPublic>
<AppData>
<AppDataPublic>

1197
Generator/resources.py Normal file

File diff suppressed because it is too large Load Diff

6
Generator/resources.qrc Normal file
View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/images">
<file alias="star_full">resources/star_full.png</file>
<file alias="star_empty">resources/star_empty.png</file>
</qresource>
</RCC>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

41
Generator/user.py Normal file
View File

@ -0,0 +1,41 @@
import secrets
import os
import winreg
path = winreg.HKEY_CURRENT_USER
def saveReg(k,v):
try:
key = winreg.OpenKeyEx(path, r"SOFTWARE\\")
newKey = winreg.CreateKey(key,"RotorOps")
winreg.SetValueEx(newKey, k, 0, winreg.REG_SZ, str(v))
if newKey:
winreg.CloseKey(newKey)
return True
except Exception as e:
print(e)
return False
def readReg(k):
try:
key = winreg.OpenKeyEx(path, r"SOFTWARE\\RotorOps\\")
value = winreg.QueryValueEx(key,k)
if key:
winreg.CloseKey(key)
return value[0]
except Exception as e:
print(e)
return None
def createUserKey():
userid = readReg('User')
if not userid or userid == 'None':
print("Unable to find userid in registry.")
userid = secrets.token_urlsafe(10)
if saveReg('User', userid):
print("Saved userid to registry")
return userid

Binary file not shown.

View File

@ -1,11 +1,11 @@
![alt text](https://github.com/spencershepard/RotorOps/blob/main/Generator/assets/briefing1.png?raw=true) ![alt text](https://dcs-helicopters.com/images/briefing1.png?raw=true)
# What is RotorOps? # 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'. 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'.
At the core of the RotorOps script are AI enhancements that provide a dynamic ground war by causing automatic conflicts between ground forces and a progression of the front line. At the core of the RotorOps script are AI enhancements that provide a dynamic ground war by causing automatic conflicts between ground forces and a progression of the front line.
![alt text](https://github.com/spencershepard/RotorOps/blob/main/documentation/images/rotorops%20ss%200_3.PNG?raw=true) ![alt text](https://dcs-helicopters.com/images/RotorOps%20v1%20UI.png?raw=true)
# Key Features: # Key Features:

View File

Before

Width:  |  Height:  |  Size: 56 KiB

After

Width:  |  Height:  |  Size: 56 KiB

BIN
assets/briefing1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

Before

Width:  |  Height:  |  Size: 689 KiB

After

Width:  |  Height:  |  Size: 689 KiB

View File

Before

Width:  |  Height:  |  Size: 259 KiB

After

Width:  |  Height:  |  Size: 259 KiB

View File

Before

Width:  |  Height:  |  Size: 75 KiB

After

Width:  |  Height:  |  Size: 75 KiB

BIN
assets/splash.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

BIN
assets/star_empty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

BIN
assets/star_full.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

View File

@ -0,0 +1,29 @@
description:
player_spawn: auto
checkboxes:
defense_checkBox: false
apcs_spawn_checkBox: true
logistics_crates_checkBox: true
awacs_checkBox: true
tankers_checkBox: true
zone_sams_checkBox: false
smoke_pickup_zone_checkBox: false
inf_spawn_voiceovers_checkBox: true
game_status_checkBox: true
voiceovers_checkBox: true
force_offroad_checkBox: false
hotstart_checkBox: false
disable_checkboxes:
spinboxes:
blueqty_spinBox: 4
redqty_spinBox: 2
e_attack_helos_spinBox: 2
e_attack_planes_spinBox: 1
e_transport_helos_spinBox: 1
troop_drop_spinBox: 4
inf_spawn_spinBox: 2
radiobuttons: farp_gunits,
red_forces: "RED Default Armor (HARD)"
blue_forces: "BLUE Default US Armor"

2
config/user-data.yaml Normal file
View File

@ -0,0 +1,2 @@
local_ratings:
C:\RotorOps\templates\Scenarios\included\007d3d\Nevada Conflict - Vegas Tour (GRIMM).miz: 4

View File

@ -1 +0,0 @@
Use of this software or derivitives of this software is not permitted on 24/7 public multiplayer servers without permission. Scheduled events are excepted.

6427
scripts/CTLD2.lua Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
RotorOps = {} RotorOps = {}
RotorOps.version = "1.2.7" RotorOps.version = "1.2.8"
local debug = true local debug = true
@ -31,6 +31,7 @@ RotorOps.CTLD_crates = false
RotorOps.CTLD_sound_effects = true --sound effects for troop pickup/dropoffs RotorOps.CTLD_sound_effects = true --sound effects for troop pickup/dropoffs
RotorOps.exclude_ai_group_name = "Static" --include this somewhere in a group name to exclude the group from being tasked in the active zone RotorOps.exclude_ai_group_name = "Static" --include this somewhere in a group name to exclude the group from being tasked in the active zone
RotorOps.pickup_zone_smoke = "blue" RotorOps.pickup_zone_smoke = "blue"
RotorOps.apc_group = {mg=1,at=0,aa=0,inf=3,mortar=0} --not used yet, but we should define the CTLD groups
---[[END OF OPTIONS]]--- ---[[END OF OPTIONS]]---
@ -45,7 +46,7 @@ RotorOps.zones = {}
RotorOps.active_zone = "" --name of the active zone RotorOps.active_zone = "" --name of the active zone
RotorOps.active_zone_index = 0 RotorOps.active_zone_index = 0
RotorOps.game_state_flag = 1 --user flag to store the game state RotorOps.game_state_flag = 1 --user flag to store the game state
RotorOps.staging_zone = "" RotorOps.staging_zones = {}
RotorOps.ctld_pickup_zones = {} --keep track of ctld zones we've added, mainly for map markup RotorOps.ctld_pickup_zones = {} --keep track of ctld zones we've added, mainly for map markup
RotorOps.ai_defending_infantry_groups = {} RotorOps.ai_defending_infantry_groups = {}
RotorOps.ai_attacking_infantry_groups = {} RotorOps.ai_attacking_infantry_groups = {}
@ -59,6 +60,7 @@ trigger.action.outText("ROTOR OPS STARTED: "..RotorOps.version, 5)
env.info("ROTOR OPS STARTED: "..RotorOps.version) env.info("ROTOR OPS STARTED: "..RotorOps.version)
RotorOps.staged_units = {} --table of ground units that started in the staging zone RotorOps.staged_units = {} --table of ground units that started in the staging zone
RotorOps.staged_units_by_zone = {}
RotorOps.eventHandler = {} RotorOps.eventHandler = {}
local commandDB = {} local commandDB = {}
local game_message_buffer = {} local game_message_buffer = {}
@ -200,7 +202,7 @@ function RotorOps.eventHandler:onEvent(event)
if (world.event.S_EVENT_ENGINE_STARTUP == event.id) then --play some sound files when a player starts engines if (world.event.S_EVENT_ENGINE_STARTUP == event.id) then --play some sound files when a player starts engines
local initiator = event.initiator:getGroup():getID() local initiator = event.initiator:getGroup():getID()
if #event.initiator:getGroup():getUnits() == 1 then --if there are no other units in the player flight group (preventing duplicated messages for ai wingman flights) if #event.initiator:getGroup():getUnits() == 1 and RotorOps.voice_overs then --if there are no other units in the player flight group (preventing duplicated messages for ai wingman flights)
if RotorOps.defending then if RotorOps.defending then
trigger.action.outSoundForGroup(initiator , RotorOps.gameMsgs.enemy_pushing[RotorOps.active_zone_index + 1][2]) trigger.action.outSoundForGroup(initiator , RotorOps.gameMsgs.enemy_pushing[RotorOps.active_zone_index + 1][2])
else else
@ -423,7 +425,12 @@ function RotorOps.getValidUnitFromGroup(grp)
else else
group_obj = grp group_obj = grp
end end
if grp:isExist() ~= true then return nil end if not grp then
return nil
end
if grp:isExist() ~= true then
return nil
end
local first_valid_unit local first_valid_unit
for index, unit in pairs(grp:getUnits()) for index, unit in pairs(grp:getUnits())
do do
@ -521,6 +528,36 @@ function RotorOps.aiTask(grp, task, zone)
end end
--add units to the staged_units table for ai tasking as attackers
function RotorOps.tallyZone(zone_name)
local new_units
if RotorOps.defending then
new_units = mist.getUnitsInZones(mist.makeUnitTable({'[red][vehicle]'}), {zone_name})
else
new_units = mist.getUnitsInZones(mist.makeUnitTable({'[blue][vehicle]'}), {zone_name})
end
if new_units and #new_units > 0 then
for index, unit in pairs(new_units) do
if not hasValue(RotorOps.staged_units, unit) then
env.info("RotorOps adding new units to staged_units: "..#new_units)
table.insert(RotorOps.staged_units, unit)
RotorOps.aiTask(unit:getGroup(),"move_to_active_zone", RotorOps.zones[RotorOps.active_zone_index].name)
else
--env.info("unit already in table")
end
end
end
--
-- for index, unit in pairs(RotorOps.staged_units) do
-- if string.find(Unit.getGroup(unit):getName():lower(), RotorOps.exclude_ai_group_name:lower()) then
-- RotorOps.staged_units[index] = nil --remove 'static' units
-- end
-- end
end
---AI CORE BEHAVIOR-- ---AI CORE BEHAVIOR--
@ -976,11 +1013,9 @@ function RotorOps.assessUnitsInZone(var)
if RotorOps.defending == true then if RotorOps.defending == true then
RotorOps.game_state = RotorOps.game_states.lost RotorOps.game_state = RotorOps.game_states.lost
trigger.action.setUserFlag(RotorOps.game_state_flag, RotorOps.game_states.lost) trigger.action.setUserFlag(RotorOps.game_state_flag, RotorOps.game_states.lost)
RotorOps.gameMsg(RotorOps.gameMsgs.failure)
else else
RotorOps.game_state = RotorOps.game_states.won RotorOps.game_state = RotorOps.game_states.won
trigger.action.setUserFlag(RotorOps.game_state_flag, RotorOps.game_states.won) trigger.action.setUserFlag(RotorOps.game_state_flag, RotorOps.game_states.won)
RotorOps.gameMsg(RotorOps.gameMsgs.success)
end end
return --we won't reset our timer to fire this function again return --we won't reset our timer to fire this function again
end end
@ -995,7 +1030,6 @@ function RotorOps.assessUnitsInZone(var)
if RotorOps.defending and defending_game_won then if RotorOps.defending and defending_game_won then
RotorOps.game_state = RotorOps.game_states.won RotorOps.game_state = RotorOps.game_states.won
trigger.action.setUserFlag(RotorOps.game_state_flag, RotorOps.game_states.won) trigger.action.setUserFlag(RotorOps.game_state_flag, RotorOps.game_states.won)
RotorOps.gameMsg(RotorOps.gameMsgs.success)
return --we won't reset our timer to fire this function again return --we won't reset our timer to fire this function again
end end
@ -1193,7 +1227,6 @@ function RotorOps.setActiveZone(new_index)
RotorOps.gameMsg(RotorOps.gameMsgs.enemy_pushing, new_index) RotorOps.gameMsg(RotorOps.gameMsgs.enemy_pushing, new_index)
else else
RotorOps.gameMsg(RotorOps.gameMsgs.push, new_index) RotorOps.gameMsg(RotorOps.gameMsgs.push, new_index)
RotorOps.gameMsg(RotorOps.gameMsgs.get_troops_to_zone, new_index)
end end
end end
@ -1281,13 +1314,14 @@ function RotorOps.addZone(_name, _zone_defenders_flag)
RotorOps.addPickupZone(_name, RotorOps.pickup_zone_smoke, -1, "no", 2) RotorOps.addPickupZone(_name, RotorOps.pickup_zone_smoke, -1, "no", 2)
end end
function RotorOps.stagingZone(_name)
function RotorOps.addStagingZone(_name)
if trigger.misc.getZone(_name) == nil then if trigger.misc.getZone(_name) == nil then
trigger.action.outText(_name.." trigger zone missing! Check RotorOps setup!", 60) trigger.action.outText(_name.." trigger zone missing! Check RotorOps setup!", 60)
env.warning(_name.." trigger zone missing! Check RotorOps setup!") env.warning(_name.." trigger zone missing! Check RotorOps setup!")
end end
RotorOps.addPickupZone(_name, RotorOps.pickup_zone_smoke, -1, "no", 0) RotorOps.addPickupZone(_name, RotorOps.pickup_zone_smoke, -1, "no", 0)
RotorOps.staging_zone = _name RotorOps.staging_zones[#RotorOps.staging_zones + 1] = _name
end end
@ -1325,17 +1359,26 @@ function RotorOps.addPickupZone(zone_name, smoke, limit, active, side)
RotorOps.ctld_pickup_zones[#RotorOps.ctld_pickup_zones + 1] = zone_name RotorOps.ctld_pickup_zones[#RotorOps.ctld_pickup_zones + 1] = zone_name
ctld.pickupZones[#ctld.pickupZones + 1] = {zone_name, smoke, limit, active, side} ctld.pickupZones[#ctld.pickupZones + 1] = {zone_name, smoke, limit, active, side}
end end
function RotorOps.startConflict() function RotorOps.startConflict()
if RotorOps.game_state ~= RotorOps.game_states.not_started then return end --if RotorOps.game_state ~= RotorOps.game_states.not_started then return end
--make some changes to the radio menu --make some changes to the radio menu
--local conflict_zones_menu = commandDB['conflict_zones_menu'] --local conflict_zones_menu = commandDB['conflict_zones_menu']
--missionCommands.removeItem(commandDB['start_conflict']) --missionCommands.removeItem(commandDB['start_conflict'])
--commandDB['clear_zone'] = missionCommands.addCommand( "[CHEAT] Force Clear Zone" , conflict_zones_menu , RotorOps.clearActiveZone) --commandDB['clear_zone'] = missionCommands.addCommand( "[CHEAT] Force Clear Zone" , conflict_zones_menu , RotorOps.clearActiveZone)
RotorOps.staged_units = mist.getUnitsInZones(mist.makeUnitTable({'[all][vehicle]'}), {RotorOps.staging_zone}) RotorOps.staged_units = mist.getUnitsInZones(mist.makeUnitTable({'[all][vehicle]'}), RotorOps.staging_zones)
--filter out 'static' units
-- for index, unit in pairs(RotorOps.staged_units) do
-- if string.find(Unit.getGroup(unit):getName():lower(), RotorOps.exclude_ai_group_name:lower()) then
-- RotorOps.staged_units[index] = nil --remove 'static' units
-- end
-- end
if RotorOps.staged_units[1] == nil then if RotorOps.staged_units[1] == nil then
trigger.action.outText("RotorOps failed: You must place ground units in the staging and conflict zones!" , 60, false) trigger.action.outText("RotorOps failed: You must place ground units in the staging and conflict zones!" , 60, false)
@ -1347,10 +1390,16 @@ function RotorOps.startConflict()
RotorOps.defending = true RotorOps.defending = true
RotorOps.gameMsg(RotorOps.gameMsgs.start_defense) RotorOps.gameMsg(RotorOps.gameMsgs.start_defense)
ctld.activatePickupZone(RotorOps.zones[#RotorOps.zones].name) --make the last zone a pickup zone for defenders ctld.activatePickupZone(RotorOps.zones[#RotorOps.zones].name) --make the last zone a pickup zone for defenders
ctld.deactivatePickupZone(RotorOps.staging_zone) for index, zone in pairs(RotorOps.staging_zones) do
ctld.deactivatePickupZone(zone)
end
else else
RotorOps.gameMsg(RotorOps.gameMsgs.start) RotorOps.gameMsg(RotorOps.gameMsgs.start)
ctld.activatePickupZone(RotorOps.staging_zone) for index, zone in pairs(RotorOps.staging_zones) do
ctld.activatePickupZone(zone)
end
end end
RotorOps.setActiveZone(1) RotorOps.setActiveZone(1)

View File

@ -0,0 +1,66 @@
# A script for creating the modules map file
import os
import yaml
print("Current dir: " + os.getcwd())
modules = []
module_folders = next(os.walk('.'))[1]
for folder in module_folders:
valid_module = False
module_filenames = []
module = {}
print("searching folder: " + folder)
for filename in os.listdir(folder):
module_filenames.append(filename)
# assume the yaml file is our scenario configuration file
if filename.endswith(".yaml"):
#print("found config file: " + filename)
stream = file(os.path.join(folder, filename), 'r')
config = yaml.load(stream)
#print("Config file yaml: " + str(config))
if 'name' in config:
print("Config file has name: " + config['name'])
valid_module = True
module['name'] = config['name']
if valid_module:
print("Populating module attributes for " + folder)
module['id'] = folder
module['dist'] = 'add'
module['path'] = 'templates\Scenarios\downloaded'
module['files'] = module_filenames
if 'version' in config:
module['version'] = config['version']
else:
module['version'] = 1
if 'requires' in config:
module['requires'] = config['requires']
else:
module['requires'] = 1
modules.append(module)
print("Found modules: " + str(len(modules)))
if len(modules) > 0:
modulemap = {}
#print(str(modules))
for m in modules:
print("adding module: " + m["id"])
modulemap[m['id']] = m
with open('module-map.yaml', 'w') as mapfile:
print("Creating map file...")
yaml.dump(modulemap, mapfile)
print("Success.")

View File

@ -0,0 +1,24 @@
## Forces Templates
The friendly/enemy forces templates available in the generator are simply .miz files in the Generator/Forces folder.
A Forces template defines the groups of ground units available, AI aircraft, liveries, and loadouts.
To create your own Forces template:
1) Create an empty mission on Caucasus
2) Add ground unit groups.
3) Save the mission in this directory.
Optional:
4) Add helicopters with "CAS" main task for attack helicopters.
5) Add helicopters with "Transport" main task for transport helicopters.
6) Add planes with "CAS" main task for attack planes.
7) Add planes with "CAP" main task for fighters.
8) Configure loadouts, liveries, and skill for aircraft.
Tips:
- The mission generator will only extract blue ground units from the template when selected from the "Blue Forces" menu, and vice versa.
- Only unit types are used from ground units. Liveries or other attributes are able to be copied.
- For aircraft, group size is currently capped at 2 units per group to help prevent issues with parking. Only the first unit in the group is used as a source.

Binary file not shown.

View File

@ -0,0 +1,20 @@
## Imports
A breakthrough feature of mission design with RotorOps is the ability to import complex arrangements of statics and vehicles. This allows you to create reusable mission assets like bases, FARPs, objective sites, or just about anything you can imagine building in the mission editor. You can place these on any map, at your desired point, rotation and coalition!
A selection of FOBs, FARPs, and other objects are available in the Imports folder. Included are multiplayer FOBs with up to 16 helicopter spawns! A guide to the included templates is available here: [RotorOps IMPORT Assets](http://dcs-helicopters.com/wp-content/uploads/2022/03/RotorOps_IMPORT_TEMPLATES-1.pdf)
To use an import template:
1) Place a static mark flag in the scenario template mission.
2) Change the group name to 'IMPORT-filename', where the filename is a .miz file in the Generator/Imports folder.
3) Change the flag coalition to CJTF Blue/Red or UN Peacekeepers.
4) Change the flag heading and position as desired.
5) Change the flag UNIT NAME to something relevant (ie. 'North Base')
6) For multiple imports of the same template, the import object GROUP NAME should end with '-01' etc
To create a new import template:
1) Make an empty mission on Caucasus.
2) Place units/objects on the map.
3) Make one unit group name: 'ANCHOR' This will represent the point of insertion/rotation in the target mission.
4) Save the template .miz file in Generator/Imports

Binary file not shown.