Merge pull request #20 from spencershepard/develop

Develop
This commit is contained in:
spencershepard 2022-02-06 16:15:42 -08:00 committed by GitHub
commit 02f496a406
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 606 additions and 142 deletions

Binary file not shown.

View File

@ -13,6 +13,9 @@ from PyQt5.QtWidgets import (
from PyQt5 import QtGui from PyQt5 import QtGui
from MissionGeneratorUI import Ui_MainWindow from MissionGeneratorUI import Ui_MainWindow
maj_version = 0
minor_version = 3
version_string = str(maj_version) + "." + str(minor_version)
scenarios = [] scenarios = []
red_forces_files = [] red_forces_files = []
blue_forces_files = [] blue_forces_files = []
@ -43,6 +46,8 @@ class Window(QMainWindow, Ui_MainWindow):
self.statusbar.setStyleSheet( self.statusbar.setStyleSheet(
"QStatusBar{padding-left:5px;color:black;font-weight:bold;}") "QStatusBar{padding-left:5px;color:black;font-weight:bold;}")
self.version_label.setText("Version " + version_string)
def connectSignalsSlots(self): def connectSignalsSlots(self):
# self.action_Exit.triggered.connect(self.close) # self.action_Exit.triggered.connect(self.close)
@ -155,14 +160,14 @@ class Window(QMainWindow, Ui_MainWindow):
"crates": self.logistics_crates_checkBox.isChecked(), "crates": self.logistics_crates_checkBox.isChecked(),
"f_awacs": self.awacs_checkBox.isChecked(), "f_awacs": self.awacs_checkBox.isChecked(),
"f_tankers": self.tankers_checkBox.isChecked(), "f_tankers": self.tankers_checkBox.isChecked(),
"smoke_zone": self.smoke_checkBox.isChecked(),
"voiceovers": self.voiceovers_checkBox.isChecked(), "voiceovers": self.voiceovers_checkBox.isChecked(),
"force_offroad": self.force_offroad_checkBox.isChecked(), "force_offroad": self.force_offroad_checkBox.isChecked(),
"game_display": self.game_status_checkBox.isChecked(), "game_display": self.game_status_checkBox.isChecked(),
"defending": self.defense_checkBox.isChecked(), "defending": self.defense_checkBox.isChecked(),
"slots": self.slot_template_comboBox.currentText(), "slots": self.slot_template_comboBox.currentText(),
"smoke_zone": self.smoke_checkBox.isChecked(),
"zone_protect_sams": self.zone_sams_checkBox.isChecked(), "zone_protect_sams": self.zone_sams_checkBox.isChecked(),
"zone_farps": self.farp_buttonGroup.checkedButton().objectName(),
"inf_spawn_msgs": self.inf_spawn_voiceovers_checkBox.isChecked(),
} }
os.chdir(self.m.home_dir + '/Generator') os.chdir(self.m.home_dir + '/Generator')
n = ROps.RotorOpsMission() n = ROps.RotorOpsMission()

View File

@ -73,7 +73,7 @@ class Ui_MainWindow(object):
self.redforces_comboBox.setGeometry(QtCore.QRect(170, 230, 291, 31)) self.redforces_comboBox.setGeometry(QtCore.QRect(170, 230, 291, 31))
self.redforces_comboBox.setObjectName("redforces_comboBox") self.redforces_comboBox.setObjectName("redforces_comboBox")
self.background_label = QtWidgets.QLabel(self.centralwidget) self.background_label = QtWidgets.QLabel(self.centralwidget)
self.background_label.setGeometry(QtCore.QRect(-30, 490, 801, 371)) self.background_label.setGeometry(QtCore.QRect(-40, 440, 801, 371))
self.background_label.setAutoFillBackground(False) self.background_label.setAutoFillBackground(False)
self.background_label.setStyleSheet("") self.background_label.setStyleSheet("")
self.background_label.setText("") self.background_label.setText("")
@ -93,7 +93,7 @@ class Ui_MainWindow(object):
font.setPointSize(12) font.setPointSize(12)
self.blueqty_spinBox.setFont(font) self.blueqty_spinBox.setFont(font)
self.blueqty_spinBox.setMinimum(0) self.blueqty_spinBox.setMinimum(0)
self.blueqty_spinBox.setMaximum(50) self.blueqty_spinBox.setMaximum(8)
self.blueqty_spinBox.setProperty("value", 3) self.blueqty_spinBox.setProperty("value", 3)
self.blueqty_spinBox.setObjectName("blueqty_spinBox") self.blueqty_spinBox.setObjectName("blueqty_spinBox")
self.redqty_spinBox = QtWidgets.QSpinBox(self.centralwidget) self.redqty_spinBox = QtWidgets.QSpinBox(self.centralwidget)
@ -102,7 +102,7 @@ class Ui_MainWindow(object):
font.setPointSize(12) font.setPointSize(12)
self.redqty_spinBox.setFont(font) self.redqty_spinBox.setFont(font)
self.redqty_spinBox.setMinimum(0) self.redqty_spinBox.setMinimum(0)
self.redqty_spinBox.setMaximum(50) self.redqty_spinBox.setMaximum(8)
self.redqty_spinBox.setProperty("value", 2) self.redqty_spinBox.setProperty("value", 2)
self.redqty_spinBox.setObjectName("redqty_spinBox") self.redqty_spinBox.setObjectName("redqty_spinBox")
self.scenario_label_4 = QtWidgets.QLabel(self.centralwidget) self.scenario_label_4 = QtWidgets.QLabel(self.centralwidget)
@ -113,7 +113,7 @@ class Ui_MainWindow(object):
self.scenario_label_4.setAlignment(QtCore.Qt.AlignCenter) self.scenario_label_4.setAlignment(QtCore.Qt.AlignCenter)
self.scenario_label_4.setObjectName("scenario_label_4") self.scenario_label_4.setObjectName("scenario_label_4")
self.game_status_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.game_status_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.game_status_checkBox.setGeometry(QtCore.QRect(1000, 590, 191, 16)) self.game_status_checkBox.setGeometry(QtCore.QRect(810, 790, 191, 16))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(9) font.setPointSize(9)
self.game_status_checkBox.setFont(font) self.game_status_checkBox.setFont(font)
@ -121,20 +121,21 @@ class Ui_MainWindow(object):
self.game_status_checkBox.setTristate(False) self.game_status_checkBox.setTristate(False)
self.game_status_checkBox.setObjectName("game_status_checkBox") self.game_status_checkBox.setObjectName("game_status_checkBox")
self.voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.voiceovers_checkBox.setGeometry(QtCore.QRect(1000, 650, 191, 16)) self.voiceovers_checkBox.setGeometry(QtCore.QRect(810, 820, 191, 16))
font = QtGui.QFont() font = QtGui.QFont()
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.logistics_crates_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.logistics_crates_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.logistics_crates_checkBox.setGeometry(QtCore.QRect(970, 390, 251, 31)) self.logistics_crates_checkBox.setGeometry(QtCore.QRect(920, 320, 251, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setPointSize(11)
self.logistics_crates_checkBox.setFont(font) self.logistics_crates_checkBox.setFont(font)
self.logistics_crates_checkBox.setChecked(True)
self.logistics_crates_checkBox.setObjectName("logistics_crates_checkBox") self.logistics_crates_checkBox.setObjectName("logistics_crates_checkBox")
self.awacs_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.awacs_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.awacs_checkBox.setGeometry(QtCore.QRect(970, 420, 251, 31)) self.awacs_checkBox.setGeometry(QtCore.QRect(920, 350, 251, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setPointSize(11)
self.awacs_checkBox.setFont(font) self.awacs_checkBox.setFont(font)
@ -142,34 +143,27 @@ class Ui_MainWindow(object):
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(970, 450, 251, 31)) self.tankers_checkBox.setGeometry(QtCore.QRect(920, 380, 251, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setPointSize(11)
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.apcs_spawn_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.apcs_spawn_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(500, 400, 251, 31)) self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(470, 400, 251, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(10) font.setPointSize(10)
self.apcs_spawn_checkBox.setFont(font) self.apcs_spawn_checkBox.setFont(font)
self.apcs_spawn_checkBox.setObjectName("apcs_spawn_checkBox") self.apcs_spawn_checkBox.setObjectName("apcs_spawn_checkBox")
self.inf_spawn_spinBox = QtWidgets.QSpinBox(self.centralwidget) self.inf_spawn_spinBox = QtWidgets.QSpinBox(self.centralwidget)
self.inf_spawn_spinBox.setGeometry(QtCore.QRect(710, 360, 71, 31)) self.inf_spawn_spinBox.setGeometry(QtCore.QRect(680, 360, 71, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(12) font.setPointSize(12)
self.inf_spawn_spinBox.setFont(font) self.inf_spawn_spinBox.setFont(font)
self.inf_spawn_spinBox.setMinimum(0) self.inf_spawn_spinBox.setMinimum(0)
self.inf_spawn_spinBox.setMaximum(50) self.inf_spawn_spinBox.setMaximum(20)
self.inf_spawn_spinBox.setProperty("value", 2) self.inf_spawn_spinBox.setProperty("value", 2)
self.inf_spawn_spinBox.setObjectName("inf_spawn_spinBox") self.inf_spawn_spinBox.setObjectName("inf_spawn_spinBox")
self.smoke_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.smoke_checkBox.setGeometry(QtCore.QRect(1000, 620, 191, 16))
font = QtGui.QFont()
font.setPointSize(9)
self.smoke_checkBox.setFont(font)
self.smoke_checkBox.setChecked(True)
self.smoke_checkBox.setObjectName("smoke_checkBox")
self.scenario_label_5 = QtWidgets.QLabel(self.centralwidget) self.scenario_label_5 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_5.setGeometry(QtCore.QRect(50, 260, 101, 31)) self.scenario_label_5.setGeometry(QtCore.QRect(50, 260, 101, 31))
font = QtGui.QFont() font = QtGui.QFont()
@ -182,28 +176,28 @@ class Ui_MainWindow(object):
self.forces_hint_label_2.setAlignment(QtCore.Qt.AlignCenter) self.forces_hint_label_2.setAlignment(QtCore.Qt.AlignCenter)
self.forces_hint_label_2.setObjectName("forces_hint_label_2") self.forces_hint_label_2.setObjectName("forces_hint_label_2")
self.label = QtWidgets.QLabel(self.centralwidget) self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(500, 360, 191, 31)) self.label.setGeometry(QtCore.QRect(470, 360, 191, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(10) font.setPointSize(10)
self.label.setFont(font) self.label.setFont(font)
self.label.setObjectName("label") self.label.setObjectName("label")
self.slot_template_comboBox = QtWidgets.QComboBox(self.centralwidget) self.slot_template_comboBox = QtWidgets.QComboBox(self.centralwidget)
self.slot_template_comboBox.setGeometry(QtCore.QRect(870, 700, 291, 31)) self.slot_template_comboBox.setGeometry(QtCore.QRect(870, 640, 291, 31))
self.slot_template_comboBox.setObjectName("slot_template_comboBox") self.slot_template_comboBox.setObjectName("slot_template_comboBox")
self.label_2 = QtWidgets.QLabel(self.centralwidget) self.label_2 = QtWidgets.QLabel(self.centralwidget)
self.label_2.setGeometry(QtCore.QRect(750, 700, 111, 31)) self.label_2.setGeometry(QtCore.QRect(750, 640, 111, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setPointSize(11)
self.label_2.setFont(font) self.label_2.setFont(font)
self.label_2.setObjectName("label_2") self.label_2.setObjectName("label_2")
self.scenario_label_6 = QtWidgets.QLabel(self.centralwidget) self.scenario_label_6 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_6.setGeometry(QtCore.QRect(500, 320, 141, 31)) self.scenario_label_6.setGeometry(QtCore.QRect(470, 320, 141, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setPointSize(11)
self.scenario_label_6.setFont(font) self.scenario_label_6.setFont(font)
self.scenario_label_6.setObjectName("scenario_label_6") self.scenario_label_6.setObjectName("scenario_label_6")
self.force_offroad_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.force_offroad_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.force_offroad_checkBox.setGeometry(QtCore.QRect(1000, 560, 191, 16)) self.force_offroad_checkBox.setGeometry(QtCore.QRect(810, 760, 191, 16))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(9) font.setPointSize(9)
self.force_offroad_checkBox.setFont(font) self.force_offroad_checkBox.setFont(font)
@ -222,17 +216,17 @@ class Ui_MainWindow(object):
font.setPointSize(12) font.setPointSize(12)
self.e_attack_helos_spinBox.setFont(font) self.e_attack_helos_spinBox.setFont(font)
self.e_attack_helos_spinBox.setMinimum(0) self.e_attack_helos_spinBox.setMinimum(0)
self.e_attack_helos_spinBox.setMaximum(50) self.e_attack_helos_spinBox.setMaximum(8)
self.e_attack_helos_spinBox.setProperty("value", 2) self.e_attack_helos_spinBox.setProperty("value", 2)
self.e_attack_helos_spinBox.setObjectName("e_attack_helos_spinBox") self.e_attack_helos_spinBox.setObjectName("e_attack_helos_spinBox")
self.scenario_label_7 = QtWidgets.QLabel(self.centralwidget) self.scenario_label_7 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_7.setGeometry(QtCore.QRect(140, 330, 231, 31)) self.scenario_label_7.setGeometry(QtCore.QRect(140, 330, 211, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setPointSize(11)
self.scenario_label_7.setFont(font) self.scenario_label_7.setFont(font)
self.scenario_label_7.setObjectName("scenario_label_7") self.scenario_label_7.setObjectName("scenario_label_7")
self.scenario_label_8 = QtWidgets.QLabel(self.centralwidget) self.scenario_label_8 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_8.setGeometry(QtCore.QRect(140, 370, 231, 31)) self.scenario_label_8.setGeometry(QtCore.QRect(140, 370, 201, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setPointSize(11)
self.scenario_label_8.setFont(font) self.scenario_label_8.setFont(font)
@ -243,15 +237,56 @@ class Ui_MainWindow(object):
font.setPointSize(12) font.setPointSize(12)
self.e_attack_planes_spinBox.setFont(font) self.e_attack_planes_spinBox.setFont(font)
self.e_attack_planes_spinBox.setMinimum(0) self.e_attack_planes_spinBox.setMinimum(0)
self.e_attack_planes_spinBox.setMaximum(50) self.e_attack_planes_spinBox.setMaximum(8)
self.e_attack_planes_spinBox.setProperty("value", 1) self.e_attack_planes_spinBox.setProperty("value", 1)
self.e_attack_planes_spinBox.setObjectName("e_attack_planes_spinBox") self.e_attack_planes_spinBox.setObjectName("e_attack_planes_spinBox")
self.zone_sams_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.zone_sams_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.zone_sams_checkBox.setGeometry(QtCore.QRect(970, 480, 201, 31)) self.zone_sams_checkBox.setGeometry(QtCore.QRect(920, 410, 201, 31))
font = QtGui.QFont() font = QtGui.QFont()
font.setPointSize(11) font.setPointSize(11)
self.zone_sams_checkBox.setFont(font) self.zone_sams_checkBox.setFont(font)
self.zone_sams_checkBox.setObjectName("zone_sams_checkBox") self.zone_sams_checkBox.setObjectName("zone_sams_checkBox")
self.scenario_label_9 = QtWidgets.QLabel(self.centralwidget)
self.scenario_label_9.setGeometry(QtCore.QRect(740, 490, 171, 31))
font = QtGui.QFont()
font.setPointSize(10)
self.scenario_label_9.setFont(font)
self.scenario_label_9.setObjectName("scenario_label_9")
self.inf_spawn_voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget)
self.inf_spawn_voiceovers_checkBox.setGeometry(QtCore.QRect(470, 430, 251, 31))
font = QtGui.QFont()
font.setPointSize(10)
self.inf_spawn_voiceovers_checkBox.setFont(font)
self.inf_spawn_voiceovers_checkBox.setChecked(True)
self.inf_spawn_voiceovers_checkBox.setObjectName("inf_spawn_voiceovers_checkBox")
self.farp_never = QtWidgets.QRadioButton(self.centralwidget)
self.farp_never.setGeometry(QtCore.QRect(950, 500, 95, 20))
font = QtGui.QFont()
font.setPointSize(9)
self.farp_never.setFont(font)
self.farp_never.setObjectName("farp_never")
self.farp_buttonGroup = QtWidgets.QButtonGroup(MainWindow)
self.farp_buttonGroup.setObjectName("farp_buttonGroup")
self.farp_buttonGroup.addButton(self.farp_never)
self.farp_gunits = QtWidgets.QRadioButton(self.centralwidget)
self.farp_gunits.setGeometry(QtCore.QRect(950, 530, 221, 21))
font = QtGui.QFont()
font.setPointSize(9)
self.farp_gunits.setFont(font)
self.farp_gunits.setChecked(True)
self.farp_gunits.setObjectName("farp_gunits")
self.farp_buttonGroup.addButton(self.farp_gunits)
self.farp_always = QtWidgets.QRadioButton(self.centralwidget)
self.farp_always.setGeometry(QtCore.QRect(950, 560, 221, 21))
font = QtGui.QFont()
font.setPointSize(9)
self.farp_always.setFont(font)
self.farp_always.setObjectName("farp_always")
self.farp_buttonGroup.addButton(self.farp_always)
self.version_label = QtWidgets.QLabel(self.centralwidget)
self.version_label.setGeometry(QtCore.QRect(920, 840, 241, 21))
self.version_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
self.version_label.setObjectName("version_label")
self.background_label.raise_() self.background_label.raise_()
self.scenario_comboBox.raise_() self.scenario_comboBox.raise_()
self.scenario_label.raise_() self.scenario_label.raise_()
@ -273,7 +308,6 @@ class Ui_MainWindow(object):
self.tankers_checkBox.raise_() self.tankers_checkBox.raise_()
self.apcs_spawn_checkBox.raise_() self.apcs_spawn_checkBox.raise_()
self.inf_spawn_spinBox.raise_() self.inf_spawn_spinBox.raise_()
self.smoke_checkBox.raise_()
self.scenario_label_5.raise_() self.scenario_label_5.raise_()
self.forces_hint_label_2.raise_() self.forces_hint_label_2.raise_()
self.label.raise_() self.label.raise_()
@ -287,6 +321,12 @@ class Ui_MainWindow(object):
self.scenario_label_8.raise_() self.scenario_label_8.raise_()
self.e_attack_planes_spinBox.raise_() self.e_attack_planes_spinBox.raise_()
self.zone_sams_checkBox.raise_() self.zone_sams_checkBox.raise_()
self.scenario_label_9.raise_()
self.inf_spawn_voiceovers_checkBox.raise_()
self.farp_never.raise_()
self.farp_gunits.raise_()
self.farp_always.raise_()
self.version_label.raise_()
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, 1209, 26)) self.menubar.setGeometry(QtCore.QRect(0, 0, 1209, 26))
@ -334,15 +374,13 @@ class Ui_MainWindow(object):
self.game_status_checkBox.setText(_translate("MainWindow", "Game Status Display")) self.game_status_checkBox.setText(_translate("MainWindow", "Game Status Display"))
self.voiceovers_checkBox.setStatusTip(_translate("MainWindow", "Voiceovers from the ground commander. Helps keep focus on the active zone.")) self.voiceovers_checkBox.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.logistics_crates_checkBox.setStatusTip(_translate("MainWindow", "Enable CTLD logistics crates for building ground units and air defenses.")) self.logistics_crates_checkBox.setStatusTip(_translate("MainWindow", "Enable CTLD logistics crates for building ground units and air defenses. Pickup logistics containers to create new logistics sites."))
self.logistics_crates_checkBox.setText(_translate("MainWindow", "Logistics Crates")) self.logistics_crates_checkBox.setText(_translate("MainWindow", "Logistics"))
self.awacs_checkBox.setText(_translate("MainWindow", "Friendly AWACS")) self.awacs_checkBox.setText(_translate("MainWindow", "Friendly AWACS"))
self.tankers_checkBox.setText(_translate("MainWindow", "Friendly Tankers")) self.tankers_checkBox.setText(_translate("MainWindow", "Friendly Tankers"))
self.apcs_spawn_checkBox.setStatusTip(_translate("MainWindow", "Friendly/enemy APCs will drop infantry when reaching a new conflict zone.")) self.apcs_spawn_checkBox.setStatusTip(_translate("MainWindow", "Friendly/enemy APCs will drop infantry when reaching a new conflict zone."))
self.apcs_spawn_checkBox.setText(_translate("MainWindow", "APCs Spawn Infantry")) self.apcs_spawn_checkBox.setText(_translate("MainWindow", "APCs Spawn Infantry"))
self.inf_spawn_spinBox.setStatusTip(_translate("MainWindow", "This value is multiplied by the number of spawn zones in the mission template.")) self.inf_spawn_spinBox.setStatusTip(_translate("MainWindow", "This value is multiplied by the number of spawn zones in the mission template."))
self.smoke_checkBox.setStatusTip(_translate("MainWindow", "Not yet implemented."))
self.smoke_checkBox.setText(_translate("MainWindow", "Smoke Active Zone"))
self.scenario_label_5.setText(_translate("MainWindow", "Groups Per Zone")) self.scenario_label_5.setText(_translate("MainWindow", "Groups Per Zone"))
self.forces_hint_label_2.setText(_translate("MainWindow", "Forces templates are .miz files in \'Generator/Forces\'")) self.forces_hint_label_2.setText(_translate("MainWindow", "Forces templates are .miz files in \'Generator/Forces\'"))
self.label.setText(_translate("MainWindow", "Infantry Groups per zone:")) self.label.setText(_translate("MainWindow", "Infantry Groups per zone:"))
@ -358,6 +396,16 @@ class Ui_MainWindow(object):
self.e_attack_planes_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack plane group spawns.")) self.e_attack_planes_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack plane group spawns."))
self.zone_sams_checkBox.setStatusTip(_translate("MainWindow", "Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed.")) self.zone_sams_checkBox.setStatusTip(_translate("MainWindow", "Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed."))
self.zone_sams_checkBox.setText(_translate("MainWindow", "Inactive Zone SAMs")) self.zone_sams_checkBox.setText(_translate("MainWindow", "Inactive Zone SAMs"))
self.scenario_label_9.setText(_translate("MainWindow", "Zone FARP Conditions:"))
self.inf_spawn_voiceovers_checkBox.setStatusTip(_translate("MainWindow", "Friendly/enemy APCs will drop infantry when reaching a new conflict zone."))
self.inf_spawn_voiceovers_checkBox.setText(_translate("MainWindow", "Voiceovers on Infantry Spawn"))
self.farp_never.setStatusTip(_translate("MainWindow", "Never spawn FARPs in defeated conflict zones."))
self.farp_never.setText(_translate("MainWindow", "Never"))
self.farp_gunits.setStatusTip(_translate("MainWindow", "Only spawn FARPs in defeated conflict zones if we have sufficient ground units remaining."))
self.farp_gunits.setText(_translate("MainWindow", "20% Ground Units Remaining"))
self.farp_always.setStatusTip(_translate("MainWindow", "Always spawn a FARP in defeated conflict zones."))
self.farp_always.setText(_translate("MainWindow", "Always"))
self.version_label.setText(_translate("MainWindow", "Version string"))
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"))

View File

@ -183,8 +183,8 @@ p, li { white-space: pre-wrap; }
<widget class="QLabel" name="background_label"> <widget class="QLabel" name="background_label">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>-30</x> <x>-40</x>
<y>490</y> <y>440</y>
<width>801</width> <width>801</width>
<height>371</height> <height>371</height>
</rect> </rect>
@ -255,7 +255,7 @@ p, li { white-space: pre-wrap; }
<number>0</number> <number>0</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>50</number> <number>8</number>
</property> </property>
<property name="value"> <property name="value">
<number>3</number> <number>3</number>
@ -282,7 +282,7 @@ p, li { white-space: pre-wrap; }
<number>0</number> <number>0</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>50</number> <number>8</number>
</property> </property>
<property name="value"> <property name="value">
<number>2</number> <number>2</number>
@ -312,8 +312,8 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="game_status_checkBox"> <widget class="QCheckBox" name="game_status_checkBox">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>1000</x> <x>810</x>
<y>590</y> <y>790</y>
<width>191</width> <width>191</width>
<height>16</height> <height>16</height>
</rect> </rect>
@ -339,8 +339,8 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="voiceovers_checkBox"> <widget class="QCheckBox" name="voiceovers_checkBox">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>1000</x> <x>810</x>
<y>650</y> <y>820</y>
<width>191</width> <width>191</width>
<height>16</height> <height>16</height>
</rect> </rect>
@ -363,8 +363,8 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="logistics_crates_checkBox"> <widget class="QCheckBox" name="logistics_crates_checkBox">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>970</x> <x>920</x>
<y>390</y> <y>320</y>
<width>251</width> <width>251</width>
<height>31</height> <height>31</height>
</rect> </rect>
@ -375,17 +375,20 @@ p, li { white-space: pre-wrap; }
</font> </font>
</property> </property>
<property name="statusTip"> <property name="statusTip">
<string>Enable CTLD logistics crates for building ground units and air defenses.</string> <string>Enable CTLD logistics crates for building ground units and air defenses. Pickup logistics containers to create new logistics sites.</string>
</property> </property>
<property name="text"> <property name="text">
<string>Logistics Crates</string> <string>Logistics</string>
</property>
<property name="checked">
<bool>true</bool>
</property> </property>
</widget> </widget>
<widget class="QCheckBox" name="awacs_checkBox"> <widget class="QCheckBox" name="awacs_checkBox">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>970</x> <x>920</x>
<y>420</y> <y>350</y>
<width>251</width> <width>251</width>
<height>31</height> <height>31</height>
</rect> </rect>
@ -408,8 +411,8 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="tankers_checkBox"> <widget class="QCheckBox" name="tankers_checkBox">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>970</x> <x>920</x>
<y>450</y> <y>380</y>
<width>251</width> <width>251</width>
<height>31</height> <height>31</height>
</rect> </rect>
@ -429,7 +432,7 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="apcs_spawn_checkBox"> <widget class="QCheckBox" name="apcs_spawn_checkBox">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>500</x> <x>470</x>
<y>400</y> <y>400</y>
<width>251</width> <width>251</width>
<height>31</height> <height>31</height>
@ -450,7 +453,7 @@ p, li { white-space: pre-wrap; }
<widget class="QSpinBox" name="inf_spawn_spinBox"> <widget class="QSpinBox" name="inf_spawn_spinBox">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>710</x> <x>680</x>
<y>360</y> <y>360</y>
<width>71</width> <width>71</width>
<height>31</height> <height>31</height>
@ -468,36 +471,12 @@ p, li { white-space: pre-wrap; }
<number>0</number> <number>0</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>50</number> <number>20</number>
</property> </property>
<property name="value"> <property name="value">
<number>2</number> <number>2</number>
</property> </property>
</widget> </widget>
<widget class="QCheckBox" name="smoke_checkBox">
<property name="geometry">
<rect>
<x>1000</x>
<y>620</y>
<width>191</width>
<height>16</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="statusTip">
<string>Not yet implemented.</string>
</property>
<property name="text">
<string>Smoke Active Zone</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QLabel" name="scenario_label_5"> <widget class="QLabel" name="scenario_label_5">
<property name="geometry"> <property name="geometry">
<rect> <rect>
@ -538,7 +517,7 @@ p, li { white-space: pre-wrap; }
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>500</x> <x>470</x>
<y>360</y> <y>360</y>
<width>191</width> <width>191</width>
<height>31</height> <height>31</height>
@ -557,7 +536,7 @@ p, li { white-space: pre-wrap; }
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>870</x> <x>870</x>
<y>700</y> <y>640</y>
<width>291</width> <width>291</width>
<height>31</height> <height>31</height>
</rect> </rect>
@ -570,7 +549,7 @@ p, li { white-space: pre-wrap; }
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>750</x> <x>750</x>
<y>700</y> <y>640</y>
<width>111</width> <width>111</width>
<height>31</height> <height>31</height>
</rect> </rect>
@ -587,7 +566,7 @@ p, li { white-space: pre-wrap; }
<widget class="QLabel" name="scenario_label_6"> <widget class="QLabel" name="scenario_label_6">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>500</x> <x>470</x>
<y>320</y> <y>320</y>
<width>141</width> <width>141</width>
<height>31</height> <height>31</height>
@ -605,8 +584,8 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="force_offroad_checkBox"> <widget class="QCheckBox" name="force_offroad_checkBox">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>1000</x> <x>810</x>
<y>560</y> <y>760</y>
<width>191</width> <width>191</width>
<height>16</height> <height>16</height>
</rect> </rect>
@ -668,7 +647,7 @@ p, li { white-space: pre-wrap; }
<number>0</number> <number>0</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>50</number> <number>8</number>
</property> </property>
<property name="value"> <property name="value">
<number>2</number> <number>2</number>
@ -679,7 +658,7 @@ p, li { white-space: pre-wrap; }
<rect> <rect>
<x>140</x> <x>140</x>
<y>330</y> <y>330</y>
<width>231</width> <width>211</width>
<height>31</height> <height>31</height>
</rect> </rect>
</property> </property>
@ -697,7 +676,7 @@ p, li { white-space: pre-wrap; }
<rect> <rect>
<x>140</x> <x>140</x>
<y>370</y> <y>370</y>
<width>231</width> <width>201</width>
<height>31</height> <height>31</height>
</rect> </rect>
</property> </property>
@ -731,7 +710,7 @@ p, li { white-space: pre-wrap; }
<number>0</number> <number>0</number>
</property> </property>
<property name="maximum"> <property name="maximum">
<number>50</number> <number>8</number>
</property> </property>
<property name="value"> <property name="value">
<number>1</number> <number>1</number>
@ -740,8 +719,8 @@ p, li { white-space: pre-wrap; }
<widget class="QCheckBox" name="zone_sams_checkBox"> <widget class="QCheckBox" name="zone_sams_checkBox">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>970</x> <x>920</x>
<y>480</y> <y>410</y>
<width>201</width> <width>201</width>
<height>31</height> <height>31</height>
</rect> </rect>
@ -758,6 +737,139 @@ p, li { white-space: pre-wrap; }
<string>Inactive Zone SAMs</string> <string>Inactive Zone SAMs</string>
</property> </property>
</widget> </widget>
<widget class="QLabel" name="scenario_label_9">
<property name="geometry">
<rect>
<x>740</x>
<y>490</y>
<width>171</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="text">
<string>Zone FARP Conditions:</string>
</property>
</widget>
<widget class="QCheckBox" name="inf_spawn_voiceovers_checkBox">
<property name="geometry">
<rect>
<x>470</x>
<y>430</y>
<width>251</width>
<height>31</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>10</pointsize>
</font>
</property>
<property name="statusTip">
<string>Friendly/enemy APCs will drop infantry when reaching a new conflict zone.</string>
</property>
<property name="text">
<string>Voiceovers on Infantry Spawn</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
</widget>
<widget class="QRadioButton" name="farp_never">
<property name="geometry">
<rect>
<x>950</x>
<y>500</y>
<width>95</width>
<height>20</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="statusTip">
<string>Never spawn FARPs in defeated conflict zones.</string>
</property>
<property name="text">
<string>Never</string>
</property>
<attribute name="buttonGroup">
<string notr="true">farp_buttonGroup</string>
</attribute>
</widget>
<widget class="QRadioButton" name="farp_gunits">
<property name="geometry">
<rect>
<x>950</x>
<y>530</y>
<width>221</width>
<height>21</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="statusTip">
<string>Only spawn FARPs in defeated conflict zones if we have sufficient ground units remaining.</string>
</property>
<property name="text">
<string>20% Ground Units Remaining</string>
</property>
<property name="checked">
<bool>true</bool>
</property>
<attribute name="buttonGroup">
<string notr="true">farp_buttonGroup</string>
</attribute>
</widget>
<widget class="QRadioButton" name="farp_always">
<property name="geometry">
<rect>
<x>950</x>
<y>560</y>
<width>221</width>
<height>21</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>9</pointsize>
</font>
</property>
<property name="statusTip">
<string>Always spawn a FARP in defeated conflict zones.</string>
</property>
<property name="text">
<string>Always</string>
</property>
<attribute name="buttonGroup">
<string notr="true">farp_buttonGroup</string>
</attribute>
</widget>
<widget class="QLabel" name="version_label">
<property name="geometry">
<rect>
<x>920</x>
<y>840</y>
<width>241</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Version string</string>
</property>
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
</widget>
<zorder>background_label</zorder> <zorder>background_label</zorder>
<zorder>scenario_comboBox</zorder> <zorder>scenario_comboBox</zorder>
<zorder>scenario_label</zorder> <zorder>scenario_label</zorder>
@ -779,7 +891,6 @@ p, li { white-space: pre-wrap; }
<zorder>tankers_checkBox</zorder> <zorder>tankers_checkBox</zorder>
<zorder>apcs_spawn_checkBox</zorder> <zorder>apcs_spawn_checkBox</zorder>
<zorder>inf_spawn_spinBox</zorder> <zorder>inf_spawn_spinBox</zorder>
<zorder>smoke_checkBox</zorder>
<zorder>scenario_label_5</zorder> <zorder>scenario_label_5</zorder>
<zorder>forces_hint_label_2</zorder> <zorder>forces_hint_label_2</zorder>
<zorder>label</zorder> <zorder>label</zorder>
@ -793,6 +904,12 @@ p, li { white-space: pre-wrap; }
<zorder>scenario_label_8</zorder> <zorder>scenario_label_8</zorder>
<zorder>e_attack_planes_spinBox</zorder> <zorder>e_attack_planes_spinBox</zorder>
<zorder>zone_sams_checkBox</zorder> <zorder>zone_sams_checkBox</zorder>
<zorder>scenario_label_9</zorder>
<zorder>inf_spawn_voiceovers_checkBox</zorder>
<zorder>farp_never</zorder>
<zorder>farp_gunits</zorder>
<zorder>farp_always</zorder>
<zorder>version_label</zorder>
</widget> </widget>
<widget class="QMenuBar" name="menubar"> <widget class="QMenuBar" name="menubar">
<property name="geometry"> <property name="geometry">
@ -865,4 +982,7 @@ p, li { white-space: pre-wrap; }
</hints> </hints>
</connection> </connection>
</connections> </connections>
<buttongroups>
<buttongroup name="farp_buttonGroup"/>
</buttongroups>
</ui> </ui>

116
Generator/RotorOpsGroups.py Normal file
View File

@ -0,0 +1,116 @@
from dcs.countries import Russia, USA
import dcs.unit as unit
from dcs.mission import Mission
import dcs.mapping as mapping
import dcs.ships
import dcs.vehicles
import dcs.statics
import dcs.unit
import random
class VehicleTemplate:
class USA:
@staticmethod
def invisible_farp(mission, country, position, heading, name, late_activation):
farp = mission.farp(country, name, position, hidden=False, dead=False, farp_type=dcs.unit.InvisibleFARP)
vg = mission.vehicle_group_platoon(
country,
name,
[
dcs.vehicles.Unarmed.M_818,
dcs.vehicles.AirDefence.Vulcan,
dcs.vehicles.Unarmed.Ural_375
],
position.point_from_heading(45, 7),
heading=random.randint(0, 359),
formation=dcs.unitgroup.VehicleGroup.Formation.Star,
)
vg.late_activation = late_activation
return vg
@staticmethod
def logistics_site(mission, country, position, heading, prefix=""):
farp = mission.farp(country, "Logistics FARP", position, hidden=False, dead=False, farp_type=dcs.unit.InvisibleFARP)
sg = mission.static_group(
country,
prefix + " Logistics",
dcs.statics.Fortification.TV_tower,
position.point_from_heading(heading, 80),
heading
)
dist_from_center = 30
for i in range(1,4):
u = mission.static("logistic" + str(i), dcs.statics.Cargo.Iso_container_small)
u.position = position.point_from_heading(heading + 90, dist_from_center + (i * 15))
u.heading = 10
sg.add_unit(u)
for i in range(5,8):
u = mission.static("logistic" + str(i), dcs.statics.Cargo.Iso_container_small)
u.position = position.point_from_heading(heading + 270, dist_from_center + (i * 15))
u.heading = 10
sg.add_unit(u)
a_pos = position.point_from_heading(heading + 180, dist_from_center)
u = mission.static("Ammo Dump", dcs.statics.Fortification.FARP_Ammo_Dump_Coating)
u.position = a_pos.point_from_heading(heading + 90, 1)
u.heading = heading
sg.add_unit(u)
u = mission.static("FARP Tent", dcs.statics.Fortification.FARP_Tent)
u.position = a_pos.point_from_heading(heading + 90, dist_from_center + 20)
u.heading = heading
sg.add_unit(u)
u = mission.static("Fuel Depot", dcs.statics.Fortification.FARP_Fuel_Depot)
u.position = a_pos.point_from_heading(heading + 90, dist_from_center + 40)
u.heading = heading
sg.add_unit(u)
return sg
@staticmethod
def sa6_site(mission, country, position, heading, prefix="", skill=unit.Skill.Average):
vg = mission.vehicle_group(
country,
prefix + "SA6 site",
dcs.vehicles.AirDefence.Kub_1S91_str,
position,
heading
)
u = mission.vehicle("Launcher 1", dcs.vehicles.AirDefence.Kub_2P25_ln)
u.position = position.point_from_heading(heading + 140, 30)
u.heading = heading
vg.add_unit(u)
u = mission.vehicle("Launcher 2", dcs.vehicles.AirDefence.Kub_2P25_ln)
u.position = position.point_from_heading(heading + 210, 30)
u.heading = heading
vg.add_unit(u)
u = mission.vehicle("Rearm Truck", dcs.vehicles.Unarmed.Ural_375)
u.position = position.point_from_heading(heading + 0, 40)
u.heading = heading
vg.add_unit(u)
for u in vg.units:
u.skill = skill
return vg

View File

@ -3,6 +3,8 @@ from tokenize import String
import dcs import dcs
import os import os
import random import random
import RotorOpsGroups
import RotorOpsUnits import RotorOpsUnits
import time import time
@ -119,9 +121,6 @@ class RotorOpsMission:
elif zone.name.rfind("SPAWN") >= 0: elif zone.name.rfind("SPAWN") >= 0:
self.addZone(self.spawn_zones, self.RotorOpsZone(zone.name, None, zone.position, zone.radius)) self.addZone(self.spawn_zones, self.RotorOpsZone(zone.name, None, zone.position, zone.radius))
#add files and triggers necessary for RotorOps.lua script
self.addResources(self.sound_directory, self.script_directory)
self.scriptTriggerSetup(options)
blue_zones = self.staging_zones blue_zones = self.staging_zones
red_zones = self.conflict_zones red_zones = self.conflict_zones
@ -137,16 +136,21 @@ class RotorOpsMission:
self.m.terrain.airports[airport_name].set_blue() self.m.terrain.airports[airport_name].set_blue()
#Add red ground units #Populate Red zones with ground units
for zone_name in red_zones: for zone_name in red_zones:
if red_forces: if red_forces:
self.addGroundGroups(red_zones[zone_name], self.m.country('Russia'), red_forces, options["red_quantity"]) self.addGroundGroups(red_zones[zone_name], self.m.country('Russia'), red_forces, options["red_quantity"])
if options["zone_protect_sams"]: #Add blue FARPS
for zone_name in red_zones: if options["zone_farps"] != "farp_never" and not options["defending"]:
RotorOpsGroups.VehicleTemplate.USA.invisible_farp(self.m, self.m.country('USA'),
red_zones[zone_name].position,
180, zone_name + " FARP", late_activation=True)
if options["zone_protect_sams"]:
self.m.vehicle_group( self.m.vehicle_group(
self.m.country('Russia'), self.m.country('Russia'),
zone_name + " Protection SAM NOAI", "Static " + zone_name + " Protection SAM",
random.choice(RotorOpsUnits.e_zone_sams), random.choice(RotorOpsUnits.e_zone_sams),
red_zones[zone_name].position, red_zones[zone_name].position,
heading=random.randint(0, 359), heading=random.randint(0, 359),
@ -154,17 +158,28 @@ class RotorOpsMission:
formation=dcs.unitgroup.VehicleGroup.Formation.Star formation=dcs.unitgroup.VehicleGroup.Formation.Star
) )
#Add blue ground units
#Populate Blue zones with ground units
for zone_name in blue_zones: for zone_name in blue_zones:
if blue_forces: if blue_forces:
self.addGroundGroups(blue_zones[zone_name], self.m.country('USA'), blue_forces, self.addGroundGroups(blue_zones[zone_name], self.m.country('USA'), blue_forces,
options["blue_quantity"]) options["blue_quantity"])
if options["zone_protect_sams"]: #add logistics sites
for zone_name in blue_zones: if options["crates"] and zone_name in self.staging_zones:
self.m.vehicle_group( RotorOpsGroups.VehicleTemplate.USA.logistics_site(self.m, self.m.country('USA'),
blue_zones[zone_name].position,
180, zone_name)
if options["zone_protect_sams"] and options["defending"]:
vg = self.m.vehicle_group(
self.m.country('USA'), self.m.country('USA'),
zone_name + " Protection SAM NOAI", "Static " + zone_name + " Protection SAM",
random.choice(RotorOpsUnits.e_zone_sams), random.choice(RotorOpsUnits.e_zone_sams),
blue_zones[zone_name].position, blue_zones[zone_name].position,
heading=random.randint(0, 359), heading=random.randint(0, 359),
@ -172,6 +187,8 @@ class RotorOpsMission:
formation=dcs.unitgroup.VehicleGroup.Formation.Star formation=dcs.unitgroup.VehicleGroup.Formation.Star
) )
#Add player slots #Add player slots
if options["slots"] == "Multiple Slots": if options["slots"] == "Multiple Slots":
self.addMultiplayerHelos() self.addMultiplayerHelos()
@ -187,6 +204,10 @@ class RotorOpsMission:
self.m.map.position = self.m.terrain.airports[self.getCoalitionAirports("blue")[0]].position self.m.map.position = self.m.terrain.airports[self.getCoalitionAirports("blue")[0]].position
self.m.map.zoom = 100000 self.m.map.zoom = 100000
#add files and triggers necessary for RotorOps.lua script
self.addResources(self.sound_directory, self.script_directory)
self.scriptTriggerSetup(options)
#Save the mission file #Save the mission file
print(self.m.triggers.zones()) print(self.m.triggers.zones())
os.chdir(self.output_dir) os.chdir(self.output_dir)
@ -414,7 +435,7 @@ class RotorOpsMission:
helo, helo,
airport=enemy_airport, airport=enemy_airport,
maintask=dcs.task.CAS, maintask=dcs.task.CAS,
start_type=dcs.mission.StartType.Warm, start_type=dcs.mission.StartType.Cold,
group_size=2) group_size=2)
zone_attack(afg, helo) zone_attack(afg, helo)
@ -424,7 +445,7 @@ class RotorOpsMission:
russia, "Enemy Attack Planes", plane["type"], russia, "Enemy Attack Planes", plane["type"],
airport=enemy_airport, airport=enemy_airport,
maintask=dcs.task.CAS, maintask=dcs.task.CAS,
start_type=dcs.mission.StartType.Warm, start_type=dcs.mission.StartType.Cold,
group_size=2) group_size=2)
zone_attack(afg, plane) zone_attack(afg, plane)
@ -450,6 +471,7 @@ class RotorOpsMission:
"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_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"))))
self.m.triggerrules.triggers.append(trig) self.m.triggerrules.triggers.append(trig)
@ -473,23 +495,50 @@ class RotorOpsMission:
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.startConflict(100)"))) trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.startConflict(100)")))
self.m.triggerrules.triggers.append(trig) self.m.triggerrules.triggers.append(trig)
#Add all zone-based triggers #Add generic zone-based triggers
for index, zone_name in enumerate(self.conflict_zones): for index, zone_name in enumerate(self.conflict_zones):
z_active_trig = dcs.triggers.TriggerOnce(comment= zone_name + " Active") z_active_trig = dcs.triggers.TriggerOnce(comment= zone_name + " Active")
z_active_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1)) z_active_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_active_trig.actions.append(dcs.action.DoScript(dcs.action.String("--Add any action you want here!"))) z_active_trig.actions.append(dcs.action.DoScript(dcs.action.String("--Add any action you want here!")))
#Smoke action not working
# if options["smoke_zone"]:
# z_active_trig.actions.append(dcs.action.Smoke(zone=zone_name, density=1, preset=1))
# if index > 0:
# previous_zone = list(self.conflict_zones)[index - 1]
# z_active_trig.actions.append(dcs.action.Smoke(zone=previous_zone, density=1, preset=0))
#Zone protection SAMs
if options["zone_protect_sams"]:
z_active_trig.actions.append(dcs.action.DoScript(dcs.action.String("Group.destroy(Group.getByName('" + zone_name + " Protection SAM'))")))
self.m.triggerrules.triggers.append(z_active_trig) self.m.triggerrules.triggers.append(z_active_trig)
#Zone protection SAMs
if options["zone_protect_sams"]:
for index, zone_name in enumerate(self.conflict_zones):
z_sams_trig = dcs.triggers.TriggerOnce(comment="Deactivate " + zone_name + " SAMs")
z_sams_trig.actions.append(dcs.action.DoScript(dcs.action.String("Group.destroy(Group.getByName('" + zone_name + " Protection SAM'))")))
self.m.triggerrules.triggers.append(z_sams_trig)
#Zone FARPS always
if options["zone_farps"] == "farp_always" and not options["defending"] and index > 0:
for index, zone_name in enumerate(self.conflict_zones):
if index > 0:
previous_zone = list(self.conflict_zones)[index - 1]
if not self.m.country("USA").find_group(previous_zone + " FARP"):
continue
z_farps_trig = dcs.triggers.TriggerOnce(comment="Activate " + previous_zone + " FARP")
z_farps_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_farps_trig.actions.append(dcs.action.ActivateGroup(self.m.country("USA").find_group(previous_zone + " FARP").id))
self.m.triggerrules.triggers.append(z_farps_trig)
#Zone FARPS conditional on staged units remaining
if options["zone_farps"] == "farp_gunits":
for index, zone_name in enumerate(self.conflict_zones):
if index > 0:
previous_zone = list(self.conflict_zones)[index - 1]
if not self.m.country("USA").find_group(previous_zone + " FARP"):
continue
z_farps_trig = dcs.triggers.TriggerOnce(comment= "Activate " + previous_zone + " FARP")
z_farps_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_farps_trig.rules.append(dcs.condition.FlagIsMore(111, 20))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String("--The 100 flag indicates which zone is active. The 111 flag value is the percentage of staged units remaining")))
z_farps_trig.actions.append(
dcs.action.ActivateGroup(self.m.country("USA").find_group(previous_zone + " FARP").id))
self.m.triggerrules.triggers.append(z_farps_trig)
#Add attack helos triggers #Add attack helos triggers
for index in range(options["e_attack_helos"]): for index in range(options["e_attack_helos"]):
random_zone_obj = random.choice(list(self.conflict_zones.items())) random_zone_obj = random.choice(list(self.conflict_zones.items()))

View File

@ -21,6 +21,9 @@ Optional:
Tips: Tips:
-Position the center of conflict zones over an open area, as this position may be used to spawn units. -Position the center of conflict zones over an open area, as this position may be used to spawn units.
-Position the center of staging zones over an open area of at least 1000 x 1000ft to provide space for logistics units.
Position the center of staging zones over an open area of at least 1000 x 1000ft to provide space for logistics units.
-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. -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. -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. -Keep the zones fairly close together, both for helicopter and ground unit travel times.

Binary file not shown.

View File

@ -1,28 +1,65 @@
# What is RotorOps? # What is RotorOps?
RotorOps brings the ground war in DCS to life. Infantry becomes useful, and the helicopter operations that support them will directly contribute to the success of the mission. 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 fun territory capture game that promotes focus on individual 'conflict zones'.
RotorOps is a DCS script that makes it easy to create fun and engaging missions on the fly, directly in the mission editor and without ever opening a script file.
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://raw.githubusercontent.com/spencershepard/RotorOps/develop/documentation/images/rotorops%ss%200_3.png?raw=true)
# Key Features:
- Unique helicopter-focused gameplay
- Mission Generator windows app
- Over 100 built-in voiceovers (or for use in mission customization via trigger actions).
- Splash Damage 2 script for more realistic explosions that no longer require direct hits.
- CTLD troop and logistics transport automatically integrated and enhanced with sound effects.
- Play the role of the attacking or defending force.
- Single-player and multiplayer slot creation.
## Demo Missions ## Demo Missions
RotorOps: Aleppo Under Siege https://www.digitalcombatsimulator.com/en/files/3320079/ RotorOps: Aleppo Under Siege https://www.digitalcombatsimulator.com/en/files/3320079/
Rota Landing (Mr. Nobody) https://www.digitalcombatsimulator.com/en/files/3320186/
# RotorOps: Conflict # RotorOps: Conflict
At the heart of this first release is a game type called Conflict, where attacking forces must clear Conflict Zones of defending ground forces. Once a zone is cleared, the next zone is activated and ground vehicles will move to the next Conflict Zone automatically. It's up to the rotorheads to pickup troops from the cleared zones and transport them to the active Conflict Zone. Conflict is a game type in which attacking forces must clear Conflict Zones of defending ground forces. Once a zone is cleared, the next zone is activated and ground vehicles will move to the next Conflict Zone automatically.
![alt text](https://raw.githubusercontent.com/spencershepard/RotorOps/develop/documentation/images/rotorops%20conflict%20zones.png?raw=true) ![alt text](https://raw.githubusercontent.com/spencershepard/RotorOps/develop/documentation/images/rotorops%20conflict%20zones.png?raw=true)
## Dynamic Roles
A RotorOps conflict mission has opportunities for a variety of roles and tasks. There's no need to artificially select these roles, as the mission is fully dynamic.
### Do I have to transport troops? ### Transport Logistics:
This is really up to the mission designer. Transporting troops is not required for mission success in Conflict. However, friendly troops can be a very valuable asset, especially for clearing enemies in dense urban areas. If you're in a fixed wing or attack helicopter role, troop transport could be provided by other players or AI. CTLD logistics crates are available from your starting base or staging zone. The logistics area has several logistics containers, that can themselves be moved to a new area via DCS inbuilt sling loading. If you can get one of these containers to a new area safely, it becomes a CTLD logistics zone for spawning crates to build ground units and air defenses.
### What about attack helicopters? ### CAS:
The constantly moving infantry is easier to see than the statues we are used to seeing. Destroying defending enemy vehicles so that our troops and vehicles can survive, and intercepting enemy reinforcements may be crucial to mission success. The attacking side starts with ground units that move progressively through enemy conflict zones, seeking out enemy units within each zone. Protecting these ground forces is essential for establishing forward bases for rearming, troop pickup, and winning the battle
### How do I create a Conflict mission? ### Troop Transport:
Just open a demo mission in the DCS mission editor and drop units into the Conflict Zones. These are trigger areas drawn in the mission editor that will automatically control the ground forces that enter them. This means that you do not need to worry about creating waypoints; enemy vehicles and infantry will seek each other out automatically. Move the Conflict Zones or change their size, add friendly or enemy units (remember, no waypoints needed). Never before has infantry been so important in DCS! Pick up troops from the staging area or a cleared conflict zone and deliver them to the active conflict zone. They will move through the zone until no enemies remain (or until they are killed). Very useful for flushing out enemy infantry and vehicles in densely forested or urban areas. JTAC units can mark important targets with smoke and laser.
Optional USER FLAGS are available to trigger events based on the status of individual zones and the game as a whole. Simple DO SCRIPT waypoint actions are available to drop troops from friendly or enemy AI helicopters or ground vehicles. ### Ground Attack:
Destroy enemy vehicles and infantry to ensure the survival of our own ground units. Clearing conflict zones of enemy units is essential for establishing forward bases for rearming and refueling. All enemy ground units must be destroyed to win the battle!
## RotorOps Mission Creator Guide: https://github.com/spencershepard/RotorOps/wiki/RotorOps:-Mission-Creator-Guide ### Fixed-wing CAP/CAS:
Enemy attack helicopters and planes are optional in the generator. Add slots in the mission generator for fixed-wing flights to provide cover for our helicopters and ground units. For a unique challenge, try Defense mode in a fixed-wing ground attack role...enemies are nearly always in motion.
## Mission Generator and Customization
The mission generator works by automatically placing units and trigger actions into a map template with defined airports and trigger zones.
Missions produced by the generator are easy to modify and understand. For example, units can be moved, and player flights can be added without issue. Use the result of the mission generator for quick plays, or build on it for something epic. Trigger actions are set up, labeled, and commented so that you can understand how things work and add your own actions. An additional library of voiceover files is provided for your own use.
Easily add your own templates for friendly/enemy ground units directly in the DCS mission editor.
Create your own scenarios for the RotorOps mission generator, using the DCS mission editor.
### RotorOps Mission Creator Guide:
For more detailed information on how the script works, see this wiki:
https://github.com/spencershepard/RotorOps/wiki/RotorOps:-Mission-Creator-Guide
*** ***
@ -35,7 +72,7 @@ https://discord.gg/HFqjrZV9xD
https://www.patreon.com/spencershepard https://www.patreon.com/spencershepard
### Developers ### Developers
We welcome contributors to this new project! Please get in touch on Discord with new ideas or pickup/create an issue in this repo. We welcome contributors to this new project! Please get in touch on Discord with new ideas or pickup/create an issue in this repo.
*** ***
@ -44,3 +81,7 @@ RotorOps uses MIST and integrates CTLD:
https://github.com/mrSkortch/MissionScriptingTools https://github.com/mrSkortch/MissionScriptingTools
https://github.com/ciribob/DCS-CTLD https://github.com/ciribob/DCS-CTLD
The mission generator would not be possible without PyDCS:
https://github.com/pydcs/dcs

View File

@ -1,6 +1,6 @@
RotorOps = {} RotorOps = {}
RotorOps.version = "1.2.4" RotorOps.version = "1.2.5"
local debug = false local debug = true
---[[ROTOROPS OPTIONS]]--- ---[[ROTOROPS OPTIONS]]---
@ -20,13 +20,14 @@ RotorOps.inf_spawns_avail = 0 --this is the number of infantry group spawn event
RotorOps.inf_spawn_chance = 25 -- 0-100 the chance of spawning infantry in an active zone spawn zone, per 'assessUnitsInZone' loop (10 seconds) RotorOps.inf_spawn_chance = 25 -- 0-100 the chance of spawning infantry in an active zone spawn zone, per 'assessUnitsInZone' loop (10 seconds)
RotorOps.inf_spawn_trigger_percent = 70 --infantry has a chance of spawning if the percentage of defenders remaining in zone is less than this value RotorOps.inf_spawn_trigger_percent = 70 --infantry has a chance of spawning if the percentage of defenders remaining in zone is less than this value
RotorOps.inf_spawns_per_zone = 3 --number of infantry groups to spawn per zone RotorOps.inf_spawns_per_zone = 3 --number of infantry groups to spawn per zone
RotorOps.inf_spawn_messages = true --voiceovers and messages for infantry spawns
--RotorOps settings that are safe to change only before calling setupConflict() --RotorOps settings that are safe to change only before calling setupConflict()
RotorOps.transports = {'UH-1H', 'Mi-8MT', 'Mi-24P', 'SA342M', 'SA342L', 'SA342Mistral', 'UH-60L'} --players flying these will have ctld transport access RotorOps.transports = {'UH-1H', 'Mi-8MT', 'Mi-24P', 'SA342M', 'SA342L', 'SA342Mistral', 'UH-60L'} --players flying these will have ctld transport access
RotorOps.CTLD_crates = false 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 = "noai" --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
---[[END OF OPTIONS]]--- ---[[END OF OPTIONS]]---
@ -49,6 +50,7 @@ RotorOps.ai_defending_vehicle_groups = {}
RotorOps.ai_attacking_vehicle_groups = {} RotorOps.ai_attacking_vehicle_groups = {}
RotorOps.ai_tasks = {} RotorOps.ai_tasks = {}
RotorOps.defending = false RotorOps.defending = false
RotorOps.staged_units_flag = 111
trigger.action.outText("ROTOR OPS STARTED: "..RotorOps.version, 5) trigger.action.outText("ROTOR OPS STARTED: "..RotorOps.version, 5)
env.info("ROTOR OPS STARTED: "..RotorOps.version) env.info("ROTOR OPS STARTED: "..RotorOps.version)
@ -58,10 +60,14 @@ RotorOps.eventHandler = {}
local commandDB = {} local commandDB = {}
local game_message_buffer = {} local game_message_buffer = {}
local active_zone_initial_defenders local active_zone_initial_defenders
local initial_stage_units
local apcs = {} --table to keep track of infantry vehicles local apcs = {} --table to keep track of infantry vehicles
local low_units_message_fired = false local low_units_message_fired = false
local inf_spawn_zones = {} local inf_spawn_zones = {}
local cooldown = {
["attack_helo_msg"] = 0,
["attack_plane_msg"] = 0,
}
RotorOps.gameMsgs = { RotorOps.gameMsgs = {
@ -144,6 +150,20 @@ RotorOps.gameMsgs = {
attack_planes = { attack_planes = {
{'ENEMY ATTACK PLANES INBOUND!', 'enemy_attack_planes.ogg'}, {'ENEMY ATTACK PLANES INBOUND!', 'enemy_attack_planes.ogg'},
}, },
attack_helos_prep = {
{'ENEMY ATTACK HELICOPTERS PREPARING FOR TAKEOFF!', 'e_attack_helicopters_preparing.ogg'},
},
attack_planes_prep = {
{'ENEMY ATTACK PLANES PREPARING FOR TAKEOFF!', 'e_attack_planes_preparing.ogg'},
},
infantry_spawned = {
{'ENEMY CONTACTS IN THE OPEN!', 'e_infantry_spawn1.ogg'},
{'ENEMY TROOPS LEAVING COVER!', 'e_infantry_spawn2.ogg'},
{'VISUAL ON ENEMY INFANTRY!', 'e_infantry_spawn3.ogg'},
{'ENEMY CONTACTS IN THE ACTIVE!', 'e_infantry_spawn4.ogg'},
{'ENEMY TROOPS IN THE ACTIVE!', 'e_infantry_spawn5.ogg'},
{'VISUAL ON ENEMY TROOPS!', 'e_infantry_spawn6.ogg'},
},
} }
@ -154,15 +174,53 @@ local sound_effects = {
["troop_dropoff"] = {'troops_unload_thanks.ogg', 'troops_unload_everybody_off.ogg', 'troops_unload_get_off.ogg', 'troops_unload_here_we_go.ogg', 'troops_unload_moving_out.ogg',}, ["troop_dropoff"] = {'troops_unload_thanks.ogg', 'troops_unload_everybody_off.ogg', 'troops_unload_get_off.ogg', 'troops_unload_here_we_go.ogg', 'troops_unload_moving_out.ogg',},
} }
function RotorOps.getTime()
return timer.getAbsTime() - timer.getTime0() --time since mission started
end
function RotorOps.eventHandler:onEvent(event) function RotorOps.eventHandler:onEvent(event)
if (world.event.S_EVENT_ENGINE_STARTUP == event.id) then --play some sound files when a player starts engines ---ENGINE STARTUP EVENTS
local initaitor = event.initiator:getGroup():getID() if (world.event.S_EVENT_ENGINE_STARTUP == event.id) then --play some sound files when a player starts engines
if RotorOps.defending then local initiator = event.initiator:getGroup():getID()
trigger.action.outSoundForGroup(initaitor , RotorOps.gameMsgs.enemy_pushing[RotorOps.active_zone_index + 1][2])
else 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)
trigger.action.outSoundForGroup(initaitor , RotorOps.gameMsgs.push[RotorOps.active_zone_index + 1][2]) if RotorOps.defending then
trigger.action.outSoundForGroup(initiator , RotorOps.gameMsgs.enemy_pushing[RotorOps.active_zone_index + 1][2])
else
trigger.action.outSoundForGroup(initiator , RotorOps.gameMsgs.push[RotorOps.active_zone_index + 1][2])
end
end end
end end
---TAKEOFF EVENTS
if (world.event.S_EVENT_TAKEOFF == event.id) then
local initiator_name = event.initiator:getGroup():getName()
if (initiator_name == "Enemy Attack Helicopters") then
--we use flights of two aircraft which triggers two events, but we only want to use one event so we use a cooldown timer
if ((RotorOps.getTime() - cooldown["attack_helo_msg"]) > 90) then
RotorOps.gameMsg(RotorOps.gameMsgs.attack_helos)
cooldown["attack_helo_msg"] = RotorOps.getTime()
else
env.warning("RotorOps attack helo message skipped")
end
end
if initiator_name == "Enemy Attack Planes" then
if ((RotorOps.getTime() - cooldown["attack_plane_msg"]) > 90) then
RotorOps.gameMsg(RotorOps.gameMsgs.attack_planes)
cooldown["attack_plane_msg"] = RotorOps.getTime()
else
env.warning("RotorOps attack plane message skipped")
end
end
end
end end
@ -507,7 +565,12 @@ function RotorOps.chargeEnemy(vars)
if vars.zone then ---mist getUnitsInZones method if vars.zone then ---mist getUnitsInZones method
local units_in_zone = mist.getUnitsInZones(mist.makeUnitTable({'[red][vehicle]'}), {vars.zone}, "spherical") local units_in_zone
if enemy_coal == 1 then
units_in_zone = mist.getUnitsInZones(mist.makeUnitTable({'[red][vehicle]'}), {vars.zone}, "spherical")
elseif enemy_coal == 2 then
units_in_zone = mist.getUnitsInZones(mist.makeUnitTable({'[blue][vehicle]'}), {vars.zone}, "spherical")
end
local closest_dist = 10000 local closest_dist = 10000
local closest_unit local closest_unit
for index, unit in pairs(units_in_zone) do for index, unit in pairs(units_in_zone) do
@ -872,6 +935,19 @@ function RotorOps.assessUnitsInZone(var)
end end
end end
--update staged units remaining flag
local staged_units_remaining = {}
for index, unit in pairs(RotorOps.staged_units) do
if unit:isExist() then
staged_units_remaining[#staged_units_remaining + 1] = unit
end
end
local percent_staged_remain = 0
percent_staged_remain = math.floor((#staged_units_remaining / #RotorOps.staged_units) * 100)
trigger.action.setUserFlag(RotorOps.staged_units_flag, percent_staged_remain)
debugMsg("Staged units remaining: "..percent_staged_remain.."%")
--is the game finished? --is the game finished?
if all_zones_clear then if all_zones_clear then
if RotorOps.defending == true then if RotorOps.defending == true then
@ -956,8 +1032,9 @@ function RotorOps.assessUnitsInZone(var)
ctld.spawnGroupAtTrigger("blue", 5, zone, 1000) ctld.spawnGroupAtTrigger("blue", 5, zone, 1000)
else else
ctld.spawnGroupAtTrigger("red", 5, zone, 1000) ctld.spawnGroupAtTrigger("red", 5, zone, 1000)
RotorOps.gameMsg(RotorOps.gameMsgs.infantry_spawned, math.random(1, #RotorOps.gameMsgs.infantry_spawned))
end end
RotorOps.inf_spawns_avail = RotorOps.inf_spawns_avail - 1 RotorOps.inf_spawns_avail = RotorOps.inf_spawns_avail - 1
env.info("ROTOR OPS: Spawned infantry. "..RotorOps.inf_spawns_avail.." spawns remaining in "..zone) env.info("ROTOR OPS: Spawned infantry. "..RotorOps.inf_spawns_avail.." spawns remaining in "..zone)
end end
@ -1126,6 +1203,11 @@ function RotorOps.setupCTLD()
ctld.numberOfTroops = 24 --max loading size ctld.numberOfTroops = 24 --max loading size
ctld.maximumSearchDistance = 4000 -- max distance for troops to search for enemy ctld.maximumSearchDistance = 4000 -- max distance for troops to search for enemy
ctld.maximumMoveDistance = 0 -- max distance for troops to move from drop point if no enemy is nearby ctld.maximumMoveDistance = 0 -- max distance for troops to move from drop point if no enemy is nearby
ctld.maximumDistanceLogistic = 300
ctld.minimumHoverHeight = 5.0 -- Lowest allowable height for crate hover
ctld.maximumHoverHeight = 15.0 -- Highest allowable height for crate hover
ctld.maxDistanceFromCrate = 7 -- Maximum distance from from crate for hover
ctld.hoverTime = 5 -- Time to hold hover above a crate for loading in seconds
ctld.unitLoadLimits = { ctld.unitLoadLimits = {
-- Remove the -- below to turn on options -- Remove the -- below to turn on options
@ -1269,12 +1351,12 @@ end
function RotorOps.spawnAttackHelos() function RotorOps.spawnAttackHelos()
RotorOps.triggerSpawn("Enemy Attack Helicopters", RotorOps.gameMsgs.attack_helos) RotorOps.triggerSpawn("Enemy Attack Helicopters", RotorOps.gameMsgs.attack_helos_prep)
end end
function RotorOps.spawnAttackPlanes() function RotorOps.spawnAttackPlanes()
RotorOps.triggerSpawn("Enemy Attack Planes", RotorOps.gameMsgs.attack_planes) RotorOps.triggerSpawn("Enemy Attack Planes", RotorOps.gameMsgs.attack_planes_prep)
end end

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 MiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.