diff --git a/Generator/Forces/red/RED Default Armor.miz b/Generator/Forces/red/RED Armor (Hard).miz similarity index 100% rename from Generator/Forces/red/RED Default Armor.miz rename to Generator/Forces/red/RED Armor (Hard).miz diff --git a/Generator/Forces/red/RED Armor, Infantry & Artillery (Med).miz b/Generator/Forces/red/RED Armor, Infantry & Artillery (Med).miz new file mode 100644 index 0000000..fa4ada1 Binary files /dev/null and b/Generator/Forces/red/RED Armor, Infantry & Artillery (Med).miz differ diff --git a/Generator/Forces/red/RED Default Mixed.miz b/Generator/Forces/red/RED Default Mixed.miz deleted file mode 100644 index 59cb155..0000000 Binary files a/Generator/Forces/red/RED Default Mixed.miz and /dev/null differ diff --git a/Generator/Forces/red/RED Trucks & Infantry (Easy).miz b/Generator/Forces/red/RED Trucks & Infantry (Easy).miz new file mode 100644 index 0000000..85e75b8 Binary files /dev/null and b/Generator/Forces/red/RED Trucks & Infantry (Easy).miz differ diff --git a/Generator/MissionGenerator.py b/Generator/MissionGenerator.py index 242cde4..b9d8367 100644 --- a/Generator/MissionGenerator.py +++ b/Generator/MissionGenerator.py @@ -13,6 +13,9 @@ from PyQt5.QtWidgets import ( from PyQt5 import QtGui from MissionGeneratorUI import Ui_MainWindow +maj_version = 0 +minor_version = 3 +version_string = str(maj_version) + "." + str(minor_version) scenarios = [] red_forces_files = [] blue_forces_files = [] @@ -43,6 +46,8 @@ class Window(QMainWindow, Ui_MainWindow): self.statusbar.setStyleSheet( "QStatusBar{padding-left:5px;color:black;font-weight:bold;}") + self.version_label.setText("Version " + version_string) + def connectSignalsSlots(self): # self.action_Exit.triggered.connect(self.close) @@ -155,14 +160,14 @@ class Window(QMainWindow, Ui_MainWindow): "crates": self.logistics_crates_checkBox.isChecked(), "f_awacs": self.awacs_checkBox.isChecked(), "f_tankers": self.tankers_checkBox.isChecked(), - "smoke_zone": self.smoke_checkBox.isChecked(), "voiceovers": self.voiceovers_checkBox.isChecked(), "force_offroad": self.force_offroad_checkBox.isChecked(), "game_display": self.game_status_checkBox.isChecked(), "defending": self.defense_checkBox.isChecked(), "slots": self.slot_template_comboBox.currentText(), - "smoke_zone": self.smoke_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') n = ROps.RotorOpsMission() diff --git a/Generator/MissionGeneratorUI.py b/Generator/MissionGeneratorUI.py index d1f8dda..a318da0 100644 --- a/Generator/MissionGeneratorUI.py +++ b/Generator/MissionGeneratorUI.py @@ -73,7 +73,7 @@ class Ui_MainWindow(object): self.redforces_comboBox.setGeometry(QtCore.QRect(170, 230, 291, 31)) self.redforces_comboBox.setObjectName("redforces_comboBox") self.background_label = QtWidgets.QLabel(self.centralwidget) - self.background_label.setGeometry(QtCore.QRect(-30, 490, 801, 371)) + self.background_label.setGeometry(QtCore.QRect(-40, 440, 801, 371)) self.background_label.setAutoFillBackground(False) self.background_label.setStyleSheet("") self.background_label.setText("") @@ -93,7 +93,7 @@ class Ui_MainWindow(object): font.setPointSize(12) self.blueqty_spinBox.setFont(font) self.blueqty_spinBox.setMinimum(0) - self.blueqty_spinBox.setMaximum(50) + self.blueqty_spinBox.setMaximum(8) self.blueqty_spinBox.setProperty("value", 3) self.blueqty_spinBox.setObjectName("blueqty_spinBox") self.redqty_spinBox = QtWidgets.QSpinBox(self.centralwidget) @@ -102,7 +102,7 @@ class Ui_MainWindow(object): font.setPointSize(12) self.redqty_spinBox.setFont(font) self.redqty_spinBox.setMinimum(0) - self.redqty_spinBox.setMaximum(50) + self.redqty_spinBox.setMaximum(8) self.redqty_spinBox.setProperty("value", 2) self.redqty_spinBox.setObjectName("redqty_spinBox") self.scenario_label_4 = QtWidgets.QLabel(self.centralwidget) @@ -113,7 +113,7 @@ class Ui_MainWindow(object): self.scenario_label_4.setAlignment(QtCore.Qt.AlignCenter) self.scenario_label_4.setObjectName("scenario_label_4") self.game_status_checkBox = QtWidgets.QCheckBox(self.centralwidget) - self.game_status_checkBox.setGeometry(QtCore.QRect(1000, 590, 191, 16)) + self.game_status_checkBox.setGeometry(QtCore.QRect(810, 790, 191, 16)) font = QtGui.QFont() font.setPointSize(9) self.game_status_checkBox.setFont(font) @@ -121,20 +121,21 @@ class Ui_MainWindow(object): self.game_status_checkBox.setTristate(False) self.game_status_checkBox.setObjectName("game_status_checkBox") self.voiceovers_checkBox = QtWidgets.QCheckBox(self.centralwidget) - self.voiceovers_checkBox.setGeometry(QtCore.QRect(1000, 650, 191, 16)) + self.voiceovers_checkBox.setGeometry(QtCore.QRect(810, 820, 191, 16)) font = QtGui.QFont() font.setPointSize(9) self.voiceovers_checkBox.setFont(font) self.voiceovers_checkBox.setChecked(True) self.voiceovers_checkBox.setObjectName("voiceovers_checkBox") self.logistics_crates_checkBox = QtWidgets.QCheckBox(self.centralwidget) - self.logistics_crates_checkBox.setGeometry(QtCore.QRect(970, 390, 251, 31)) + self.logistics_crates_checkBox.setGeometry(QtCore.QRect(920, 320, 251, 31)) font = QtGui.QFont() font.setPointSize(11) self.logistics_crates_checkBox.setFont(font) + self.logistics_crates_checkBox.setChecked(True) self.logistics_crates_checkBox.setObjectName("logistics_crates_checkBox") self.awacs_checkBox = QtWidgets.QCheckBox(self.centralwidget) - self.awacs_checkBox.setGeometry(QtCore.QRect(970, 420, 251, 31)) + self.awacs_checkBox.setGeometry(QtCore.QRect(920, 350, 251, 31)) font = QtGui.QFont() font.setPointSize(11) self.awacs_checkBox.setFont(font) @@ -142,34 +143,27 @@ class Ui_MainWindow(object): self.awacs_checkBox.setChecked(True) self.awacs_checkBox.setObjectName("awacs_checkBox") self.tankers_checkBox = QtWidgets.QCheckBox(self.centralwidget) - self.tankers_checkBox.setGeometry(QtCore.QRect(970, 450, 251, 31)) + self.tankers_checkBox.setGeometry(QtCore.QRect(920, 380, 251, 31)) font = QtGui.QFont() font.setPointSize(11) self.tankers_checkBox.setFont(font) self.tankers_checkBox.setChecked(True) self.tankers_checkBox.setObjectName("tankers_checkBox") self.apcs_spawn_checkBox = QtWidgets.QCheckBox(self.centralwidget) - self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(500, 400, 251, 31)) + self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(470, 400, 251, 31)) font = QtGui.QFont() font.setPointSize(10) self.apcs_spawn_checkBox.setFont(font) self.apcs_spawn_checkBox.setObjectName("apcs_spawn_checkBox") 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.setPointSize(12) self.inf_spawn_spinBox.setFont(font) 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.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.setGeometry(QtCore.QRect(50, 260, 101, 31)) 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.setObjectName("forces_hint_label_2") 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.setPointSize(10) self.label.setFont(font) self.label.setObjectName("label") self.slot_template_comboBox = QtWidgets.QComboBox(self.centralwidget) - self.slot_template_comboBox.setGeometry(QtCore.QRect(870, 700, 291, 31)) + self.slot_template_comboBox.setGeometry(QtCore.QRect(870, 640, 291, 31)) self.slot_template_comboBox.setObjectName("slot_template_comboBox") self.label_2 = QtWidgets.QLabel(self.centralwidget) - self.label_2.setGeometry(QtCore.QRect(750, 700, 111, 31)) + self.label_2.setGeometry(QtCore.QRect(750, 640, 111, 31)) font = QtGui.QFont() font.setPointSize(11) self.label_2.setFont(font) self.label_2.setObjectName("label_2") 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.setPointSize(11) self.scenario_label_6.setFont(font) self.scenario_label_6.setObjectName("scenario_label_6") 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.setPointSize(9) self.force_offroad_checkBox.setFont(font) @@ -222,17 +216,17 @@ class Ui_MainWindow(object): font.setPointSize(12) self.e_attack_helos_spinBox.setFont(font) 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.setObjectName("e_attack_helos_spinBox") 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.setPointSize(11) self.scenario_label_7.setFont(font) self.scenario_label_7.setObjectName("scenario_label_7") self.scenario_label_8 = QtWidgets.QLabel(self.centralwidget) - self.scenario_label_8.setGeometry(QtCore.QRect(140, 370, 231, 31)) + self.scenario_label_8.setGeometry(QtCore.QRect(140, 370, 201, 31)) font = QtGui.QFont() font.setPointSize(11) self.scenario_label_8.setFont(font) @@ -243,15 +237,56 @@ class Ui_MainWindow(object): font.setPointSize(12) self.e_attack_planes_spinBox.setFont(font) 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.setObjectName("e_attack_planes_spinBox") 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.setPointSize(11) self.zone_sams_checkBox.setFont(font) 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.scenario_comboBox.raise_() self.scenario_label.raise_() @@ -273,7 +308,6 @@ class Ui_MainWindow(object): self.tankers_checkBox.raise_() self.apcs_spawn_checkBox.raise_() self.inf_spawn_spinBox.raise_() - self.smoke_checkBox.raise_() self.scenario_label_5.raise_() self.forces_hint_label_2.raise_() self.label.raise_() @@ -287,6 +321,12 @@ class Ui_MainWindow(object): self.scenario_label_8.raise_() self.e_attack_planes_spinBox.raise_() self.zone_sams_checkBox.raise_() + self.scenario_label_9.raise_() + self.inf_spawn_voiceovers_checkBox.raise_() + self.farp_never.raise_() + self.farp_gunits.raise_() + self.farp_always.raise_() + self.version_label.raise_() MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) 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.voiceovers_checkBox.setStatusTip(_translate("MainWindow", "Voiceovers from the ground commander. Helps keep focus on the active zone.")) self.voiceovers_checkBox.setText(_translate("MainWindow", "Voiceovers")) - self.logistics_crates_checkBox.setStatusTip(_translate("MainWindow", "Enable CTLD logistics crates for building ground units and air defenses.")) - self.logistics_crates_checkBox.setText(_translate("MainWindow", "Logistics Crates")) + self.logistics_crates_checkBox.setStatusTip(_translate("MainWindow", "Enable CTLD logistics crates for building ground units and air defenses. Pickup logistics containers to create new logistics sites.")) + self.logistics_crates_checkBox.setText(_translate("MainWindow", "Logistics")) self.awacs_checkBox.setText(_translate("MainWindow", "Friendly AWACS")) self.tankers_checkBox.setText(_translate("MainWindow", "Friendly Tankers")) self.apcs_spawn_checkBox.setStatusTip(_translate("MainWindow", "Friendly/enemy APCs will drop infantry when reaching a new conflict zone.")) 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.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.forces_hint_label_2.setText(_translate("MainWindow", "Forces templates are .miz files in \'Generator/Forces\'")) 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.zone_sams_checkBox.setStatusTip(_translate("MainWindow", "Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed.")) self.zone_sams_checkBox.setText(_translate("MainWindow", "Inactive Zone SAMs")) + self.scenario_label_9.setText(_translate("MainWindow", "Zone FARP Conditions:")) + self.inf_spawn_voiceovers_checkBox.setStatusTip(_translate("MainWindow", "Friendly/enemy APCs will drop infantry when reaching a new conflict zone.")) + self.inf_spawn_voiceovers_checkBox.setText(_translate("MainWindow", "Voiceovers on Infantry Spawn")) + self.farp_never.setStatusTip(_translate("MainWindow", "Never spawn FARPs in defeated conflict zones.")) + self.farp_never.setText(_translate("MainWindow", "Never")) + self.farp_gunits.setStatusTip(_translate("MainWindow", "Only spawn FARPs in defeated conflict zones if we have sufficient ground units remaining.")) + self.farp_gunits.setText(_translate("MainWindow", "20% Ground Units Remaining")) + self.farp_always.setStatusTip(_translate("MainWindow", "Always spawn a FARP in defeated conflict zones.")) + self.farp_always.setText(_translate("MainWindow", "Always")) + self.version_label.setText(_translate("MainWindow", "Version string")) self.action_generateMission.setText(_translate("MainWindow", "_generateMission")) self.action_scenarioSelected.setText(_translate("MainWindow", "_scenarioSelected")) self.action_blueforcesSelected.setText(_translate("MainWindow", "_blueforcesSelected")) diff --git a/Generator/MissionGeneratorUI.ui b/Generator/MissionGeneratorUI.ui index 3c32722..7838cc9 100644 --- a/Generator/MissionGeneratorUI.ui +++ b/Generator/MissionGeneratorUI.ui @@ -183,8 +183,8 @@ p, li { white-space: pre-wrap; } - -30 - 490 + -40 + 440 801 371 @@ -255,7 +255,7 @@ p, li { white-space: pre-wrap; } 0 - 50 + 8 3 @@ -282,7 +282,7 @@ p, li { white-space: pre-wrap; } 0 - 50 + 8 2 @@ -312,8 +312,8 @@ p, li { white-space: pre-wrap; } - 1000 - 590 + 810 + 790 191 16 @@ -339,8 +339,8 @@ p, li { white-space: pre-wrap; } - 1000 - 650 + 810 + 820 191 16 @@ -363,8 +363,8 @@ p, li { white-space: pre-wrap; } - 970 - 390 + 920 + 320 251 31 @@ -375,17 +375,20 @@ p, li { white-space: pre-wrap; } - Enable CTLD logistics crates for building ground units and air defenses. + Enable CTLD logistics crates for building ground units and air defenses. Pickup logistics containers to create new logistics sites. - Logistics Crates + Logistics + + + true - 970 - 420 + 920 + 350 251 31 @@ -408,8 +411,8 @@ p, li { white-space: pre-wrap; } - 970 - 450 + 920 + 380 251 31 @@ -429,7 +432,7 @@ p, li { white-space: pre-wrap; } - 500 + 470 400 251 31 @@ -450,7 +453,7 @@ p, li { white-space: pre-wrap; } - 710 + 680 360 71 31 @@ -468,36 +471,12 @@ p, li { white-space: pre-wrap; } 0 - 50 + 20 2 - - - - 1000 - 620 - 191 - 16 - - - - - 9 - - - - Not yet implemented. - - - Smoke Active Zone - - - true - - @@ -538,7 +517,7 @@ p, li { white-space: pre-wrap; } - 500 + 470 360 191 31 @@ -557,7 +536,7 @@ p, li { white-space: pre-wrap; } 870 - 700 + 640 291 31 @@ -570,7 +549,7 @@ p, li { white-space: pre-wrap; } 750 - 700 + 640 111 31 @@ -587,7 +566,7 @@ p, li { white-space: pre-wrap; } - 500 + 470 320 141 31 @@ -605,8 +584,8 @@ p, li { white-space: pre-wrap; } - 1000 - 560 + 810 + 760 191 16 @@ -668,7 +647,7 @@ p, li { white-space: pre-wrap; } 0 - 50 + 8 2 @@ -679,7 +658,7 @@ p, li { white-space: pre-wrap; } 140 330 - 231 + 211 31 @@ -697,7 +676,7 @@ p, li { white-space: pre-wrap; } 140 370 - 231 + 201 31 @@ -731,7 +710,7 @@ p, li { white-space: pre-wrap; } 0 - 50 + 8 1 @@ -740,8 +719,8 @@ p, li { white-space: pre-wrap; } - 970 - 480 + 920 + 410 201 31 @@ -758,6 +737,139 @@ p, li { white-space: pre-wrap; } Inactive Zone SAMs + + + + 740 + 490 + 171 + 31 + + + + + 10 + + + + Zone FARP Conditions: + + + + + + 470 + 430 + 251 + 31 + + + + + 10 + + + + Friendly/enemy APCs will drop infantry when reaching a new conflict zone. + + + Voiceovers on Infantry Spawn + + + true + + + + + + 950 + 500 + 95 + 20 + + + + + 9 + + + + Never spawn FARPs in defeated conflict zones. + + + Never + + + farp_buttonGroup + + + + + + 950 + 530 + 221 + 21 + + + + + 9 + + + + Only spawn FARPs in defeated conflict zones if we have sufficient ground units remaining. + + + 20% Ground Units Remaining + + + true + + + farp_buttonGroup + + + + + + 950 + 560 + 221 + 21 + + + + + 9 + + + + Always spawn a FARP in defeated conflict zones. + + + Always + + + farp_buttonGroup + + + + + + 920 + 840 + 241 + 21 + + + + Version string + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + background_label scenario_comboBox scenario_label @@ -779,7 +891,6 @@ p, li { white-space: pre-wrap; } tankers_checkBox apcs_spawn_checkBox inf_spawn_spinBox - smoke_checkBox scenario_label_5 forces_hint_label_2 label @@ -793,6 +904,12 @@ p, li { white-space: pre-wrap; } scenario_label_8 e_attack_planes_spinBox zone_sams_checkBox + scenario_label_9 + inf_spawn_voiceovers_checkBox + farp_never + farp_gunits + farp_always + version_label @@ -865,4 +982,7 @@ p, li { white-space: pre-wrap; } + + + diff --git a/Generator/RotorOpsGroups.py b/Generator/RotorOpsGroups.py new file mode 100644 index 0000000..a9f125d --- /dev/null +++ b/Generator/RotorOpsGroups.py @@ -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 diff --git a/Generator/RotorOpsMission.py b/Generator/RotorOpsMission.py index 0478d58..880a8c0 100644 --- a/Generator/RotorOpsMission.py +++ b/Generator/RotorOpsMission.py @@ -3,6 +3,8 @@ from tokenize import String import dcs import os import random + +import RotorOpsGroups import RotorOpsUnits import time @@ -119,9 +121,6 @@ class RotorOpsMission: elif zone.name.rfind("SPAWN") >= 0: 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 red_zones = self.conflict_zones @@ -137,16 +136,21 @@ class RotorOpsMission: self.m.terrain.airports[airport_name].set_blue() - #Add red ground units + #Populate Red zones with ground units for zone_name in red_zones: if red_forces: self.addGroundGroups(red_zones[zone_name], self.m.country('Russia'), red_forces, options["red_quantity"]) - if options["zone_protect_sams"]: - for zone_name in red_zones: + #Add blue FARPS + 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.country('Russia'), - zone_name + " Protection SAM NOAI", + "Static " + zone_name + " Protection SAM", random.choice(RotorOpsUnits.e_zone_sams), red_zones[zone_name].position, heading=random.randint(0, 359), @@ -154,17 +158,28 @@ class RotorOpsMission: formation=dcs.unitgroup.VehicleGroup.Formation.Star ) - #Add blue ground units + + + #Populate Blue zones with ground units for zone_name in blue_zones: if blue_forces: self.addGroundGroups(blue_zones[zone_name], self.m.country('USA'), blue_forces, options["blue_quantity"]) - if options["zone_protect_sams"]: - for zone_name in blue_zones: - self.m.vehicle_group( + #add logistics sites + if options["crates"] and zone_name in self.staging_zones: + 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'), - zone_name + " Protection SAM NOAI", + "Static " + zone_name + " Protection SAM", random.choice(RotorOpsUnits.e_zone_sams), blue_zones[zone_name].position, heading=random.randint(0, 359), @@ -172,6 +187,8 @@ class RotorOpsMission: formation=dcs.unitgroup.VehicleGroup.Formation.Star ) + + #Add player slots if options["slots"] == "Multiple Slots": self.addMultiplayerHelos() @@ -187,6 +204,10 @@ class RotorOpsMission: self.m.map.position = self.m.terrain.airports[self.getCoalitionAirports("blue")[0]].position 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 print(self.m.triggers.zones()) os.chdir(self.output_dir) @@ -414,7 +435,7 @@ class RotorOpsMission: helo, airport=enemy_airport, maintask=dcs.task.CAS, - start_type=dcs.mission.StartType.Warm, + start_type=dcs.mission.StartType.Cold, group_size=2) zone_attack(afg, helo) @@ -424,7 +445,7 @@ class RotorOpsMission: russia, "Enemy Attack Planes", plane["type"], airport=enemy_airport, maintask=dcs.task.CAS, - start_type=dcs.mission.StartType.Warm, + start_type=dcs.mission.StartType.Cold, group_size=2) zone_attack(afg, plane) @@ -450,6 +471,7 @@ class RotorOpsMission: "RotorOps.force_offroad = " + lb("force_offroad") + "\n\n" + "RotorOps.voice_overs = " + lb("voiceovers") + "\n\n" + "RotorOps.zone_status_display = " + lb("game_display") + "\n\n" + + "RotorOps.inf_spawn_messages = " + lb("inf_spawn_msgs") + "\n\n" + "RotorOps.inf_spawns_per_zone = " + lb("inf_spawn_qty") + "\n\n" + "RotorOps.apcs_spawn_infantry = " + lb("apc_spawns_inf") + " \n\n")))) self.m.triggerrules.triggers.append(trig) @@ -473,23 +495,50 @@ class RotorOpsMission: trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.startConflict(100)"))) 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): - z_active_trig = dcs.triggers.TriggerOnce(comment= zone_name + " Active") z_active_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1)) z_active_trig.actions.append(dcs.action.DoScript(dcs.action.String("--Add any action you want here!"))) - #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) + #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 for index in range(options["e_attack_helos"]): random_zone_obj = random.choice(list(self.conflict_zones.items())) diff --git a/Generator/Scenarios/Caucasus Conflict - Batumi to Kobuleti (GRIMM).miz b/Generator/Scenarios/Caucasus Conflict - Batumi to Kobuleti (GRIMM).miz index 78a8300..f44a18e 100644 Binary files a/Generator/Scenarios/Caucasus Conflict - Batumi to Kobuleti (GRIMM).miz and b/Generator/Scenarios/Caucasus Conflict - Batumi to Kobuleti (GRIMM).miz differ diff --git a/Generator/Scenarios/Caucasus Conflict - Nalchik to Beslan (GRIMM).miz b/Generator/Scenarios/Caucasus Conflict - Nalchik to Beslan (GRIMM).miz index 693096c..d55089b 100644 Binary files a/Generator/Scenarios/Caucasus Conflict - Nalchik to Beslan (GRIMM).miz and b/Generator/Scenarios/Caucasus Conflict - Nalchik to Beslan (GRIMM).miz differ diff --git a/Generator/Scenarios/Mariana Conflict - Anderson to Won Pat (GRIMM).miz b/Generator/Scenarios/Mariana Conflict - Anderson to Won Pat (GRIMM).miz index 544c62c..a1bed71 100644 Binary files a/Generator/Scenarios/Mariana Conflict - Anderson to Won Pat (GRIMM).miz and b/Generator/Scenarios/Mariana Conflict - Anderson to Won Pat (GRIMM).miz differ diff --git a/Generator/Scenarios/Nevada Conflict - Vegas Tour (GRIMM).miz b/Generator/Scenarios/Nevada Conflict - Vegas Tour (GRIMM).miz index 4a47022..38828de 100644 Binary files a/Generator/Scenarios/Nevada Conflict - Vegas Tour (GRIMM).miz and b/Generator/Scenarios/Nevada Conflict - Vegas Tour (GRIMM).miz differ diff --git a/Generator/Scenarios/PG Conflict - Abu Dhabi to Ras (GRIMM).miz b/Generator/Scenarios/PG Conflict - Abu Dhabi to Ras (GRIMM).miz index e1e6964..68638fb 100644 Binary files a/Generator/Scenarios/PG Conflict - Abu Dhabi to Ras (GRIMM).miz and b/Generator/Scenarios/PG Conflict - Abu Dhabi to Ras (GRIMM).miz differ diff --git a/Generator/Scenarios/Syria Conflict - Aleppo Tour (GRIMM).miz b/Generator/Scenarios/Syria Conflict - Aleppo Tour (GRIMM).miz index 940a2af..9e3d50d 100644 Binary files a/Generator/Scenarios/Syria Conflict - Aleppo Tour (GRIMM).miz and b/Generator/Scenarios/Syria Conflict - Aleppo Tour (GRIMM).miz differ diff --git a/Generator/Scenarios/_How to create your own scenarios.txt b/Generator/Scenarios/_How to create your own scenarios.txt index 24b9f90..199971a 100644 --- a/Generator/Scenarios/_How to create your own scenarios.txt +++ b/Generator/Scenarios/_How to create your own scenarios.txt @@ -21,6 +21,7 @@ Optional: Tips: -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. -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. diff --git a/MissionGenerator.exe b/MissionGenerator.exe index 9c893ff..cb34568 100644 Binary files a/MissionGenerator.exe and b/MissionGenerator.exe differ diff --git a/RotorOps.lua b/RotorOps.lua index 0e433e8..cd32b31 100644 --- a/RotorOps.lua +++ b/RotorOps.lua @@ -1,6 +1,6 @@ RotorOps = {} -RotorOps.version = "1.2.4" -local debug = false +RotorOps.version = "1.2.5" +local debug = true ---[[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_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_spawn_messages = true --voiceovers and messages for infantry spawns --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.CTLD_crates = false 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]]--- @@ -49,6 +50,7 @@ RotorOps.ai_defending_vehicle_groups = {} RotorOps.ai_attacking_vehicle_groups = {} RotorOps.ai_tasks = {} RotorOps.defending = false +RotorOps.staged_units_flag = 111 trigger.action.outText("ROTOR OPS STARTED: "..RotorOps.version, 5) env.info("ROTOR OPS STARTED: "..RotorOps.version) @@ -58,10 +60,14 @@ RotorOps.eventHandler = {} local commandDB = {} local game_message_buffer = {} local active_zone_initial_defenders +local initial_stage_units local apcs = {} --table to keep track of infantry vehicles local low_units_message_fired = false local inf_spawn_zones = {} - +local cooldown = { + ["attack_helo_msg"] = 0, + ["attack_plane_msg"] = 0, +} RotorOps.gameMsgs = { @@ -144,6 +150,20 @@ RotorOps.gameMsgs = { attack_planes = { {'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',}, } + +function RotorOps.getTime() + return timer.getAbsTime() - timer.getTime0() --time since mission started +end + + + function RotorOps.eventHandler:onEvent(event) - if (world.event.S_EVENT_ENGINE_STARTUP == event.id) then --play some sound files when a player starts engines - local initaitor = event.initiator:getGroup():getID() - if RotorOps.defending then - trigger.action.outSoundForGroup(initaitor , RotorOps.gameMsgs.enemy_pushing[RotorOps.active_zone_index + 1][2]) - else - trigger.action.outSoundForGroup(initaitor , RotorOps.gameMsgs.push[RotorOps.active_zone_index + 1][2]) + ---ENGINE STARTUP EVENTS + 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() + + 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 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 + + ---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 @@ -507,7 +565,12 @@ function RotorOps.chargeEnemy(vars) 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_unit for index, unit in pairs(units_in_zone) do @@ -872,6 +935,19 @@ function RotorOps.assessUnitsInZone(var) 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? if all_zones_clear then if RotorOps.defending == true then @@ -957,7 +1033,7 @@ function RotorOps.assessUnitsInZone(var) else ctld.spawnGroupAtTrigger("red", 5, zone, 1000) end - + RotorOps.gameMsg(RotorOps.gameMsgs.infantry_spawned, math.random(1, #RotorOps.gameMsgs.infantry_spawned)) RotorOps.inf_spawns_avail = RotorOps.inf_spawns_avail - 1 env.info("ROTOR OPS: Spawned infantry. "..RotorOps.inf_spawns_avail.." spawns remaining in "..zone) end @@ -1126,6 +1202,11 @@ function RotorOps.setupCTLD() ctld.numberOfTroops = 24 --max loading size 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.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 = { -- Remove the -- below to turn on options @@ -1269,12 +1350,12 @@ end function RotorOps.spawnAttackHelos() - RotorOps.triggerSpawn("Enemy Attack Helicopters", RotorOps.gameMsgs.attack_helos) + RotorOps.triggerSpawn("Enemy Attack Helicopters", RotorOps.gameMsgs.attack_helos_prep) end function RotorOps.spawnAttackPlanes() - RotorOps.triggerSpawn("Enemy Attack Planes", RotorOps.gameMsgs.attack_planes) + RotorOps.triggerSpawn("Enemy Attack Planes", RotorOps.gameMsgs.attack_planes_prep) end diff --git a/sound/embedded/e_attack_helicopters_preparing.ogg b/sound/embedded/e_attack_helicopters_preparing.ogg new file mode 100644 index 0000000..ee1b892 Binary files /dev/null and b/sound/embedded/e_attack_helicopters_preparing.ogg differ diff --git a/sound/embedded/e_attack_planes_preparing.ogg b/sound/embedded/e_attack_planes_preparing.ogg new file mode 100644 index 0000000..4b2973c Binary files /dev/null and b/sound/embedded/e_attack_planes_preparing.ogg differ diff --git a/sound/embedded/e_infantry_spawn1.ogg b/sound/embedded/e_infantry_spawn1.ogg new file mode 100644 index 0000000..0d0910d Binary files /dev/null and b/sound/embedded/e_infantry_spawn1.ogg differ diff --git a/sound/embedded/e_infantry_spawn2.ogg b/sound/embedded/e_infantry_spawn2.ogg new file mode 100644 index 0000000..8d99dad Binary files /dev/null and b/sound/embedded/e_infantry_spawn2.ogg differ diff --git a/sound/embedded/e_infantry_spawn3.ogg b/sound/embedded/e_infantry_spawn3.ogg new file mode 100644 index 0000000..db9a8c4 Binary files /dev/null and b/sound/embedded/e_infantry_spawn3.ogg differ diff --git a/sound/embedded/e_infantry_spawn4.ogg b/sound/embedded/e_infantry_spawn4.ogg new file mode 100644 index 0000000..393b834 Binary files /dev/null and b/sound/embedded/e_infantry_spawn4.ogg differ diff --git a/sound/embedded/e_infantry_spawn5.ogg b/sound/embedded/e_infantry_spawn5.ogg new file mode 100644 index 0000000..8000000 Binary files /dev/null and b/sound/embedded/e_infantry_spawn5.ogg differ diff --git a/sound/embedded/e_infantry_spawn6.ogg b/sound/embedded/e_infantry_spawn6.ogg new file mode 100644 index 0000000..8e0693d Binary files /dev/null and b/sound/embedded/e_infantry_spawn6.ogg differ