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:
@@ -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"])
|
||||
|
||||
Reference in New Issue
Block a user