mirror of
https://github.com/spencershepard/RotorOps.git
synced 2025-11-10 15:45:30 +00:00
..
-uh-60L troop capacity set to 11 -bugfix: AI enemy planes/helicopters attacked invisible FARPS -generator now produces error log -syria scenario farp support units invulnerable -all russia/usa objects now swap sides for defense mode, including carriers and farps -forces templates can include air units with customization for loadout, livery, and skill -carrier and farp parking for enemy helicopters -parking now supports multiple airports per side -improved AI flight orbits (now onside and perpendicular to closest enemy airport) -enemy transport helicopters! -apcs spawn infantry now disables conflict zones as infinite pickup zones (adds a bit of realism) -bug fix: add zone triggers can be added in wrong order
This commit is contained in:
parent
7356f90eab
commit
ad11fd7937
7
.gitignore
vendored
7
.gitignore
vendored
@ -6,4 +6,9 @@ Generator/.idea
|
||||
Generator/__pycache__
|
||||
Generator/build
|
||||
Generator/venv
|
||||
Generator/dist
|
||||
Generator/dist
|
||||
Generator/generator.log
|
||||
MissionGenerator.exe
|
||||
incoming templates/
|
||||
Generator/utils/extract units/source.miz
|
||||
Generator/utils/extract units/units.txt
|
||||
|
||||
@ -4,6 +4,15 @@ You can add your own unit templates in this directory and they will appear in th
|
||||
2) Add ground unit groups.
|
||||
3) Save the mission in this directory.
|
||||
|
||||
Optional:
|
||||
4) Add helicopters with "CAS" main task for attack helicopters.
|
||||
5) Add helicopters with "Transport" main task for transport helicopters.
|
||||
6) Add planes with "CAS" main task for attack planes.
|
||||
7) Add planes with "CAP" main task for fighters.
|
||||
8) Configure loadouts, liveries, and skill for aircraft.
|
||||
|
||||
Tips:
|
||||
-Drop your templates in the RotorOps Discord if you'd like to have them added in a release for everyone.
|
||||
-The mission generator will only extract blue ground units from the template when selected from the "Blue Forces" menu, and vice versa.
|
||||
-Only unit types are used from ground units. Liveries or other attributes are able to be copied.
|
||||
-For aircraft, group size is currently capped at 2 units per group to help prevent issues with parking. Only the first unit in the group is used as a source.
|
||||
|
||||
BIN
Generator/Forces/blue/BLUE Vietnam Armor (Mr Nobody).miz
Normal file
BIN
Generator/Forces/blue/BLUE Vietnam Armor (Mr Nobody).miz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -5,7 +5,7 @@ import dcs
|
||||
import RotorOpsMission as ROps
|
||||
import RotorOpsUtils
|
||||
import RotorOpsUnits
|
||||
|
||||
import logging
|
||||
|
||||
from PyQt5.QtWidgets import (
|
||||
QApplication, QDialog, QMainWindow, QMessageBox
|
||||
@ -13,12 +13,38 @@ from PyQt5.QtWidgets import (
|
||||
from PyQt5 import QtGui
|
||||
from MissionGeneratorUI import Ui_MainWindow
|
||||
|
||||
|
||||
#Setup logfile and exception handler
|
||||
logger = logging.getLogger(__name__)
|
||||
logging.basicConfig(filename='generator.log', encoding='utf-8', level=logging.DEBUG, format='%(asctime)s %(levelname)-8s %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
|
||||
handler = logging.StreamHandler(stream=sys.stdout)
|
||||
logger.addHandler(handler)
|
||||
|
||||
def handle_exception(exc_type, exc_value, exc_traceback):
|
||||
if issubclass(exc_type, KeyboardInterrupt): #example of handling error subclasses
|
||||
sys.__excepthook__(exc_type, exc_value, exc_traceback)
|
||||
return
|
||||
|
||||
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Uncaught exception")
|
||||
msg.setText("Oops, there was a problem. Please check the log file or post it in the RotorOps discord where some helpful people will have a look.")
|
||||
x = msg.exec_()
|
||||
|
||||
|
||||
sys.excepthook = handle_exception
|
||||
|
||||
|
||||
maj_version = 0
|
||||
minor_version = 3
|
||||
minor_version = 4
|
||||
version_string = str(maj_version) + "." + str(minor_version)
|
||||
scenarios = []
|
||||
red_forces_files = []
|
||||
blue_forces_files = []
|
||||
defenders_text = "Defending Forces:"
|
||||
attackers_text = "Attacking Forces:"
|
||||
|
||||
logger.info("RotorOps v" + version_string)
|
||||
|
||||
class Window(QMainWindow, Ui_MainWindow):
|
||||
|
||||
@ -27,11 +53,11 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
super().__init__(parent)
|
||||
|
||||
if getattr(sys, 'frozen', False) and hasattr(sys, '_MEIPASS'):
|
||||
print('running in a PyInstaller bundle')
|
||||
logger.info('running in a PyInstaller bundle')
|
||||
home_dir = os.getcwd()
|
||||
os.chdir(home_dir + "/Generator")
|
||||
else:
|
||||
print('running in a normal Python process')
|
||||
logger.info('running in a normal Python process')
|
||||
|
||||
|
||||
self.m = ROps.RotorOpsMission()
|
||||
@ -42,6 +68,8 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
self.populateForces("blue", self.blueforces_comboBox, blue_forces_files)
|
||||
self.populateSlotSelection()
|
||||
|
||||
self.blue_forces_label.setText(attackers_text)
|
||||
self.red_forces_label.setText(defenders_text)
|
||||
self.background_label.setPixmap(QtGui.QPixmap(self.m.assets_dir + "/background.PNG"))
|
||||
self.statusbar.setStyleSheet(
|
||||
"QStatusBar{padding-left:5px;color:black;font-weight:bold;}")
|
||||
@ -50,15 +78,15 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
|
||||
|
||||
def connectSignalsSlots(self):
|
||||
# self.action_Exit.triggered.connect(self.close)
|
||||
self.action_generateMission.triggered.connect(self.generateMissionAction)
|
||||
self.action_scenarioSelected.triggered.connect(self.scenarioChanged)
|
||||
self.action_defensiveModeChanged.triggered.connect(self.defensiveModeChanged)
|
||||
|
||||
def populateScenarios(self):
|
||||
os.chdir(self.m.scenarios_dir)
|
||||
path = os.getcwd()
|
||||
dir_list = os.listdir(path)
|
||||
print("Looking for mission files in '", path, "' :")
|
||||
logger.info("Looking for mission files in " + path)
|
||||
|
||||
for filename in dir_list:
|
||||
if filename.endswith(".miz"):
|
||||
@ -70,7 +98,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
os.chdir(self.m.forces_dir + "/" + side)
|
||||
path = os.getcwd()
|
||||
dir_list = os.listdir(path)
|
||||
print("Looking for " + side + " Forces files in '", os.getcwd(), "' :")
|
||||
logger.info("Looking for " + side + " Forces files in '" + path)
|
||||
|
||||
for filename in dir_list:
|
||||
if filename.endswith(".miz"):
|
||||
@ -82,65 +110,69 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
for type in RotorOpsUnits.client_helos:
|
||||
self.slot_template_comboBox.addItem(type.id)
|
||||
|
||||
def defensiveModeChanged(self):
|
||||
if self.defense_checkBox.isChecked():
|
||||
self.red_forces_label.setText(attackers_text)
|
||||
self.blue_forces_label.setText(defenders_text)
|
||||
else:
|
||||
self.red_forces_label.setText(defenders_text)
|
||||
self.blue_forces_label.setText(attackers_text)
|
||||
|
||||
|
||||
def scenarioChanged(self):
|
||||
try:
|
||||
os.chdir(self.m.scenarios_dir)
|
||||
filename = scenarios[self.scenario_comboBox.currentIndex()]
|
||||
source_mission = dcs.mission.Mission()
|
||||
source_mission.load_file(filename)
|
||||
zones = source_mission.triggers.zones()
|
||||
conflict_zones = 0
|
||||
staging_zones = 0
|
||||
conflict_zone_size_sum = 0
|
||||
conflict_zone_distance_sum = 0
|
||||
spawn_zones = 0
|
||||
conflict_zone_positions = []
|
||||
#friendly_airports = source_mission.getCoalitionAirports("blue")
|
||||
#enemy_airports = source_mission.getCoalitionAirports("red")
|
||||
friendly_airports = True
|
||||
enemy_airports = True
|
||||
os.chdir(self.m.scenarios_dir)
|
||||
filename = scenarios[self.scenario_comboBox.currentIndex()]
|
||||
source_mission = dcs.mission.Mission()
|
||||
source_mission.load_file(filename)
|
||||
zones = source_mission.triggers.zones()
|
||||
conflict_zones = 0
|
||||
staging_zones = 0
|
||||
conflict_zone_size_sum = 0
|
||||
conflict_zone_distance_sum = 0
|
||||
spawn_zones = 0
|
||||
conflict_zone_positions = []
|
||||
#friendly_airports = source_mission.getCoalitionAirports("blue")
|
||||
#enemy_airports = source_mission.getCoalitionAirports("red")
|
||||
friendly_airports = True
|
||||
enemy_airports = True
|
||||
|
||||
## TODO: we should be creating a new instance of RotorOpsMission each time scenario is changed so we can access all methods and vars
|
||||
for zone in zones:
|
||||
if zone.name == "STAGING":
|
||||
staging_zones += 1
|
||||
if zone.name == "ALPHA" or zone.name == "BRAVO" or zone.name == "CHARLIE" or zone.name == "DELTA":
|
||||
conflict_zones += 1
|
||||
conflict_zone_size_sum += zone.radius
|
||||
conflict_zone_positions.append(zone.position)
|
||||
if zone.name.rfind("_SPAWN") > 0:
|
||||
spawn_zones += 1
|
||||
if conflict_zones > 1:
|
||||
for index, position in enumerate(conflict_zone_positions):
|
||||
if index > 0:
|
||||
conflict_zone_distance_sum += RotorOpsUtils.getDistance(conflict_zone_positions[index], conflict_zone_positions[index - 1])
|
||||
|
||||
for zone in zones:
|
||||
if zone.name == "STAGING":
|
||||
staging_zones += 1
|
||||
if zone.name == "ALPHA" or zone.name == "BRAVO" or zone.name == "CHARLIE" or zone.name == "DELTA":
|
||||
conflict_zones += 1
|
||||
conflict_zone_size_sum += zone.radius
|
||||
conflict_zone_positions.append(zone.position)
|
||||
if zone.name.rfind("_SPAWN") > 0:
|
||||
spawn_zones += 1
|
||||
if conflict_zones > 1:
|
||||
for index, position in enumerate(conflict_zone_positions):
|
||||
if index > 0:
|
||||
conflict_zone_distance_sum += RotorOpsUtils.getDistance(conflict_zone_positions[index], conflict_zone_positions[index - 1])
|
||||
def validateTemplate():
|
||||
valid = True
|
||||
if len(staging_zones) < 1:
|
||||
valid = False
|
||||
if len(conflict_zones) < 1:
|
||||
valid = False
|
||||
if not friendly_airports:
|
||||
valid = False
|
||||
if not enemy_airports:
|
||||
valid = False
|
||||
return valid
|
||||
|
||||
def validateTemplate():
|
||||
valid = True
|
||||
if len(staging_zones) < 1:
|
||||
valid = False
|
||||
if len(conflict_zones) < 1:
|
||||
valid = False
|
||||
if not friendly_airports:
|
||||
valid = False
|
||||
if not enemy_airports:
|
||||
valid = False
|
||||
return valid
|
||||
|
||||
if conflict_zones and staging_zones :
|
||||
average_zone_size = conflict_zone_size_sum / conflict_zones
|
||||
self.description_textBrowser.setText(
|
||||
"Map: " + source_mission.terrain.name + "\n" +
|
||||
"Conflict Zones: " + str(conflict_zones) + "\n" +
|
||||
"Average Zone Size " + str(math.floor(average_zone_size)) + "m \n" +
|
||||
"Infantry Spawn Zones: " + str(spawn_zones) + "\n" +
|
||||
"Approx Distance: " + str(math.floor(RotorOpsUtils.convertMeterToNM(conflict_zone_distance_sum))) + "nm \n"
|
||||
#"Validity Check:" + str(validateTemplate())
|
||||
)
|
||||
except:
|
||||
self.description_textBrowser.setText("File error occured.")
|
||||
if conflict_zones and staging_zones :
|
||||
average_zone_size = conflict_zone_size_sum / conflict_zones
|
||||
self.description_textBrowser.setText(
|
||||
"Map: " + source_mission.terrain.name + "\n" +
|
||||
"Conflict Zones: " + str(conflict_zones) + "\n" +
|
||||
"Average Zone Size " + str(math.floor(average_zone_size)) + "m \n" +
|
||||
"Infantry Spawn Zones: " + str(spawn_zones) + "\n" +
|
||||
"Approx Distance: " + str(math.floor(RotorOpsUtils.convertMeterToNM(conflict_zone_distance_sum))) + "nm \n"
|
||||
#"Validity Check:" + str(validateTemplate())
|
||||
)
|
||||
#self.description_textBrowser.setText("File error occured.")
|
||||
|
||||
|
||||
def generateMissionAction(self):
|
||||
@ -168,19 +200,21 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
"zone_protect_sams": self.zone_sams_checkBox.isChecked(),
|
||||
"zone_farps": self.farp_buttonGroup.checkedButton().objectName(),
|
||||
"inf_spawn_msgs": self.inf_spawn_voiceovers_checkBox.isChecked(),
|
||||
"e_transport_helos": self.e_transport_helos_spinBox.value(),
|
||||
"transport_drop_qty": self.troop_drop_spinBox.value(),
|
||||
}
|
||||
os.chdir(self.m.home_dir + '/Generator')
|
||||
n = ROps.RotorOpsMission()
|
||||
result = n.generateMission(data)
|
||||
print("Generating mission with options:")
|
||||
print(str(data))
|
||||
logger.info("Generating mission with options:")
|
||||
logger.info(str(data))
|
||||
|
||||
# generate the mission
|
||||
#result = self.m.generateMission(data)
|
||||
|
||||
#display results
|
||||
if result["success"]:
|
||||
print(result["filename"] + "' successfully generated in " + result["directory"])
|
||||
logger.info(result["filename"] + "' successfully generated in " + result["directory"])
|
||||
self.statusbar.showMessage(result["filename"] + "' successfully generated in " + result["directory"], 10000)
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Mission Generated")
|
||||
@ -199,7 +233,7 @@ class Window(QMainWindow, Ui_MainWindow):
|
||||
)
|
||||
x = msg.exec_()
|
||||
elif not result["success"]:
|
||||
print(result["failure_msg"])
|
||||
logger.warning(result["failure_msg"])
|
||||
msg = QMessageBox()
|
||||
msg.setWindowTitle("Error")
|
||||
msg.setText(result["failure_msg"])
|
||||
|
||||
@ -57,23 +57,23 @@ class Ui_MainWindow(object):
|
||||
self.blueforces_comboBox = QtWidgets.QComboBox(self.centralwidget)
|
||||
self.blueforces_comboBox.setGeometry(QtCore.QRect(790, 230, 291, 31))
|
||||
self.blueforces_comboBox.setObjectName("blueforces_comboBox")
|
||||
self.scenario_label_2 = QtWidgets.QLabel(self.centralwidget)
|
||||
self.scenario_label_2.setGeometry(QtCore.QRect(690, 180, 141, 31))
|
||||
self.blue_forces_label = QtWidgets.QLabel(self.centralwidget)
|
||||
self.blue_forces_label.setGeometry(QtCore.QRect(690, 180, 241, 31))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(12)
|
||||
self.scenario_label_2.setFont(font)
|
||||
self.scenario_label_2.setObjectName("scenario_label_2")
|
||||
self.scenario_label_3 = QtWidgets.QLabel(self.centralwidget)
|
||||
self.scenario_label_3.setGeometry(QtCore.QRect(60, 180, 141, 31))
|
||||
self.blue_forces_label.setFont(font)
|
||||
self.blue_forces_label.setObjectName("blue_forces_label")
|
||||
self.red_forces_label = QtWidgets.QLabel(self.centralwidget)
|
||||
self.red_forces_label.setGeometry(QtCore.QRect(60, 180, 261, 31))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(12)
|
||||
self.scenario_label_3.setFont(font)
|
||||
self.scenario_label_3.setObjectName("scenario_label_3")
|
||||
self.red_forces_label.setFont(font)
|
||||
self.red_forces_label.setObjectName("red_forces_label")
|
||||
self.redforces_comboBox = QtWidgets.QComboBox(self.centralwidget)
|
||||
self.redforces_comboBox.setGeometry(QtCore.QRect(170, 230, 291, 31))
|
||||
self.redforces_comboBox.setObjectName("redforces_comboBox")
|
||||
self.background_label = QtWidgets.QLabel(self.centralwidget)
|
||||
self.background_label.setGeometry(QtCore.QRect(-40, 440, 801, 371))
|
||||
self.background_label.setGeometry(QtCore.QRect(-40, 490, 801, 371))
|
||||
self.background_label.setAutoFillBackground(False)
|
||||
self.background_label.setStyleSheet("")
|
||||
self.background_label.setText("")
|
||||
@ -150,13 +150,13 @@ class Ui_MainWindow(object):
|
||||
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(470, 400, 251, 31))
|
||||
self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(450, 420, 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(680, 360, 71, 31))
|
||||
self.inf_spawn_spinBox.setGeometry(QtCore.QRect(670, 340, 51, 31))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(12)
|
||||
self.inf_spawn_spinBox.setFont(font)
|
||||
@ -176,7 +176,7 @@ 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(470, 360, 191, 31))
|
||||
self.label.setGeometry(QtCore.QRect(450, 340, 211, 21))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(10)
|
||||
self.label.setFont(font)
|
||||
@ -190,12 +190,6 @@ class Ui_MainWindow(object):
|
||||
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(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(810, 760, 191, 16))
|
||||
font = QtGui.QFont()
|
||||
@ -247,15 +241,15 @@ class Ui_MainWindow(object):
|
||||
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))
|
||||
self.scenario_label_9.setGeometry(QtCore.QRect(810, 450, 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))
|
||||
self.inf_spawn_voiceovers_checkBox.setGeometry(QtCore.QRect(810, 720, 251, 31))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(10)
|
||||
font.setPointSize(9)
|
||||
self.inf_spawn_voiceovers_checkBox.setFont(font)
|
||||
self.inf_spawn_voiceovers_checkBox.setChecked(True)
|
||||
self.inf_spawn_voiceovers_checkBox.setObjectName("inf_spawn_voiceovers_checkBox")
|
||||
@ -287,14 +281,44 @@ class Ui_MainWindow(object):
|
||||
self.version_label.setGeometry(QtCore.QRect(920, 840, 241, 21))
|
||||
self.version_label.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter)
|
||||
self.version_label.setObjectName("version_label")
|
||||
self.scenario_label_10 = QtWidgets.QLabel(self.centralwidget)
|
||||
self.scenario_label_10.setGeometry(QtCore.QRect(140, 410, 241, 31))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(11)
|
||||
self.scenario_label_10.setFont(font)
|
||||
self.scenario_label_10.setObjectName("scenario_label_10")
|
||||
self.e_transport_helos_spinBox = QtWidgets.QSpinBox(self.centralwidget)
|
||||
self.e_transport_helos_spinBox.setGeometry(QtCore.QRect(70, 410, 51, 31))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(12)
|
||||
self.e_transport_helos_spinBox.setFont(font)
|
||||
self.e_transport_helos_spinBox.setMinimum(0)
|
||||
self.e_transport_helos_spinBox.setMaximum(8)
|
||||
self.e_transport_helos_spinBox.setProperty("value", 1)
|
||||
self.e_transport_helos_spinBox.setObjectName("e_transport_helos_spinBox")
|
||||
self.label_3 = QtWidgets.QLabel(self.centralwidget)
|
||||
self.label_3.setGeometry(QtCore.QRect(450, 380, 191, 31))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(10)
|
||||
self.label_3.setFont(font)
|
||||
self.label_3.setObjectName("label_3")
|
||||
self.troop_drop_spinBox = QtWidgets.QSpinBox(self.centralwidget)
|
||||
self.troop_drop_spinBox.setGeometry(QtCore.QRect(670, 380, 51, 31))
|
||||
font = QtGui.QFont()
|
||||
font.setPointSize(12)
|
||||
self.troop_drop_spinBox.setFont(font)
|
||||
self.troop_drop_spinBox.setMinimum(0)
|
||||
self.troop_drop_spinBox.setMaximum(10)
|
||||
self.troop_drop_spinBox.setProperty("value", 4)
|
||||
self.troop_drop_spinBox.setObjectName("troop_drop_spinBox")
|
||||
self.background_label.raise_()
|
||||
self.scenario_comboBox.raise_()
|
||||
self.scenario_label.raise_()
|
||||
self.generateButton.raise_()
|
||||
self.description_textBrowser.raise_()
|
||||
self.blueforces_comboBox.raise_()
|
||||
self.scenario_label_2.raise_()
|
||||
self.scenario_label_3.raise_()
|
||||
self.blue_forces_label.raise_()
|
||||
self.red_forces_label.raise_()
|
||||
self.redforces_comboBox.raise_()
|
||||
self.scenario_hint_label.raise_()
|
||||
self.forces_hint_label.raise_()
|
||||
@ -313,7 +337,6 @@ class Ui_MainWindow(object):
|
||||
self.label.raise_()
|
||||
self.slot_template_comboBox.raise_()
|
||||
self.label_2.raise_()
|
||||
self.scenario_label_6.raise_()
|
||||
self.force_offroad_checkBox.raise_()
|
||||
self.defense_checkBox.raise_()
|
||||
self.e_attack_helos_spinBox.raise_()
|
||||
@ -327,6 +350,10 @@ class Ui_MainWindow(object):
|
||||
self.farp_gunits.raise_()
|
||||
self.farp_always.raise_()
|
||||
self.version_label.raise_()
|
||||
self.scenario_label_10.raise_()
|
||||
self.e_transport_helos_spinBox.raise_()
|
||||
self.label_3.raise_()
|
||||
self.troop_drop_spinBox.raise_()
|
||||
MainWindow.setCentralWidget(self.centralwidget)
|
||||
self.menubar = QtWidgets.QMenuBar(MainWindow)
|
||||
self.menubar.setGeometry(QtCore.QRect(0, 0, 1209, 26))
|
||||
@ -344,10 +371,13 @@ class Ui_MainWindow(object):
|
||||
self.action_blueforcesSelected.setObjectName("action_blueforcesSelected")
|
||||
self.action_redforcesSelected = QtWidgets.QAction(MainWindow)
|
||||
self.action_redforcesSelected.setObjectName("action_redforcesSelected")
|
||||
self.action_defensiveModeChanged = QtWidgets.QAction(MainWindow)
|
||||
self.action_defensiveModeChanged.setObjectName("action_defensiveModeChanged")
|
||||
|
||||
self.retranslateUi(MainWindow)
|
||||
self.generateButton.clicked.connect(self.action_generateMission.trigger)
|
||||
self.scenario_comboBox.currentIndexChanged['int'].connect(self.action_scenarioSelected.trigger)
|
||||
self.defense_checkBox.stateChanged['int'].connect(self.action_defensiveModeChanged.trigger)
|
||||
QtCore.QMetaObject.connectSlotsByName(MainWindow)
|
||||
|
||||
def retranslateUi(self, MainWindow):
|
||||
@ -357,13 +387,13 @@ class Ui_MainWindow(object):
|
||||
self.scenario_label.setText(_translate("MainWindow", "Scenario Template:"))
|
||||
self.generateButton.setText(_translate("MainWindow", "Generate Mission"))
|
||||
self.description_textBrowser.setHtml(_translate("MainWindow", "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" \"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
|
||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
|
||||
"<html><head><meta name=\"qrichtext\" content=\"1\" /><meta charset=\"utf-8\" /><style type=\"text/css\">\n"
|
||||
"p, li { white-space: pre-wrap; }\n"
|
||||
"</style></head><body style=\" font-family:\'MS Shell Dlg 2\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
|
||||
"<p align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-size:10pt;\">Provide close air support for our convoys as we take back Las Vegas from the enemy!</span></p></body></html>"))
|
||||
"</style></head><body style=\" font-family:\'Segoe UI\'; font-size:9pt; font-weight:400; font-style:normal;\">\n"
|
||||
"<p align=\"center\" style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\"><span style=\" font-family:\'MS Shell Dlg 2\'; font-size:10pt;\">Provide close air support for our convoys as we take back Las Vegas from the enemy!</span></p></body></html>"))
|
||||
self.blueforces_comboBox.setStatusTip(_translate("MainWindow", "Tip: You can create your own custom ground forces groups to be automatically generated."))
|
||||
self.scenario_label_2.setText(_translate("MainWindow", "Friendly Forces:"))
|
||||
self.scenario_label_3.setText(_translate("MainWindow", "Enemy Forces:"))
|
||||
self.blue_forces_label.setText(_translate("MainWindow", "Friendly Forces:"))
|
||||
self.red_forces_label.setText(_translate("MainWindow", "Enemy Forces:"))
|
||||
self.redforces_comboBox.setStatusTip(_translate("MainWindow", "Tip: You can create your own custom ground forces groups to be automatically generated."))
|
||||
self.scenario_hint_label.setText(_translate("MainWindow", "Scenario templates are .miz files in \'Generator/Scenarios\'"))
|
||||
self.forces_hint_label.setText(_translate("MainWindow", "Forces templates are .miz files in \'Generator/Forces\'"))
|
||||
@ -378,20 +408,22 @@ class Ui_MainWindow(object):
|
||||
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.setStatusTip(_translate("MainWindow", "Friendly/enemy APCs will drop infantry when reaching a new conflict zone. Disables infinite troop pickups from conflict zones (you must pick up existing troops)."))
|
||||
self.apcs_spawn_checkBox.setText(_translate("MainWindow", "APCs Spawn Infantry"))
|
||||
self.inf_spawn_spinBox.setStatusTip(_translate("MainWindow", "This value is multiplied by the number of spawn zones in the mission template."))
|
||||
self.scenario_label_5.setText(_translate("MainWindow", "Groups Per Zone"))
|
||||
self.forces_hint_label_2.setText(_translate("MainWindow", "Forces templates are .miz files in \'Generator/Forces\'"))
|
||||
self.label.setText(_translate("MainWindow", "Infantry Groups per zone:"))
|
||||
self.label.setStatusTip(_translate("MainWindow", "This value is multiplied by the number of spawn zones in the mission template."))
|
||||
self.label.setText(_translate("MainWindow", "Infantry Spawns per zone:"))
|
||||
self.slot_template_comboBox.setStatusTip(_translate("MainWindow", "Default player/client spawn locations at a friendly airport."))
|
||||
self.label_2.setText(_translate("MainWindow", "Player Slots"))
|
||||
self.scenario_label_6.setText(_translate("MainWindow", "Infantry Spawns:"))
|
||||
self.force_offroad_checkBox.setStatusTip(_translate("MainWindow", "May help prevent long travel times or pathfinding issues. Tip: You can change this dynamically from mission triggers."))
|
||||
self.force_offroad_checkBox.setText(_translate("MainWindow", "Force Offroad"))
|
||||
self.defense_checkBox.setText(_translate("MainWindow", "Defensive Mode"))
|
||||
self.e_attack_helos_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack helicopter group spawns."))
|
||||
self.scenario_label_7.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack helicopter group spawns."))
|
||||
self.scenario_label_7.setText(_translate("MainWindow", "Enemy Attack Helicopters"))
|
||||
self.scenario_label_8.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack plane group spawns."))
|
||||
self.scenario_label_8.setText(_translate("MainWindow", "Enemy Attack Planes"))
|
||||
self.e_attack_planes_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack plane group spawns."))
|
||||
self.zone_sams_checkBox.setStatusTip(_translate("MainWindow", "Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed."))
|
||||
@ -406,10 +438,17 @@ class Ui_MainWindow(object):
|
||||
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.scenario_label_10.setStatusTip(_translate("MainWindow", "Approximate number of enemy transport helicopter spawns."))
|
||||
self.scenario_label_10.setText(_translate("MainWindow", "Enemy Transport Helicopters"))
|
||||
self.e_transport_helos_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy transport helicopter spawns."))
|
||||
self.label_3.setStatusTip(_translate("MainWindow", "The number of troop drops per transport helicopter flight."))
|
||||
self.label_3.setText(_translate("MainWindow", "Transport Drop Points:"))
|
||||
self.troop_drop_spinBox.setStatusTip(_translate("MainWindow", "The number of troop drops per transport helicopter flight."))
|
||||
self.action_generateMission.setText(_translate("MainWindow", "_generateMission"))
|
||||
self.action_scenarioSelected.setText(_translate("MainWindow", "_scenarioSelected"))
|
||||
self.action_blueforcesSelected.setText(_translate("MainWindow", "_blueforcesSelected"))
|
||||
self.action_redforcesSelected.setText(_translate("MainWindow", "_redforcesSelected"))
|
||||
self.action_defensiveModeChanged.setText(_translate("MainWindow", "_defensiveModeChanged"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
@ -112,10 +112,10 @@ padding: 4px;</string>
|
||||
</property>
|
||||
<property name="html">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
<html><head><meta name="qrichtext" content="1" /><meta charset="utf-8" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:10pt;">Provide close air support for our convoys as we take back Las Vegas from the enemy!</span></p></body></html></string>
|
||||
</style></head><body style=" font-family:'Segoe UI'; font-size:9pt; font-weight:400; font-style:normal;">
|
||||
<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'MS Shell Dlg 2'; font-size:10pt;">Provide close air support for our convoys as we take back Las Vegas from the enemy!</span></p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QComboBox" name="blueforces_comboBox">
|
||||
@ -131,12 +131,12 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Tip: You can create your own custom ground forces groups to be automatically generated.</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="scenario_label_2">
|
||||
<widget class="QLabel" name="blue_forces_label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>690</x>
|
||||
<y>180</y>
|
||||
<width>141</width>
|
||||
<width>241</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -149,12 +149,12 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Friendly Forces:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="scenario_label_3">
|
||||
<widget class="QLabel" name="red_forces_label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>60</x>
|
||||
<y>180</y>
|
||||
<width>141</width>
|
||||
<width>261</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -184,7 +184,7 @@ p, li { white-space: pre-wrap; }
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>-40</x>
|
||||
<y>440</y>
|
||||
<y>490</y>
|
||||
<width>801</width>
|
||||
<height>371</height>
|
||||
</rect>
|
||||
@ -432,8 +432,8 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QCheckBox" name="apcs_spawn_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>470</x>
|
||||
<y>400</y>
|
||||
<x>450</x>
|
||||
<y>420</y>
|
||||
<width>251</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
@ -444,7 +444,7 @@ p, li { white-space: pre-wrap; }
|
||||
</font>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Friendly/enemy APCs will drop infantry when reaching a new conflict zone.</string>
|
||||
<string>Friendly/enemy APCs will drop infantry when reaching a new conflict zone. Disables infinite troop pickups from conflict zones (you must pick up existing troops).</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>APCs Spawn Infantry</string>
|
||||
@ -453,9 +453,9 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QSpinBox" name="inf_spawn_spinBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>680</x>
|
||||
<y>360</y>
|
||||
<width>71</width>
|
||||
<x>670</x>
|
||||
<y>340</y>
|
||||
<width>51</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
@ -517,10 +517,10 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>470</x>
|
||||
<y>360</y>
|
||||
<width>191</width>
|
||||
<height>31</height>
|
||||
<x>450</x>
|
||||
<y>340</y>
|
||||
<width>211</width>
|
||||
<height>21</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
@ -528,8 +528,11 @@ p, li { white-space: pre-wrap; }
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>This value is multiplied by the number of spawn zones in the mission template.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Infantry Groups per zone:</string>
|
||||
<string>Infantry Spawns per zone:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QComboBox" name="slot_template_comboBox">
|
||||
@ -563,24 +566,6 @@ p, li { white-space: pre-wrap; }
|
||||
<string>Player Slots</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="scenario_label_6">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>470</x>
|
||||
<y>320</y>
|
||||
<width>141</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Infantry Spawns:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="force_offroad_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
@ -667,6 +652,9 @@ p, li { white-space: pre-wrap; }
|
||||
<pointsize>11</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Approximate number of enemy attack helicopter group spawns.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enemy Attack Helicopters</string>
|
||||
</property>
|
||||
@ -685,6 +673,9 @@ p, li { white-space: pre-wrap; }
|
||||
<pointsize>11</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Approximate number of enemy attack plane group spawns.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enemy Attack Planes</string>
|
||||
</property>
|
||||
@ -740,8 +731,8 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QLabel" name="scenario_label_9">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>740</x>
|
||||
<y>490</y>
|
||||
<x>810</x>
|
||||
<y>450</y>
|
||||
<width>171</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
@ -758,15 +749,15 @@ p, li { white-space: pre-wrap; }
|
||||
<widget class="QCheckBox" name="inf_spawn_voiceovers_checkBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>470</x>
|
||||
<y>430</y>
|
||||
<x>810</x>
|
||||
<y>720</y>
|
||||
<width>251</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
<pointsize>9</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
@ -870,14 +861,110 @@ p, li { white-space: pre-wrap; }
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="scenario_label_10">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>140</x>
|
||||
<y>410</y>
|
||||
<width>241</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>11</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Approximate number of enemy transport helicopter spawns.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enemy Transport Helicopters</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QSpinBox" name="e_transport_helos_spinBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>70</x>
|
||||
<y>410</y>
|
||||
<width>51</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>Approximate number of enemy transport helicopter spawns.</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>8</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>450</x>
|
||||
<y>380</y>
|
||||
<width>191</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>10</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>The number of troop drops per transport helicopter flight.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Transport Drop Points:</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QSpinBox" name="troop_drop_spinBox">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>670</x>
|
||||
<y>380</y>
|
||||
<width>51</width>
|
||||
<height>31</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>12</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="statusTip">
|
||||
<string>The number of troop drops per transport helicopter flight.</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</widget>
|
||||
<zorder>background_label</zorder>
|
||||
<zorder>scenario_comboBox</zorder>
|
||||
<zorder>scenario_label</zorder>
|
||||
<zorder>generateButton</zorder>
|
||||
<zorder>description_textBrowser</zorder>
|
||||
<zorder>blueforces_comboBox</zorder>
|
||||
<zorder>scenario_label_2</zorder>
|
||||
<zorder>scenario_label_3</zorder>
|
||||
<zorder>blue_forces_label</zorder>
|
||||
<zorder>red_forces_label</zorder>
|
||||
<zorder>redforces_comboBox</zorder>
|
||||
<zorder>scenario_hint_label</zorder>
|
||||
<zorder>forces_hint_label</zorder>
|
||||
@ -896,7 +983,6 @@ p, li { white-space: pre-wrap; }
|
||||
<zorder>label</zorder>
|
||||
<zorder>slot_template_comboBox</zorder>
|
||||
<zorder>label_2</zorder>
|
||||
<zorder>scenario_label_6</zorder>
|
||||
<zorder>force_offroad_checkBox</zorder>
|
||||
<zorder>defense_checkBox</zorder>
|
||||
<zorder>e_attack_helos_spinBox</zorder>
|
||||
@ -910,6 +996,10 @@ p, li { white-space: pre-wrap; }
|
||||
<zorder>farp_gunits</zorder>
|
||||
<zorder>farp_always</zorder>
|
||||
<zorder>version_label</zorder>
|
||||
<zorder>scenario_label_10</zorder>
|
||||
<zorder>e_transport_helos_spinBox</zorder>
|
||||
<zorder>label_3</zorder>
|
||||
<zorder>troop_drop_spinBox</zorder>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menubar">
|
||||
<property name="geometry">
|
||||
@ -946,6 +1036,11 @@ p, li { white-space: pre-wrap; }
|
||||
<string>_redforcesSelected</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action_defensiveModeChanged">
|
||||
<property name="text">
|
||||
<string>_defensiveModeChanged</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
@ -960,8 +1055,8 @@ p, li { white-space: pre-wrap; }
|
||||
<y>591</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>589</x>
|
||||
<y>409</y>
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
@ -981,6 +1076,22 @@ p, li { white-space: pre-wrap; }
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>defense_checkBox</sender>
|
||||
<signal>stateChanged(int)</signal>
|
||||
<receiver>action_defensiveModeChanged</receiver>
|
||||
<slot>trigger()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>150</x>
|
||||
<y>131</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>-1</x>
|
||||
<y>-1</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
<buttongroups>
|
||||
<buttongroup name="farp_buttonGroup"/>
|
||||
|
||||
@ -14,13 +14,13 @@ 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)
|
||||
def zone_farp(mission, country, farp_country, position, heading, name, late_activation):
|
||||
# ai air units attack farp with late activation units, so we will set it to enemy coalition. It will be captured when frienly units spawn
|
||||
farp = mission.farp(farp_country, name, position, hidden=False, dead=False, farp_type=dcs.unit.InvisibleFARP)
|
||||
|
||||
vg = mission.vehicle_group_platoon(
|
||||
country,
|
||||
name,
|
||||
name + " Static",
|
||||
[
|
||||
dcs.vehicles.Unarmed.M_818,
|
||||
dcs.vehicles.AirDefence.Vulcan,
|
||||
|
||||
@ -7,14 +7,12 @@ import random
|
||||
import RotorOpsGroups
|
||||
import RotorOpsUnits
|
||||
import time
|
||||
from MissionGenerator import logger
|
||||
|
||||
|
||||
|
||||
class RotorOpsMission:
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
def __init__(self):
|
||||
self.m = dcs.mission.Mission()
|
||||
os.chdir("../")
|
||||
@ -30,7 +28,7 @@ class RotorOpsMission:
|
||||
self.staging_zones = {}
|
||||
self.spawn_zones = {}
|
||||
self.scripts = {}
|
||||
|
||||
self.res_map = {}
|
||||
|
||||
class RotorOpsZone:
|
||||
def __init__(self, name: str, flag: int, position: dcs.point, size: int):
|
||||
@ -56,7 +54,9 @@ class RotorOpsMission:
|
||||
for filename in dir_list:
|
||||
if filename.endswith(".ogg"):
|
||||
#print(filename)
|
||||
self.m.map_resource.add_resource_file(filename)
|
||||
key = self.m.map_resource.add_resource_file(filename)
|
||||
self.res_map[filename] = key
|
||||
|
||||
|
||||
#add all of our lua scripts
|
||||
os.chdir(script_directory)
|
||||
@ -67,32 +67,55 @@ class RotorOpsMission:
|
||||
|
||||
for filename in dir_list:
|
||||
if filename.endswith(".lua"):
|
||||
print("Adding script to mission: " + filename)
|
||||
logger.info("Adding script to mission: " + filename)
|
||||
self.scripts[filename] = self.m.map_resource.add_resource_file(filename)
|
||||
|
||||
def getUnitsFromMiz(self, filename, side):
|
||||
forces = []
|
||||
|
||||
forces = {}
|
||||
vehicles = []
|
||||
attack_helos = []
|
||||
transp_helos = []
|
||||
attack_planes = []
|
||||
fighter_planes = []
|
||||
|
||||
os.chdir(self.home_dir)
|
||||
os.chdir(self.forces_dir + "/" + side)
|
||||
print("Looking for " + side + " Forces files in '", os.getcwd(), "' :")
|
||||
logger.info("Looking for " + side + " Forces files in '" + os.getcwd())
|
||||
source_mission = dcs.mission.Mission()
|
||||
|
||||
try:
|
||||
source_mission.load_file(filename)
|
||||
|
||||
for country_name in source_mission.coalition.get(side).countries:
|
||||
country_obj = source_mission.coalition.get(side).countries[country_name]
|
||||
for vehicle_group in country_obj.vehicle_group:
|
||||
forces.append(vehicle_group)
|
||||
return forces
|
||||
except:
|
||||
print("Failed to load units from " + filename)
|
||||
vehicles.append(vehicle_group)
|
||||
for helicopter_group in country_obj.helicopter_group:
|
||||
if helicopter_group.task == 'CAS':
|
||||
attack_helos.append(helicopter_group)
|
||||
elif helicopter_group.task == 'Transport':
|
||||
transp_helos.append(helicopter_group)
|
||||
for plane_group in country_obj.plane_group:
|
||||
if plane_group.task == 'CAS':
|
||||
attack_planes.append(plane_group)
|
||||
elif plane_group.task == 'CAP':
|
||||
fighter_planes.append(plane_group)
|
||||
|
||||
forces["vehicles"] = vehicles
|
||||
forces["attack_helos"] = attack_helos
|
||||
forces["transp_helos"] = transp_helos
|
||||
forces["attack_planes"] = attack_planes
|
||||
forces["fighter_planes"] = fighter_planes
|
||||
|
||||
return forces
|
||||
|
||||
except:
|
||||
logger.error("Failed to load units from " + filename)
|
||||
|
||||
def generateMission(self, options):
|
||||
#get the template mission file
|
||||
|
||||
os.chdir(self.scenarios_dir)
|
||||
print("Looking for mission files in '", os.getcwd(), "' :")
|
||||
logger.info("Looking for mission files in " + os.getcwd())
|
||||
|
||||
self.m.load_file(options["scenario_filename"])
|
||||
|
||||
@ -100,23 +123,22 @@ class RotorOpsMission:
|
||||
failure_msg = "You must include a USA and Russia unit in the scenario template. See the instructions in " + self.scenarios_dir
|
||||
return {"success": False, "failure_msg": failure_msg}
|
||||
|
||||
|
||||
red_forces = self.getUnitsFromMiz(options["red_forces_filename"], "red")
|
||||
blue_forces = self.getUnitsFromMiz(options["blue_forces_filename"], "blue")
|
||||
|
||||
|
||||
|
||||
# add zones to target mission
|
||||
zone_names = ["ALPHA", "BRAVO", "CHARLIE", "DELTA"]
|
||||
zone_flag = 101
|
||||
for zone_name in zone_names:
|
||||
for zone in self.m.triggers.zones():
|
||||
if zone.name == zone_name:
|
||||
self.addZone(self.conflict_zones, self.RotorOpsZone(zone_name, zone_flag, zone.position, zone.radius))
|
||||
zone_flag = zone_flag + 1
|
||||
|
||||
|
||||
for zone in self.m.triggers.zones():
|
||||
if zone.name == "ALPHA":
|
||||
self.addZone(self.conflict_zones, self.RotorOpsZone("ALPHA", 101, zone.position, zone.radius))
|
||||
elif zone.name == "BRAVO":
|
||||
self.addZone(self.conflict_zones, self.RotorOpsZone("BRAVO", 102, zone.position, zone.radius))
|
||||
elif zone.name == "CHARLIE":
|
||||
self.addZone(self.conflict_zones, self.RotorOpsZone("CHARLIE", 103, zone.position, zone.radius))
|
||||
elif zone.name == "DELTA":
|
||||
self.addZone(self.conflict_zones, self.RotorOpsZone("DELTA", 104, zone.position, zone.radius))
|
||||
elif zone.name.rfind("STAGING") >= 0:
|
||||
if zone.name.rfind("STAGING") >= 0:
|
||||
self.addZone(self.staging_zones, self.RotorOpsZone(zone.name, None, zone.position, zone.radius))
|
||||
elif zone.name.rfind("SPAWN") >= 0:
|
||||
self.addZone(self.spawn_zones, self.RotorOpsZone(zone.name, None, zone.position, zone.radius))
|
||||
@ -128,22 +150,19 @@ class RotorOpsMission:
|
||||
blue_zones = self.conflict_zones
|
||||
red_zones = self.staging_zones
|
||||
#swap airport sides
|
||||
blue_airports = self.getCoalitionAirports("blue")
|
||||
red_airports = self.getCoalitionAirports("red")
|
||||
for airport_name in blue_airports:
|
||||
self.m.terrain.airports[airport_name].set_red()
|
||||
for airport_name in red_airports:
|
||||
self.m.terrain.airports[airport_name].set_blue()
|
||||
self.swapSides(options)
|
||||
|
||||
|
||||
|
||||
#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 red_forces["vehicles"]:
|
||||
self.addGroundGroups(red_zones[zone_name], self.m.country('Russia'), red_forces["vehicles"], options["red_quantity"])
|
||||
|
||||
#Add blue FARPS
|
||||
#Add red FARPS
|
||||
if options["zone_farps"] != "farp_never" and not options["defending"]:
|
||||
RotorOpsGroups.VehicleTemplate.USA.invisible_farp(self.m, self.m.country('USA'),
|
||||
RotorOpsGroups.VehicleTemplate.USA.zone_farp(self.m, self.m.country('USA'),
|
||||
self.m.country('Russia'),
|
||||
red_zones[zone_name].position,
|
||||
180, zone_name + " FARP", late_activation=True)
|
||||
|
||||
@ -162,9 +181,15 @@ class RotorOpsMission:
|
||||
|
||||
#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,
|
||||
if blue_forces["vehicles"]:
|
||||
self.addGroundGroups(blue_zones[zone_name], self.m.country('USA'), blue_forces["vehicles"],
|
||||
options["blue_quantity"])
|
||||
#Add blue FARPS
|
||||
if options["zone_farps"] != "farp_never" and options["defending"]:
|
||||
RotorOpsGroups.VehicleTemplate.USA.zone_farp(self.m, self.m.country('USA'),
|
||||
self.m.country('USA'),
|
||||
blue_zones[zone_name].position,
|
||||
180, zone_name + " FARP", late_activation=True)
|
||||
|
||||
#add logistics sites
|
||||
if options["crates"] and zone_name in self.staging_zones:
|
||||
@ -190,18 +215,13 @@ class RotorOpsMission:
|
||||
|
||||
|
||||
#Add player slots
|
||||
if options["slots"] == "Multiple Slots":
|
||||
self.addMultiplayerHelos()
|
||||
else:
|
||||
for helicopter in dcs.helicopters.helicopter_map:
|
||||
if helicopter == options["slots"]:
|
||||
self.addSinglePlayerHelos(dcs.helicopters.helicopter_map[helicopter])
|
||||
self.addPlayerHelos(options)
|
||||
|
||||
#Add AI Flights
|
||||
self.addFlights(options)
|
||||
self.addFlights(options, red_forces, blue_forces)
|
||||
|
||||
#Set the Editor Map View
|
||||
self.m.map.position = self.m.terrain.airports[self.getCoalitionAirports("blue")[0]].position
|
||||
self.m.map.position = self.conflict_zones["ALPHA"].position
|
||||
self.m.map.zoom = 100000
|
||||
|
||||
#add files and triggers necessary for RotorOps.lua script
|
||||
@ -209,7 +229,6 @@ class RotorOpsMission:
|
||||
self.scriptTriggerSetup(options)
|
||||
|
||||
#Save the mission file
|
||||
print(self.m.triggers.zones())
|
||||
os.chdir(self.output_dir)
|
||||
output_filename = options["scenario_filename"].removesuffix('.miz') + " " + time.strftime('%a%H%M%S') + '.miz'
|
||||
success = self.m.save(output_filename)
|
||||
@ -224,14 +243,11 @@ class RotorOpsMission:
|
||||
if dcs.vehicles.vehicle_map[unit.type]:
|
||||
unit_types.append(dcs.vehicles.vehicle_map[unit.type])
|
||||
country = self.m.country(_country.name)
|
||||
#pos1 = zone.position.point_from_heading(5, 200)
|
||||
#for i in range(0, quantity):
|
||||
self.m.vehicle_group_platoon(
|
||||
country,
|
||||
zone.name + '-GND ' + str(a+1),
|
||||
unit_types,
|
||||
zone.position.random_point_within(zone.size / 1.2, 100),
|
||||
#pos1.random_point_within(zone.size / 2.5, 100),
|
||||
heading=random.randint(0, 359),
|
||||
formation=dcs.unitgroup.VehicleGroup.Formation.Scattered,
|
||||
)
|
||||
@ -239,66 +255,158 @@ class RotorOpsMission:
|
||||
|
||||
def getCoalitionAirports(self, side: str):
|
||||
coalition_airports = []
|
||||
primary_airport = None
|
||||
shortest_dist = 1000000
|
||||
for airport_name in self.m.terrain.airports:
|
||||
airportobj = self.m.terrain.airports[airport_name]
|
||||
if airportobj.coalition == str.upper(side):
|
||||
coalition_airports.append(airport_name)
|
||||
return coalition_airports
|
||||
|
||||
def getParking(self, airport, aircraft):
|
||||
slot = airport.free_parking_slot(aircraft)
|
||||
slots = airport.free_parking_slots(aircraft)
|
||||
if slot:
|
||||
return airport
|
||||
else:
|
||||
print("No parking available for " + aircraft.id + " at " + airport.name)
|
||||
return None
|
||||
coalition_airports.append(airportobj)
|
||||
|
||||
start = self.staging_zones[list(self.staging_zones)[0]]
|
||||
dist_from_start = dcs.mapping._distance(airportobj.position.x, airportobj.position.y, start.position.x, start.position.y)
|
||||
|
||||
if dist_from_start < shortest_dist:
|
||||
primary_airport = airportobj
|
||||
shortest_dist = dist_from_start
|
||||
|
||||
return coalition_airports, primary_airport
|
||||
|
||||
def getParking(self, airport, aircraft, alt_airports=None, group_size=1):
|
||||
|
||||
if len(airport.free_parking_slots(aircraft)) >= group_size:
|
||||
if not (aircraft.id in dcs.planes.plane_map and len(airport.runways) == 0):
|
||||
return airport
|
||||
for airport in alt_airports:
|
||||
if len(airport.free_parking_slots(aircraft)) >= group_size:
|
||||
if not (aircraft.id in dcs.planes.plane_map and len(airport.runways) == 0):
|
||||
return airport
|
||||
|
||||
logger.warn("No parking available for " + aircraft.id)
|
||||
return None
|
||||
|
||||
#Find parking spots on FARPs and carriers
|
||||
def getUnitParking(self, aircraft):
|
||||
return
|
||||
|
||||
|
||||
def addSinglePlayerHelos(self, helotype):
|
||||
def swapSides(self, options):
|
||||
|
||||
#Swap airports
|
||||
|
||||
blue_airports, primary_blue = self.getCoalitionAirports("blue")
|
||||
red_airports, primary_red = self.getCoalitionAirports("red")
|
||||
|
||||
for airport in blue_airports:
|
||||
self.m.terrain.airports[airport.name].set_red()
|
||||
for airport in red_airports:
|
||||
self.m.terrain.airports[airport.name].set_blue()
|
||||
|
||||
usa = self.m.country("USA")
|
||||
russia = self.m.country("Russia")
|
||||
|
||||
|
||||
#Swap ships
|
||||
|
||||
blue_ships = usa.ship_group.copy()
|
||||
red_ships = russia.ship_group.copy()
|
||||
|
||||
for group in blue_ships:
|
||||
russia.add_ship_group(group)
|
||||
usa.ship_group.remove(group)
|
||||
|
||||
|
||||
for group in red_ships:
|
||||
usa.add_ship_group(group)
|
||||
russia.ship_group.remove(group)
|
||||
|
||||
|
||||
|
||||
#Swap statics
|
||||
|
||||
blue_statics = usa.static_group.copy()
|
||||
red_statics = russia.static_group.copy()
|
||||
|
||||
for group in blue_statics:
|
||||
usa.static_group.remove(group)
|
||||
russia.add_static_group(group)
|
||||
|
||||
for group in red_statics:
|
||||
russia.static_group.remove(group)
|
||||
usa.add_static_group(group)
|
||||
|
||||
|
||||
#Swap vehicles
|
||||
|
||||
blue_vehicles = usa.vehicle_group.copy()
|
||||
red_vehicles = russia.vehicle_group.copy()
|
||||
|
||||
for group in blue_vehicles:
|
||||
usa.vehicle_group.remove(group)
|
||||
russia.add_vehicle_group(group)
|
||||
|
||||
for group in red_vehicles:
|
||||
russia.vehicle_group.remove(group)
|
||||
usa.add_vehicle_group(group)
|
||||
|
||||
|
||||
#Swap planes
|
||||
|
||||
blue_planes = usa.plane_group.copy()
|
||||
red_planes = russia.plane_group.copy()
|
||||
|
||||
for group in blue_planes:
|
||||
usa.plane_group.remove(group)
|
||||
russia.add_plane_group(group)
|
||||
|
||||
for group in red_planes:
|
||||
russia.plane_group.remove(group)
|
||||
usa.add_plane_group(group)
|
||||
|
||||
|
||||
# Swap helicopters
|
||||
|
||||
blue_helos = usa.helicopter_group.copy()
|
||||
red_helos = russia.helicopter_group.copy()
|
||||
|
||||
for group in blue_helos:
|
||||
usa.helicopter_group.remove(group)
|
||||
russia.add_helicopter_group(group)
|
||||
|
||||
for group in red_helos:
|
||||
russia.helicopter_group.remove(group)
|
||||
usa.add_helicopter_group(group)
|
||||
|
||||
|
||||
def addPlayerHelos(self, options):
|
||||
client_helos = RotorOpsUnits.client_helos
|
||||
for helicopter in dcs.helicopters.helicopter_map:
|
||||
if helicopter == options["slots"]:
|
||||
client_helos = [dcs.helicopters.helicopter_map[helicopter]]
|
||||
|
||||
#find friendly carriers and farps
|
||||
carrier = self.m.country("USA").find_ship_group(name="HELO_CARRIER")
|
||||
if not carrier:
|
||||
carrier = self.m.country("USA").find_ship_group(name="HELO_CARRIER_1")
|
||||
|
||||
farp = self.m.country("USA").find_static_group("HELO_FARP")
|
||||
friendly_airports = self.getCoalitionAirports("blue")
|
||||
if not farp:
|
||||
farp = self.m.country("USA").find_static_group("HELO_FARP_1")
|
||||
|
||||
if carrier:
|
||||
fg = self.m.flight_group_from_unit(self.m.country('USA'), "CARRIER " + helotype.id, helotype, carrier, dcs.task.CAS, group_size=2)
|
||||
|
||||
elif farp:
|
||||
fg = self.m.flight_group_from_unit(self.m.country('USA'), "FARP " + helotype.id, helotype, farp, dcs.task.CAS, group_size=2)
|
||||
fg.units[0].position = fg.units[0].position.point_from_heading(90, 30)
|
||||
|
||||
# invisible farps need manual unit placement for multiple units
|
||||
if farp.units[0].type == 'Invisible FARP':
|
||||
fg.points[0].action = dcs.point.PointAction.FromGroundArea
|
||||
fg.points[0].type = "TakeOffGround"
|
||||
fg.units[0].position = fg.units[0].position.point_from_heading(0, 30)
|
||||
|
||||
else:
|
||||
for airport_name in friendly_airports:
|
||||
fg = self.m.flight_group_from_airport(self.m.country('USA'), airport_name + " " + helotype.id, helotype,
|
||||
self.getParking(self.m.terrain.airports[airport_name], helotype), group_size=2)
|
||||
fg.units[0].set_player()
|
||||
|
||||
|
||||
|
||||
def addMultiplayerHelos(self):
|
||||
carrier = self.m.country("USA").find_ship_group(name="HELO_CARRIER")
|
||||
farp = self.m.country("USA").find_static_group("HELO_FARP")
|
||||
friendly_airports = self.getCoalitionAirports("blue")
|
||||
friendly_airports, primary_f_airport = self.getCoalitionAirports("blue")
|
||||
|
||||
heading = 0
|
||||
for helotype in RotorOpsUnits.client_helos:
|
||||
group_size = 1
|
||||
if len(client_helos) == 1:
|
||||
group_size = 2 #add a wingman if singleplayer
|
||||
|
||||
for helotype in client_helos:
|
||||
if carrier:
|
||||
fg = self.m.flight_group_from_unit(self.m.country('USA'), "CARRIER " + helotype.id, helotype, carrier,
|
||||
dcs.task.CAS, group_size=1)
|
||||
dcs.task.CAS, group_size=group_size)
|
||||
elif farp:
|
||||
fg = self.m.flight_group_from_unit(self.m.country('USA'), "FARP " + helotype.id, helotype, farp,
|
||||
dcs.task.CAS, group_size=1)
|
||||
dcs.task.CAS, group_size=group_size)
|
||||
|
||||
#invisible farps need manual unit placement for multiple units
|
||||
if farp.units[0].type == 'Invisible FARP':
|
||||
@ -307,10 +415,14 @@ class RotorOpsMission:
|
||||
fg.units[0].position = fg.units[0].position.point_from_heading(heading, 30)
|
||||
heading += 90
|
||||
else:
|
||||
for airport_name in friendly_airports:
|
||||
fg = self.m.flight_group_from_airport(self.m.country('USA'), airport_name + " " + helotype.id, helotype,
|
||||
self.getParking(self.m.terrain.airports[airport_name], helotype), group_size=1)
|
||||
fg = self.m.flight_group_from_airport(self.m.country('USA'), primary_f_airport.name + " " + helotype.id, helotype,
|
||||
self.getParking(primary_f_airport, helotype), group_size=group_size)
|
||||
fg.units[0].set_client()
|
||||
fg.load_task_default_loadout(dcs.task.CAS)
|
||||
|
||||
#setup wingman for single player
|
||||
if len(fg.units) == 2:
|
||||
fg.units[1].skill = dcs.unit.Skill.High
|
||||
|
||||
|
||||
class TrainingScenario():
|
||||
@ -324,30 +436,115 @@ class RotorOpsMission:
|
||||
race_dist = random.randrange(80 * 1000, 120 * 1000)
|
||||
return dcs.mapping.Point(x1, y1), heading, race_dist
|
||||
|
||||
@staticmethod
|
||||
def perpRacetrack(enemy_heading, friendly_pt):
|
||||
heading = enemy_heading + random.randrange(70,110)
|
||||
race_dist = random.randrange(40 * 1000, 80 * 1000)
|
||||
center_pt = dcs.mapping.point_from_heading(friendly_pt.x, friendly_pt.y, enemy_heading - random.randrange(140, 220), 10000)
|
||||
pt1 = dcs.mapping.point_from_heading(center_pt[0], center_pt[1], enemy_heading - 90, random.randrange(20 * 1000, 40 * 1000))
|
||||
return dcs.mapping.Point(pt1[0], pt1[1]), heading, race_dist
|
||||
|
||||
|
||||
def addFlights(self, options):
|
||||
def addFlights(self, options, red_forces, blue_forces):
|
||||
usa = self.m.country(dcs.countries.USA.name)
|
||||
russia = self.m.country(dcs.countries.Russia.name)
|
||||
friendly_airport = self.m.terrain.airports[self.getCoalitionAirports("blue")[0]]
|
||||
enemy_airport = self.m.terrain.airports[self.getCoalitionAirports("red")[0]]
|
||||
friendly_airports, primary_f_airport = self.getCoalitionAirports("blue")
|
||||
enemy_airports, primary_e_airport = self.getCoalitionAirports("red")
|
||||
|
||||
#find enemy carriers and farps
|
||||
carrier = self.m.country("Russia").find_ship_group(name="HELO_CARRIER")
|
||||
if not carrier:
|
||||
carrier = self.m.country("Russia").find_ship_group(name="HELO_CARRIER_1")
|
||||
|
||||
farp = self.m.country("Russia").find_static_group("HELO_FARP")
|
||||
if not farp:
|
||||
farp = self.m.country("Russia").find_static_group("HELO_FARP_1")
|
||||
|
||||
e_airport_heading = dcs.mapping.heading_between_points(
|
||||
friendly_airports[0].position.x, friendly_airports[0].position.y, enemy_airports[0].position.x, primary_e_airport.position.y
|
||||
)
|
||||
|
||||
e_airport_distance = dcs.mapping._distance(
|
||||
primary_f_airport.position.x, primary_f_airport.position.y, primary_f_airport.position.x, primary_f_airport.position.y
|
||||
)
|
||||
|
||||
center_x, center_y = dcs.mapping.point_from_heading(primary_f_airport.position.x, primary_f_airport.position.y, e_airport_heading - 180, 5000)
|
||||
center_pt = dcs.mapping.Point(center_x, center_y)
|
||||
|
||||
# add some objects to illustrate the bounds on the map
|
||||
# RotorOpsGroups.VehicleTemplate.USA.zone_farp(self.m, self.m.country('USA'), self.m.country('Russia'),
|
||||
# center_pt, 180, "CENTER", late_activation=True)
|
||||
|
||||
# orbit_rect = dcs.mapping.Rectangle(
|
||||
# int(primary_f_airport.position.x), int(primary_f_airport.position.y - 100 * 1000), int(primary_f_airport.position.x - 100 * 1000),
|
||||
# int(primary_f_airport.position.y))
|
||||
|
||||
|
||||
orbit_rect = dcs.mapping.Rectangle(
|
||||
int(friendly_airport.position.x), int(friendly_airport.position.y - 100 * 1000), int(friendly_airport.position.x - 100 * 1000),
|
||||
int(friendly_airport.position.y))
|
||||
# def pointFromHeading(point, heading, distance):
|
||||
# pos = dcs.mapping.point_from_heading(point.x, point.y, heading, distance)
|
||||
# return dcs.mapping.Point(pos[0], pos[1])
|
||||
|
||||
|
||||
|
||||
# flight_box = [
|
||||
# pointFromHeading(center_pt, e_airport_heading - 90, 100000),
|
||||
# pointFromHeading(center_pt, e_airport_heading - 180, 50000),
|
||||
# pointFromHeading(center_pt, e_airport_heading + 90, 100000),
|
||||
# pointFromHeading(center_pt, e_airport_heading + 0, 50000),
|
||||
# ]
|
||||
|
||||
# flight_box = dcs.mapping.Rectangle(
|
||||
# dcs.mapping.point_from_heading(center_pt.x, center_pt.y, 0, 50000),
|
||||
# dcs.mapping.point_from_heading(center_pt.x, center_pt.y, 270, 100000),
|
||||
# dcs.mapping.point_from_heading(center_pt.x, center_pt.y, 180, 50000),
|
||||
# dcs.mapping.point_from_heading(center_pt.x, center_pt.y, 90, 10000),
|
||||
# )
|
||||
|
||||
# flight_box = dcs.mapping.Rectangle(
|
||||
# center_pt.y + 5000,
|
||||
# center_pt.x - 10000,
|
||||
# center_pt.y - 5000,
|
||||
# center_pt.x + 10000,
|
||||
# )
|
||||
|
||||
|
||||
|
||||
# for point in flight_box:
|
||||
# #add some objects to illustrate the bounds on the map
|
||||
# RotorOpsGroups.VehicleTemplate.USA.zone_farp(self.m, self.m.country('USA'), self.m.country('Russia'),
|
||||
# point, 180, "CENTER", late_activation=True)
|
||||
|
||||
# flight_box = [
|
||||
# dcs.mapping.point_from_heading(center_pt.x, center_pt.y, e_airport_heading - 90, 100000),
|
||||
# dcs.mapping.point_from_heading(center_pt.x, center_pt.y, e_airport_heading - 180, 50000),
|
||||
# dcs.mapping.point_from_heading(center_pt.x, center_pt.y, e_airport_heading + 90, 100000),
|
||||
# dcs.mapping.point_from_heading(center_pt.x, center_pt.y, e_airport_heading + 0, 50000),
|
||||
# ]
|
||||
#
|
||||
# a = int(min(flight_box.top, self.m.terrain.bounds.top))
|
||||
# b = int(max(flight_box.left, self.m.terrain.bounds.left))
|
||||
# c = int(max(flight_box.bottom, self.m.terrain.bounds.bottom))
|
||||
# d = int(min(flight_box.right, self.m.terrain.bounds.right))
|
||||
#
|
||||
#
|
||||
# orbit_rect = dcs.mapping.Rectangle(
|
||||
# int(min(flight_box.top, self.m.terrain.bounds.top)),
|
||||
# int(max(flight_box.left, self.m.terrain.bounds.left)),
|
||||
# int(max(flight_box.bottom, self.m.terrain.bounds.bottom)),
|
||||
# int(min(flight_box.right, self.m.terrain.bounds.right)),
|
||||
# )
|
||||
|
||||
|
||||
|
||||
if options["f_awacs"]:
|
||||
awacs_name = "AWACS"
|
||||
awacs_freq = 266
|
||||
pos, heading, race_dist = self.TrainingScenario.random_orbit(orbit_rect)
|
||||
#pos, heading, race_dist = self.TrainingScenario.random_orbit(orbit_rect)
|
||||
pos, heading, race_dist = self.TrainingScenario.perpRacetrack(e_airport_heading, primary_f_airport.position)
|
||||
awacs = self.m.awacs_flight(
|
||||
usa,
|
||||
awacs_name,
|
||||
plane_type=dcs.planes.E_3A,
|
||||
airport=self.getParking(friendly_airport, dcs.planes.E_3A),
|
||||
airport=self.getParking(primary_f_airport, dcs.planes.E_3A, friendly_airports),
|
||||
position=pos,
|
||||
race_distance=race_dist, heading=heading,
|
||||
altitude=random.randrange(4000, 5500, 100), frequency=awacs_freq)
|
||||
@ -355,10 +552,10 @@ class RotorOpsMission:
|
||||
awacs_escort = self.m.escort_flight(
|
||||
usa, "AWACS Escort",
|
||||
dcs.countries.USA.Plane.F_15C,
|
||||
airport=self.getParking(friendly_airport, dcs.countries.USA.Plane.F_15C),
|
||||
airport=self.getParking(primary_f_airport, dcs.countries.USA.Plane.F_15C, friendly_airports),
|
||||
group_to_escort=awacs,
|
||||
group_size=2)
|
||||
awacs_escort.load_loadout("Combat Air Patrol") #not working for f-15
|
||||
awacs_escort.load_loadout(dcs.task.CAP)
|
||||
|
||||
#add text to mission briefing with radio freq
|
||||
briefing = self.m.description_text() + "\n\n" + awacs_name + " " + str(awacs_freq) + ".00 " + "\n"
|
||||
@ -371,12 +568,13 @@ class RotorOpsMission:
|
||||
t2_name = "Tanker KC_135 Boom"
|
||||
t2_freq = 256
|
||||
t2_tac = "101Y"
|
||||
pos, heading, race_dist = self.TrainingScenario.random_orbit(orbit_rect)
|
||||
#pos, heading, race_dist = self.TrainingScenario.random_orbit(orbit_rect)
|
||||
pos, heading, race_dist = self.TrainingScenario.perpRacetrack(e_airport_heading, primary_f_airport.position)
|
||||
refuel_net = self.m.refuel_flight(
|
||||
usa,
|
||||
t1_name,
|
||||
dcs.planes.KC130,
|
||||
airport=self.getParking(friendly_airport, dcs.planes.KC130),
|
||||
airport=self.getParking(primary_f_airport, dcs.planes.KC130, friendly_airports),
|
||||
position=pos,
|
||||
race_distance=race_dist,
|
||||
heading=heading,
|
||||
@ -386,12 +584,13 @@ class RotorOpsMission:
|
||||
frequency=t1_freq,
|
||||
tacanchannel=t1_tac)
|
||||
|
||||
pos, heading, race_dist = self.TrainingScenario.random_orbit(orbit_rect)
|
||||
#pos, heading, race_dist = self.TrainingScenario.random_orbit(orbit_rect)
|
||||
pos, heading, race_dist = self.TrainingScenario.perpRacetrack(e_airport_heading, primary_f_airport.position)
|
||||
refuel_rod = self.m.refuel_flight(
|
||||
usa,
|
||||
t2_name,
|
||||
dcs.planes.KC_135,
|
||||
airport=self.getParking(friendly_airport, dcs.planes.KC_135),
|
||||
airport=self.getParking(primary_f_airport, dcs.planes.KC_135, friendly_airports),
|
||||
position=pos,
|
||||
race_distance=race_dist, heading=heading,
|
||||
altitude=random.randrange(4000, 5500, 100),
|
||||
@ -403,51 +602,125 @@ class RotorOpsMission:
|
||||
briefing = self.m.description_text() + "\n\n" + t1_name + " " + str(t1_freq) + ".00 " + t1_tac + "\n" + t2_name + " " + str(t2_freq) + ".00 " + t2_tac + "\n"
|
||||
self.m.set_description_text(briefing)
|
||||
|
||||
def zone_attack(fg, unit_type):
|
||||
def zone_attack(fg, airport):
|
||||
fg.set_skill(dcs.unit.Skill.Random)
|
||||
fg.late_activation = True
|
||||
fg.points[0].tasks.append(dcs.task.OptROE(0))
|
||||
#fg.load_loadout(unit_type["loadout"])
|
||||
#task = dcs.task.CAS
|
||||
#loadout = dcs.planes.Su_25.loadout(task)
|
||||
#loadout = dcs.planes.Su_25.loadout_by_name("Ground Attack")
|
||||
#fg.load_task_default_loadout(task)
|
||||
#fg.load_loadout("Ground Attack")
|
||||
#fg.load_task_default_loadout(dcs.task.GroundAttack)
|
||||
|
||||
#fg.load_loadout("2xB-13L+4xATGM 9M114")
|
||||
if options["defending"]:
|
||||
for zone_name in self.conflict_zones:
|
||||
fg.add_waypoint(self.conflict_zones[zone_name].position, 1000)
|
||||
else:
|
||||
for zone_name in reversed(self.conflict_zones):
|
||||
fg.add_waypoint(self.conflict_zones[zone_name].position, 1000)
|
||||
fg.add_runway_waypoint(enemy_airport)
|
||||
fg.land_at(enemy_airport)
|
||||
if hasattr(airport, 'runways'):
|
||||
fg.add_runway_waypoint(airport)
|
||||
if airport:
|
||||
fg.land_at(airport)
|
||||
|
||||
|
||||
|
||||
if options["e_attack_helos"]:
|
||||
helo = random.choice(RotorOpsUnits.e_attack_helos)
|
||||
afg = self.m.flight_group_from_airport(
|
||||
russia,
|
||||
"Enemy Attack Helicopters",
|
||||
helo,
|
||||
airport=enemy_airport,
|
||||
maintask=dcs.task.CAS,
|
||||
start_type=dcs.mission.StartType.Cold,
|
||||
group_size=2)
|
||||
zone_attack(afg, helo)
|
||||
source_helo = None
|
||||
if red_forces["attack_helos"]:
|
||||
source_group = random.choice(red_forces["attack_helos"])
|
||||
source_helo = source_group.units[0]
|
||||
helo_type = source_helo.unit_type
|
||||
group_size = len(source_group.units)
|
||||
if group_size > 2:
|
||||
group_size = 2
|
||||
|
||||
else:
|
||||
group_size = 2
|
||||
helo_type = random.choice(RotorOpsUnits.e_attack_helos)
|
||||
|
||||
airport = self.getParking(primary_e_airport, helo_type, enemy_airports, group_size)
|
||||
|
||||
if carrier:
|
||||
afg = self.m.flight_group_from_unit(
|
||||
russia,
|
||||
"Enemy Attack Helicopters",
|
||||
helo_type,
|
||||
carrier,
|
||||
maintask=dcs.task.CAS,
|
||||
start_type=dcs.mission.StartType.Cold,
|
||||
group_size=group_size)
|
||||
zone_attack(afg, carrier)
|
||||
|
||||
elif farp:
|
||||
afg = self.m.flight_group_from_unit(
|
||||
russia,
|
||||
"Enemy Attack Helicopters",
|
||||
helo_type,
|
||||
farp,
|
||||
maintask=dcs.task.CAS,
|
||||
start_type=dcs.mission.StartType.Cold,
|
||||
group_size=group_size)
|
||||
zone_attack(afg, farp)
|
||||
|
||||
elif airport:
|
||||
afg = self.m.flight_group_from_airport(
|
||||
russia,
|
||||
"Enemy Attack Helicopters",
|
||||
helo_type,
|
||||
airport=airport,
|
||||
maintask=dcs.task.CAS,
|
||||
start_type=dcs.mission.StartType.Cold,
|
||||
group_size=group_size)
|
||||
zone_attack(afg, airport)
|
||||
|
||||
else:
|
||||
return
|
||||
|
||||
if source_helo:
|
||||
for unit in afg.units:
|
||||
unit.pylons = source_helo.pylons
|
||||
unit.livery_id = source_helo.livery_id
|
||||
unit.skill = source_helo.skill
|
||||
|
||||
|
||||
|
||||
if options["e_attack_planes"]:
|
||||
plane = random.choice(RotorOpsUnits.e_attack_planes)
|
||||
afg = self.m.flight_group_from_airport(
|
||||
russia, "Enemy Attack Planes", plane["type"],
|
||||
airport=enemy_airport,
|
||||
maintask=dcs.task.CAS,
|
||||
start_type=dcs.mission.StartType.Cold,
|
||||
group_size=2)
|
||||
zone_attack(afg, plane)
|
||||
source_plane = None
|
||||
if red_forces["attack_planes"]:
|
||||
source_group = random.choice(red_forces["attack_planes"])
|
||||
source_plane = source_group.units[0]
|
||||
plane_type = source_plane.unit_type
|
||||
group_size = len(source_group.units)
|
||||
if group_size > 2:
|
||||
group_size = 2
|
||||
else:
|
||||
group_size = 2
|
||||
plane_type = random.choice(RotorOpsUnits.e_attack_planes)
|
||||
|
||||
airport = self.getParking(primary_e_airport, plane_type, enemy_airports, group_size)
|
||||
if airport:
|
||||
afg = self.m.flight_group_from_airport(
|
||||
russia, "Enemy Attack Planes", plane_type,
|
||||
airport=airport,
|
||||
maintask=dcs.task.CAS,
|
||||
start_type=dcs.mission.StartType.Cold,
|
||||
group_size=group_size)
|
||||
zone_attack(afg, airport)
|
||||
|
||||
if source_plane:
|
||||
for unit in afg.units:
|
||||
unit.pylons = source_plane.pylons
|
||||
unit.livery_id = source_plane.livery_id
|
||||
unit.skill = source_plane.skill
|
||||
|
||||
if options["e_transport_helos"]:
|
||||
group_size = 1
|
||||
helo_type = dcs.helicopters.Mi_26
|
||||
airport = self.getParking(primary_e_airport, helo_type, enemy_airports, group_size)
|
||||
if airport:
|
||||
afg = self.m.flight_group_from_airport(
|
||||
russia, "Enemy Transport Helicopters", helo_type,
|
||||
airport=airport,
|
||||
maintask=dcs.task.Transport,
|
||||
start_type=dcs.mission.StartType.Cold,
|
||||
group_size=group_size)
|
||||
afg.late_activation = True
|
||||
|
||||
|
||||
|
||||
def scriptTriggerSetup(self, options):
|
||||
@ -514,11 +787,14 @@ class RotorOpsMission:
|
||||
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"):
|
||||
if not self.m.country("USA").find_group(previous_zone + " FARP Static"):
|
||||
continue
|
||||
z_farps_trig = dcs.triggers.TriggerOnce(comment="Activate " + previous_zone + " FARP")
|
||||
z_farps_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
|
||||
z_farps_trig.actions.append(dcs.action.ActivateGroup(self.m.country("USA").find_group(previous_zone + " FARP").id))
|
||||
z_farps_trig.actions.append(dcs.action.ActivateGroup(self.m.country("USA").find_group(previous_zone + " FARP Static").id))
|
||||
#z_farps_trig.actions.append(dcs.action.SoundToAll(str(self.res_map['forward_base_established.ogg'])))
|
||||
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
|
||||
"RotorOps.farpEstablished(" + str(index) + ")")))
|
||||
self.m.triggerrules.triggers.append(z_farps_trig)
|
||||
|
||||
|
||||
@ -527,14 +803,17 @@ class RotorOpsMission:
|
||||
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"):
|
||||
if not self.m.country("USA").find_group(previous_zone + " FARP Static"):
|
||||
continue
|
||||
z_farps_trig = dcs.triggers.TriggerOnce(comment= "Activate " + previous_zone + " FARP")
|
||||
z_farps_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
|
||||
z_farps_trig.rules.append(dcs.condition.FlagIsMore(111, 20))
|
||||
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String("--The 100 flag indicates which zone is active. The 111 flag value is the percentage of staged units remaining")))
|
||||
z_farps_trig.actions.append(
|
||||
dcs.action.ActivateGroup(self.m.country("USA").find_group(previous_zone + " FARP").id))
|
||||
dcs.action.ActivateGroup(self.m.country("USA").find_group(previous_zone + " FARP Static").id))
|
||||
#z_farps_trig.actions.append(dcs.action.SoundToAll(str(self.res_map['forward_base_established.ogg'])))
|
||||
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
|
||||
"RotorOps.farpEstablished(" + str(index) + ")")))
|
||||
self.m.triggerrules.triggers.append(z_farps_trig)
|
||||
|
||||
|
||||
@ -546,7 +825,7 @@ class RotorOpsMission:
|
||||
z_weak_trig = dcs.triggers.TriggerOnce(comment=zone.name + " Attack Helo")
|
||||
z_weak_trig.rules.append(dcs.condition.FlagIsMore(zone.flag, 1))
|
||||
z_weak_trig.rules.append(dcs.condition.FlagIsLess(zone.flag, random.randrange(20, 90)))
|
||||
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag value represents the percentage of defending ground units remaining in zone. ")))
|
||||
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag " + str(zone.flag) + " value represents the percentage of defending ground units remaining in zone. ")))
|
||||
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.spawnAttackHelos()")))
|
||||
self.m.triggerrules.triggers.append(z_weak_trig)
|
||||
|
||||
@ -557,10 +836,24 @@ class RotorOpsMission:
|
||||
z_weak_trig = dcs.triggers.TriggerOnce(comment=zone.name + " Attack Plane")
|
||||
z_weak_trig.rules.append(dcs.condition.FlagIsMore(zone.flag, 1))
|
||||
z_weak_trig.rules.append(dcs.condition.FlagIsLess(zone.flag, random.randrange(20, 90)))
|
||||
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag value represents the percentage of defending ground units remaining in zone. ")))
|
||||
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag " + str(zone.flag) + " value represents the percentage of defending ground units remaining in zone. ")))
|
||||
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.spawnAttackPlanes()")))
|
||||
self.m.triggerrules.triggers.append(z_weak_trig)
|
||||
|
||||
#Add transport helos triggers
|
||||
for index in range(options["e_transport_helos"]):
|
||||
random_zone_index = random.randrange(1, len(self.conflict_zones))
|
||||
random_zone_obj = list(self.conflict_zones.items())[random_zone_index]
|
||||
zone = random_zone_obj[1]
|
||||
z_weak_trig = dcs.triggers.TriggerOnce(comment=zone.name + " Transport Helo")
|
||||
z_weak_trig.rules.append(dcs.condition.FlagEquals(game_flag, random_zone_index + 1))
|
||||
z_weak_trig.rules.append(dcs.condition.FlagIsLess(zone.flag, random.randrange(20, 100)))
|
||||
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String(
|
||||
"---Flag " + str(game_flag) + " value represents the index of the active zone. ")))
|
||||
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("---Flag " + str(zone.flag) + " value represents the percentage of defending ground units remaining in zone. ")))
|
||||
z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.spawnTranspHelos(8," + str(options["transport_drop_qty"]) + ")")))
|
||||
self.m.triggerrules.triggers.append(z_weak_trig)
|
||||
|
||||
#Add game won/lost triggers
|
||||
trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict WON")
|
||||
trig.rules.append(dcs.condition.FlagEquals(game_flag, 99))
|
||||
|
||||
@ -20,9 +20,7 @@ e_transport_helos = [
|
||||
]
|
||||
|
||||
e_attack_planes = [
|
||||
#{'type': dcs.planes.Su_34, 'loadout': "APU-8 Vikhr-M*2,Kh-25ML,R-73*2,SPPU-22*2,Mercury LLTV Pod,MPS-410"},
|
||||
#{'type': dcs.planes.Su_25, 'loadout': "RKB-250*8,R-60M*2"},
|
||||
{'type': dcs.planes.A_10C, 'loadout': ""}
|
||||
dcs.planes.A_10C,
|
||||
]
|
||||
|
||||
e_zone_sams = [
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@ -3,7 +3,7 @@ You can add your own scenarios in this directory and they will appear in the mis
|
||||
|
||||
A scenario .miz file MUST have:
|
||||
|
||||
1) Between 1-4 trigger zones called "ALPHA", "BRAVO", "CHARLIE", "DELTA"
|
||||
1) Between 1-4 circular trigger zones called "ALPHA", "BRAVO", "CHARLIE", "DELTA"
|
||||
2) At least one trigger zone with a name that starts with "STAGING".
|
||||
3) A blue airport (recommend somewhere near/on-side your staging zone).
|
||||
4) A red airport (recommend somewhere near/on-side your last conflict zone).
|
||||
@ -13,16 +13,15 @@ A scenario .miz file MUST have:
|
||||
|
||||
|
||||
Optional:
|
||||
7) USA FARP called "HELO_FARP" for automatic player placement.
|
||||
7) USA FARP called "HELO_FARP" for automatic player placement. (Strongly suggest using immortal and invisible options for support vehicles, and add "static" to the group name to keep them from moving)
|
||||
8) USA Carrier called "HELO_CARRIER" for automatic player placement.
|
||||
9) Infantry spawn zones inside conflict zones. Add near buildings to simulate infantry hiding within. Name trigger zones like "ALPHA_SPAWN", "ALPHA_SPAWN_2, etc.
|
||||
|
||||
|
||||
|
||||
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.
|
||||
Position the center of staging zones over an open area of at least 1000 x 1000ft to provide space for logistics units.
|
||||
-Position the center of conflict zones over an open area, as this position will be used to spawn units and FARPs.
|
||||
-Position the center of staging zones over an open area of at least 1000 x 1000ft to provide space for logistics zones.
|
||||
-For very scenery dense areas like forests or urban areas, smaller conflict zone sizes are highly recommended (eg 4000ft radius). A zone center near a roadway may also help keep units moving smoothly.
|
||||
-The conflict game type can be played with blue forces on defense. In this mode the last conflict zone is the only troop pickup zone.
|
||||
-Design your template so that it can be played in normal 'attacking' mode or 'defending' the conflict zone from enemy ground units starting from the staging zone.
|
||||
@ -35,4 +34,5 @@ Position the center of staging zones over an open area of at least 1000 x 1000ft
|
||||
-Friendly AWACs and tankers will be placed at the blue airport if parking is available, otherwise they will start in the air.
|
||||
-Enemy helicopters and planes will spawn at the red airport.
|
||||
-Late activation FARPs might be useful for rearming far from the player spawn point.
|
||||
|
||||
-In "Defense" or with "Swap sides" option, USA and Russia ships, helicopters, planes, and ground units will swap countries. Static objects may not. Test it out.
|
||||
-Turn off or limit civilian road traffic.
|
||||
|
||||
BIN
Generator/requirements.txt
Normal file
BIN
Generator/requirements.txt
Normal file
Binary file not shown.
39
Generator/utils/extract units/main.py
Normal file
39
Generator/utils/extract units/main.py
Normal file
@ -0,0 +1,39 @@
|
||||
import dcs
|
||||
import os
|
||||
|
||||
|
||||
def main():
|
||||
filename = "source.miz"
|
||||
print("Attempting to extract units from " + filename + " relative to 'HELO_FARP' initial point.")
|
||||
|
||||
source_mission = dcs.mission.Mission()
|
||||
source_mission.load_file(filename)
|
||||
fo = open("units.txt", "w")
|
||||
|
||||
usa = source_mission.country("USA")
|
||||
initial_point = usa.find_static_group("HELO_FARP").position
|
||||
|
||||
def p(mystring):
|
||||
fo.write(mystring + '\n')
|
||||
print(mystring)
|
||||
|
||||
group_types = [usa.static_group, usa.vehicle_group, usa.helicopter_group, usa.plane_group, usa.ship_group]
|
||||
|
||||
for group_type in group_types:
|
||||
for group in group_type:
|
||||
for unit in group.units:
|
||||
print(str(unit.position.x))
|
||||
x_rel = initial_point.x - unit.position.x
|
||||
y_rel = initial_point.y - unit.position.y
|
||||
heading = unit.heading
|
||||
|
||||
p(unit.type)
|
||||
p("x: " + str(round(x_rel, 7)))
|
||||
p("y: " + str(round(y_rel, 7)))
|
||||
p("h: " + str(round(heading, 2)))
|
||||
p('\n')
|
||||
|
||||
fo.close()
|
||||
|
||||
|
||||
main()
|
||||
4
MissionGenerator.bat
Normal file
4
MissionGenerator.bat
Normal file
@ -0,0 +1,4 @@
|
||||
cd Generator
|
||||
pip install -r requirements.txt
|
||||
python MissionGenerator.py -log.txt
|
||||
cmd /k
|
||||
231
RotorOps.lua
231
RotorOps.lua
@ -1,5 +1,5 @@
|
||||
RotorOps = {}
|
||||
RotorOps.version = "1.2.5"
|
||||
RotorOps.version = "1.2.6"
|
||||
local debug = true
|
||||
|
||||
|
||||
@ -28,6 +28,7 @@ RotorOps.transports = {'UH-1H', 'Mi-8MT', 'Mi-24P', 'SA342M', 'SA342L', 'SA342Mi
|
||||
RotorOps.CTLD_crates = false
|
||||
RotorOps.CTLD_sound_effects = true --sound effects for troop pickup/dropoffs
|
||||
RotorOps.exclude_ai_group_name = "Static" --include this somewhere in a group name to exclude the group from being tasked in the active zone
|
||||
RotorOps.pickup_zone_smoke = "blue"
|
||||
|
||||
|
||||
---[[END OF OPTIONS]]---
|
||||
@ -67,6 +68,7 @@ local inf_spawn_zones = {}
|
||||
local cooldown = {
|
||||
["attack_helo_msg"] = 0,
|
||||
["attack_plane_msg"] = 0,
|
||||
["trans_helo_msg"] = 0,
|
||||
}
|
||||
|
||||
|
||||
@ -164,6 +166,16 @@ RotorOps.gameMsgs = {
|
||||
{'ENEMY TROOPS IN THE ACTIVE!', 'e_infantry_spawn5.ogg'},
|
||||
{'VISUAL ON ENEMY TROOPS!', 'e_infantry_spawn6.ogg'},
|
||||
},
|
||||
farp_established = {
|
||||
{'NEW FARP AVAILABLE!', 'forward_base_established.ogg'},
|
||||
{'NEW FARP AT ALPHA!', 'forward_base_established.ogg'},
|
||||
{'NEW FARP AT BRAVO!', 'forward_base_established.ogg'},
|
||||
{'NEW FARP AT CHARLIE!', 'forward_base_established.ogg'},
|
||||
{'NEW FARP AT DELTA!', 'forward_base_established.ogg'},
|
||||
},
|
||||
transp_helos_toff = {
|
||||
{'ENEMY TRANSPORT HELICOPTERS INBOUND!', 'enemy_chopper_inbound.ogg'},
|
||||
},
|
||||
|
||||
|
||||
}
|
||||
@ -184,15 +196,15 @@ end
|
||||
function RotorOps.eventHandler:onEvent(event)
|
||||
---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()
|
||||
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
|
||||
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
|
||||
|
||||
@ -219,8 +231,32 @@ function RotorOps.eventHandler:onEvent(event)
|
||||
end
|
||||
end
|
||||
|
||||
if initiator_name == "Enemy Transport Helicopters" then --we're using mist clone now so group name will not match
|
||||
env.info("Transport helicopter took off")
|
||||
|
||||
if ((RotorOps.getTime() - cooldown["trans_helo_msg"]) > 90) then
|
||||
timer.scheduleFunction(function()RotorOps.gameMsg(RotorOps.gameMsgs.transp_helos_toff) end, {}, timer.getTime() + 1)
|
||||
cooldown["trans_helo_msg"] = RotorOps.getTime()
|
||||
else
|
||||
env.warning("RotorOps transport helo message skipped")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
---BASE CAPTURE EVENTS --doesn't work with FARPs..
|
||||
if (world.event.S_EVENT_BASE_CAPTURED == event.id) then
|
||||
env.info("Base captured")
|
||||
if (event.initiator:getCoalition() == 2) then
|
||||
--RotorOps.gameMsg(RotorOps.gameMsgs.farp_established)
|
||||
env.info("Blue forces captured a base")
|
||||
end
|
||||
if (event.place:getCoalition() == 2) then
|
||||
env.info("Blue forces captured a base via place attribute")
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
|
||||
@ -258,7 +294,8 @@ end
|
||||
|
||||
|
||||
local function debugTable(table)
|
||||
trigger.action.outText("dbg: ".. mist.utils.tableShow(table), 5)
|
||||
--trigger.action.outText("dbg: ".. mist.utils.tableShow(table), 5)
|
||||
env.info("ROTOROPS_DEBUG: ".. mist.utils.tableShow(table))
|
||||
end
|
||||
|
||||
|
||||
@ -422,45 +459,7 @@ function RotorOps.spawnGroupOnGroup(grp, src_grp_name, ai_task) --allow to spawn
|
||||
end
|
||||
end
|
||||
|
||||
--Spawn infantry in a trigger zone. Uses CTLD but may use another method in the future. Side is "red" or "blue"
|
||||
--function RotorOps.spawnInfantryInZone(vars)
|
||||
-- --local group = {mg=1,at=0,aa=0,inf=4,mortar=0}
|
||||
--
|
||||
-- local _triggerName = vars.zone
|
||||
-- local _groupSide = vars.side
|
||||
-- local _number = vars.qty
|
||||
-- local _searchRadius = 500
|
||||
--
|
||||
-- local _spawnTrigger = trigger.misc.getZone(_triggerName) -- trigger to use as reference position
|
||||
--
|
||||
-- if _spawnTrigger == nil then
|
||||
-- env.warning("ERROR: Cant find zone called " .. _triggerName)
|
||||
-- return
|
||||
-- end
|
||||
--
|
||||
-- local _country
|
||||
-- if _groupSide == "red" then
|
||||
-- _groupSide = 1
|
||||
-- _country = 0
|
||||
-- else
|
||||
-- _groupSide = 2
|
||||
-- _country = 2
|
||||
-- end
|
||||
--
|
||||
-- if _searchRadius < 0 then
|
||||
-- _searchRadius = 0
|
||||
-- end
|
||||
--
|
||||
-- local _pos2 = { x = _spawnTrigger.point.x, y = _spawnTrigger.point.z }
|
||||
-- local _alt = land.getHeight(_pos2)
|
||||
-- local _pos3 = { x = _pos2.x, y = _alt, z = _pos2.y }
|
||||
--
|
||||
-- local _groupDetails = ctld.generateTroopTypes(_groupSide, _number, _country)
|
||||
--
|
||||
-- local _droppedTroops = ctld.spawnDroppedGroup(_pos3, _groupDetails, false, _searchRadius);
|
||||
-- --debugMsg(_groupDetails.groupName)
|
||||
-- return _groupDetails.groupName --_ { units = _troops, groupId = _groupId, groupName = string.format("%s %i", _groupName, _groupId), side = _side, country = _country, weight = _weight, jtac = _hasJTAC }
|
||||
--end
|
||||
|
||||
|
||||
--Easy way to deploy troops from a vehicle with waypoint action. Spawns from the first valid unit found in a group
|
||||
function RotorOps.deployTroops(quantity, target_group, announce)
|
||||
@ -470,13 +469,14 @@ function RotorOps.deployTroops(quantity, target_group, announce)
|
||||
else
|
||||
target_group_obj = target_group
|
||||
end
|
||||
debugMsg("DeployTroops on group: "..target_group_obj:getName())
|
||||
local valid_unit = RotorOps.getValidUnitFromGroup(target_group_obj)
|
||||
if not valid_unit then return end
|
||||
local coalition = valid_unit:getCoalition()
|
||||
local side = "red"
|
||||
if coalition == 2 then side = "blue" end
|
||||
local point = valid_unit:getPoint()
|
||||
ctld.spawnGroupAtPoint(side, quantity, point, 1000)
|
||||
ctld.spawnGroupAtPoint(side, quantity, point, 3000)
|
||||
|
||||
-- voiceover trigger stuff
|
||||
for index, zone in pairs(RotorOps.zones)
|
||||
@ -811,6 +811,7 @@ function RotorOps.aiExecute(vars)
|
||||
local speed = RotorOps.ground_speed
|
||||
local force_offroad = RotorOps.force_offroad
|
||||
mist.groupToPoint(group_name, RotorOps.active_zone, formation, final_heading, speed, force_offroad)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@ -945,7 +946,7 @@ function RotorOps.assessUnitsInZone(var)
|
||||
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.."%")
|
||||
debugMsg("Staged units remaining percent: "..percent_staged_remain.."%")
|
||||
|
||||
|
||||
--is the game finished?
|
||||
@ -1156,7 +1157,7 @@ function RotorOps.setActiveZone(new_index)
|
||||
|
||||
if not RotorOps.defending then
|
||||
|
||||
if old_index > 0 then
|
||||
if old_index > 0 and RotorOps.apcs_spawn_infantry == false then
|
||||
ctld.activatePickupZone(RotorOps.zones[old_index].name) --make the captured zone a pickup zone
|
||||
end
|
||||
ctld.deactivatePickupZone(RotorOps.zones[new_index].name)
|
||||
@ -1196,6 +1197,7 @@ function RotorOps.setupCTLD()
|
||||
return
|
||||
end
|
||||
|
||||
ctld.Debug = false
|
||||
ctld.enableCrates = RotorOps.CTLD_crates
|
||||
ctld.enabledFOBBuilding = false
|
||||
ctld.JTAC_lock = "vehicle"
|
||||
@ -1217,6 +1219,7 @@ function RotorOps.setupCTLD()
|
||||
["UH-1H"] = 10,
|
||||
["Mi-8MT"] = 24,
|
||||
["Mi-24P"] = 8,
|
||||
["UH-60L"] = 11,
|
||||
}
|
||||
|
||||
ctld.loadableGroups = {
|
||||
@ -1228,8 +1231,19 @@ function RotorOps.setupCTLD()
|
||||
{name = "JTAC Group (4)", inf = 3, jtac = 1 },
|
||||
{name = "Small Platoon (16)", inf = 9, mg = 3, at = 3, aa = 1 },
|
||||
{name = "Platoon (24)", inf = 10, mg = 5, at = 6, aa = 3 },
|
||||
}
|
||||
|
||||
-- ctld.dropOffZones = {
|
||||
-- { "ALPHA", "none", 1 },
|
||||
-- { "BRAVO", "none", 1 },
|
||||
-- { "CHARLIE", "none", 1 },
|
||||
-- { "DELTA", "none", 1 },
|
||||
-- }
|
||||
--
|
||||
-- ctld.transportPilotNames[#ctld.transportPilotNames + 1] = "Enemy Transport Helicopters Pilot #1"
|
||||
-- ctld.transportPilotNames[#ctld.transportPilotNames + 1] = "Enemy Transport Helicopters Pilot #2"
|
||||
|
||||
|
||||
}
|
||||
end
|
||||
|
||||
|
||||
@ -1250,7 +1264,7 @@ function RotorOps.addZone(_name, _zone_defenders_flag)
|
||||
table.insert(RotorOps.zones, {name = _name, defenders_status_flag = _zone_defenders_flag})
|
||||
trigger.action.setUserFlag(_zone_defenders_flag, 101)
|
||||
RotorOps.drawZones()
|
||||
RotorOps.addPickupZone(_name, "blue", -1, "no", 0)
|
||||
RotorOps.addPickupZone(_name, RotorOps.pickup_zone_smoke, -1, "no", 2)
|
||||
end
|
||||
|
||||
function RotorOps.stagingZone(_name)
|
||||
@ -1332,33 +1346,128 @@ function RotorOps.startConflict()
|
||||
end
|
||||
|
||||
|
||||
function RotorOps.triggerSpawn(groupName, msg)
|
||||
function RotorOps.triggerSpawn(groupName, msg, resume_task)
|
||||
local group = Group.getByName(groupName)
|
||||
if not group then
|
||||
env.warning("RotorOps tried to spawn "..groupName.." but it doesn't exist.")
|
||||
return nil
|
||||
end
|
||||
if group and group:isExist() == true and #group:getUnits() > 0 and group:getUnits()[1]:getLife() > 1 and group:getUnits()[1]:isActive() then
|
||||
env.info("RotorOps tried to respawn "..groupName.." but it's already active.")
|
||||
return nil
|
||||
else
|
||||
local new_group = mist.respawnGroup(groupName, true)
|
||||
local new_group = mist.respawnGroup(groupName, resume_task)
|
||||
if new_group then
|
||||
RotorOps.gameMsg(msg)
|
||||
if msg ~= nil then
|
||||
RotorOps.gameMsg(msg)
|
||||
end
|
||||
env.info("RotorOps spawned "..groupName)
|
||||
return new_group
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
|
||||
end
|
||||
|
||||
|
||||
function RotorOps.spawnAttackHelos()
|
||||
RotorOps.triggerSpawn("Enemy Attack Helicopters", RotorOps.gameMsgs.attack_helos_prep)
|
||||
RotorOps.triggerSpawn("Enemy Attack Helicopters", RotorOps.gameMsgs.attack_helos_prep, true)
|
||||
end
|
||||
|
||||
|
||||
function RotorOps.spawnAttackPlanes()
|
||||
RotorOps.triggerSpawn("Enemy Attack Planes", RotorOps.gameMsgs.attack_planes_prep)
|
||||
RotorOps.triggerSpawn("Enemy Attack Planes", RotorOps.gameMsgs.attack_planes_prep, true)
|
||||
end
|
||||
|
||||
|
||||
|
||||
function RotorOps.farpEstablished(index)
|
||||
env.info("RotorOps FARP established at"..RotorOps.zones[index].name)
|
||||
timer.scheduleFunction(function()RotorOps.gameMsg(RotorOps.gameMsgs.farp_established, index) end, {}, timer.getTime() + 15)
|
||||
end
|
||||
|
||||
|
||||
function RotorOps.getEnemyZones()
|
||||
local enemy_zones = {}
|
||||
|
||||
if RotorOps.defending then
|
||||
|
||||
for index, zone in pairs(RotorOps.zones) do
|
||||
if index <= RotorOps.active_zone_index then
|
||||
enemy_zones[#enemy_zones + 1] = zone
|
||||
end
|
||||
end
|
||||
|
||||
else --not defending
|
||||
|
||||
for index, zone in pairs(RotorOps.zones) do
|
||||
if index >= RotorOps.active_zone_index then
|
||||
enemy_zones[#enemy_zones + 1] = zone.name
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
debugMsg("Got enemy zones:")
|
||||
debugTable(enemy_zones)
|
||||
return enemy_zones
|
||||
end
|
||||
|
||||
|
||||
function RotorOps.spawnTranspHelos(troops, max_drops)
|
||||
|
||||
local dropTroops = {
|
||||
id = 'WrappedAction',
|
||||
params = {
|
||||
action = {
|
||||
id = 'Script',
|
||||
params = {
|
||||
command = 'RotorOps.deployTroops('..troops..', ...)',
|
||||
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
local group = Group.getByName("Enemy Transport Helicopters")
|
||||
local initial_point = group:getUnits()[1]:getPoint()
|
||||
local gp = mist.getGroupData("Enemy Transport Helicopters")
|
||||
--debugTable(gp)
|
||||
|
||||
local drop_zones = RotorOps.getEnemyZones()
|
||||
gp.route = {points = {}}
|
||||
gp.route.points[#gp.route.points + 1] = mist.heli.buildWP(initial_point, 'flyover', 80, 400, 'agl')
|
||||
|
||||
local failsafe = 100
|
||||
local drop_qty = 0
|
||||
while drop_qty < max_drops do
|
||||
|
||||
for i = 1, 10 do --pick some random points to evaluate
|
||||
local zone_name = drop_zones[math.random(#drop_zones)]
|
||||
local zone_point = trigger.misc.getZone(zone_name).point
|
||||
local drop_point = mist.getRandomPointInZone(zone_name, 300)
|
||||
|
||||
if mist.isTerrainValid(drop_point, {'LAND', 'ROAD'}) == true then --if the point looks like a good drop point
|
||||
gp.route.points[#gp.route.points + 1] = mist.heli.buildWP(zone_point, 'flyover', 80, 400, 'agl')
|
||||
gp.route.points[#gp.route.points + 1] = mist.heli.buildWP(zone_point, 'flyover', 20, 200, 'agl')
|
||||
gp.route.points[#gp.route.points + 1] = mist.heli.buildWP(drop_point, 'turning point', 10, 70, 'agl')
|
||||
gp.route.points[#gp.route.points].task = dropTroops
|
||||
drop_qty = drop_qty + 1
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
failsafe = failsafe - 1
|
||||
if failsafe < 1 then
|
||||
env.error("ROTOROPS: FINDING DROP POINTS TOOK TOO LONG")
|
||||
break
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
gp.route.points[#gp.route.points + 1] = mist.heli.buildWP(initial_point, 'flyover', 80, 400, 'agl')
|
||||
gp.clone = true
|
||||
mist.dynAdd(gp)
|
||||
env.info("ROTOROPS: TRANSPORT HELICOPTER DEPARTING WITH "..drop_qty.." PLANNED TROOP DROPS.")
|
||||
|
||||
|
||||
end
|
||||
|
||||
1
license.txt
Normal file
1
license.txt
Normal file
@ -0,0 +1 @@
|
||||
Use of this software or derivitives of this software is not permitted on 24/7 public multiplayer servers without permission. Scheduled events are excepted.
|
||||
BIN
sound/embedded/forward_base_established.ogg
Normal file
BIN
sound/embedded/forward_base_established.ogg
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user