mirror of
https://github.com/spencershepard/RotorOps.git
synced 2025-11-10 15:45:30 +00:00
Merge pull request #19 from spencershepard/feature/progressive_farps_and_logistics
Feature/progressive farps and logistics
This commit is contained in:
commit
3299d937d4
BIN
Generator/Forces/red/RED Armor, Infantry & Artillery (Med).miz
Normal file
BIN
Generator/Forces/red/RED Armor, Infantry & Artillery (Med).miz
Normal file
Binary file not shown.
Binary file not shown.
BIN
Generator/Forces/red/RED Trucks & Infantry (Easy).miz
Normal file
BIN
Generator/Forces/red/RED Trucks & Infantry (Easy).miz
Normal file
Binary file not shown.
@ -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()
|
||||
|
||||
@ -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"))
|
||||
|
||||
@ -183,8 +183,8 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QLabel" name="background_label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>-30</x>
|
||||
<y>490</y>
|
||||
<x>-40</x>
|
||||
<y>440</y>
|
||||
<width>801</width>
|
||||
<height>371</height>
|
||||
</rect>
|
||||
@ -255,7 +255,7 @@ p, li { white-space: pre-wrap; }
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>50</number>
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>3</number>
|
||||
@ -282,7 +282,7 @@ p, li { white-space: pre-wrap; }
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>50</number>
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
@ -312,8 +312,8 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QCheckBox" name="game_status_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>1000</x>
|
||||
<y>590</y>
|
||||
<x>810</x>
|
||||
<y>790</y>
|
||||
<width>191</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -339,8 +339,8 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QCheckBox" name="voiceovers_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>1000</x>
|
||||
<y>650</y>
|
||||
<x>810</x>
|
||||
<y>820</y>
|
||||
<width>191</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -363,8 +363,8 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QCheckBox" name="logistics_crates_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>970</x>
|
||||
<y>390</y>
|
||||
<x>920</x>
|
||||
<y>320</y>
|
||||
<width>251</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
@ -375,17 +375,20 @@ p, li { white-space: pre-wrap; }
|
||||
</font>
|
||||
</property>
|
||||
<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 name="text">
|
||||
<string>Logistics Crates</string>
|
||||
<string>Logistics</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="awacs_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>970</x>
|
||||
<y>420</y>
|
||||
<x>920</x>
|
||||
<y>350</y>
|
||||
<width>251</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
@ -408,8 +411,8 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QCheckBox" name="tankers_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>970</x>
|
||||
<y>450</y>
|
||||
<x>920</x>
|
||||
<y>380</y>
|
||||
<width>251</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
@ -429,7 +432,7 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QCheckBox" name="apcs_spawn_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<x>470</x>
|
||||
<y>400</y>
|
||||
<width>251</width>
|
||||
<height>31</height>
|
||||
@ -450,7 +453,7 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QSpinBox" name="inf_spawn_spinBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>710</x>
|
||||
<x>680</x>
|
||||
<y>360</y>
|
||||
<width>71</width>
|
||||
<height>31</height>
|
||||
@ -468,36 +471,12 @@ p, li { white-space: pre-wrap; }
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>50</number>
|
||||
<number>20</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</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">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
@ -538,7 +517,7 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<x>470</x>
|
||||
<y>360</y>
|
||||
<width>191</width>
|
||||
<height>31</height>
|
||||
@ -557,7 +536,7 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>870</x>
|
||||
<y>700</y>
|
||||
<y>640</y>
|
||||
<width>291</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
@ -570,7 +549,7 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>750</x>
|
||||
<y>700</y>
|
||||
<y>640</y>
|
||||
<width>111</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
@ -587,7 +566,7 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QLabel" name="scenario_label_6">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>500</x>
|
||||
<x>470</x>
|
||||
<y>320</y>
|
||||
<width>141</width>
|
||||
<height>31</height>
|
||||
@ -605,8 +584,8 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QCheckBox" name="force_offroad_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>1000</x>
|
||||
<y>560</y>
|
||||
<x>810</x>
|
||||
<y>760</y>
|
||||
<width>191</width>
|
||||
<height>16</height>
|
||||
</rect>
|
||||
@ -668,7 +647,7 @@ p, li { white-space: pre-wrap; }
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>50</number>
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>2</number>
|
||||
@ -679,7 +658,7 @@ p, li { white-space: pre-wrap; }
|
||||
<rect>
|
||||
<x>140</x>
|
||||
<y>330</y>
|
||||
<width>231</width>
|
||||
<width>211</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -697,7 +676,7 @@ p, li { white-space: pre-wrap; }
|
||||
<rect>
|
||||
<x>140</x>
|
||||
<y>370</y>
|
||||
<width>231</width>
|
||||
<width>201</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -731,7 +710,7 @@ p, li { white-space: pre-wrap; }
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>50</number>
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
@ -740,8 +719,8 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QCheckBox" name="zone_sams_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>970</x>
|
||||
<y>480</y>
|
||||
<x>920</x>
|
||||
<y>410</y>
|
||||
<width>201</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
@ -758,6 +737,139 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Inactive Zone SAMs</string>
|
||||
</property>
|
||||
</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>scenario_comboBox</zorder>
|
||||
<zorder>scenario_label</zorder>
|
||||
@ -779,7 +891,6 @@ p, li { white-space: pre-wrap; }
|
||||
<zorder>tankers_checkBox</zorder>
|
||||
<zorder>apcs_spawn_checkBox</zorder>
|
||||
<zorder>inf_spawn_spinBox</zorder>
|
||||
<zorder>smoke_checkBox</zorder>
|
||||
<zorder>scenario_label_5</zorder>
|
||||
<zorder>forces_hint_label_2</zorder>
|
||||
<zorder>label</zorder>
|
||||
@ -793,6 +904,12 @@ p, li { white-space: pre-wrap; }
|
||||
<zorder>scenario_label_8</zorder>
|
||||
<zorder>e_attack_planes_spinBox</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 class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
@ -865,4 +982,7 @@ p, li { white-space: pre-wrap; }
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="farp_buttonGroup"/>
|
||||
</buttongroups>
|
||||
</ui>
|
||||
|
||||
116
Generator/RotorOpsGroups.py
Normal file
116
Generator/RotorOpsGroups.py
Normal 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
|
||||
@ -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()))
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -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.
|
||||
|
||||
Binary file not shown.
109
RotorOps.lua
109
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
|
||||
|
||||
|
||||
|
||||
BIN
sound/embedded/e_attack_helicopters_preparing.ogg
Normal file
BIN
sound/embedded/e_attack_helicopters_preparing.ogg
Normal file
Binary file not shown.
BIN
sound/embedded/e_attack_planes_preparing.ogg
Normal file
BIN
sound/embedded/e_attack_planes_preparing.ogg
Normal file
Binary file not shown.
BIN
sound/embedded/e_infantry_spawn1.ogg
Normal file
BIN
sound/embedded/e_infantry_spawn1.ogg
Normal file
Binary file not shown.
BIN
sound/embedded/e_infantry_spawn2.ogg
Normal file
BIN
sound/embedded/e_infantry_spawn2.ogg
Normal file
Binary file not shown.
BIN
sound/embedded/e_infantry_spawn3.ogg
Normal file
BIN
sound/embedded/e_infantry_spawn3.ogg
Normal file
Binary file not shown.
BIN
sound/embedded/e_infantry_spawn4.ogg
Normal file
BIN
sound/embedded/e_infantry_spawn4.ogg
Normal file
Binary file not shown.
BIN
sound/embedded/e_infantry_spawn5.ogg
Normal file
BIN
sound/embedded/e_infantry_spawn5.ogg
Normal file
Binary file not shown.
BIN
sound/embedded/e_infantry_spawn6.ogg
Normal file
BIN
sound/embedded/e_infantry_spawn6.ogg
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user