Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1.8.0 #65

Merged
merged 22 commits into from
Mar 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
162 changes: 120 additions & 42 deletions Generator/MissionGenerator.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from PyQt5.QtGui import QPixmap, QFont
from PyQt5.QtCore import QObject, QEvent, Qt, QUrl
import resources # pyqt resource file
from Generator import aircraftMods

from MissionGeneratorUI import Ui_MainWindow

Expand Down Expand Up @@ -134,10 +135,12 @@ def __init__(self, parent=None):
self.scenarios_list = []
self.scenario = None
self.player_slots = []
self.player_slots_from_file = None
self.user_output_dir = None
self.user_data = None
self.forces_list = []
self.imports_list = []
self.current_config = None

self.user_data = self.loadUserData()

Expand Down Expand Up @@ -188,6 +191,7 @@ def connectSignalsSlots(self):
self.action_rateButton3.triggered.connect(self.rateButtonActionThree)
self.action_rateButton4.triggered.connect(self.rateButtonActionFour)
self.action_rateButton5.triggered.connect(self.rateButtonActionFive)
self.actionSave_Mission_Config.triggered.connect(self.saveScenarioConfig)

# Find the selected dropdown menu options and make a list of tags to filter for
def tagsFromMenuOptions(self):
Expand Down Expand Up @@ -247,7 +251,9 @@ def populateScenarios(self):
s.rating = module["avg_rating"]
s.rating_qty = module["rating_count"]


config_file_path = os.path.join(path, folder, basename + '.yaml')
s.config_file_path = config_file_path
if os.path.exists(config_file_path):
config = self.loadScenarioConfig(config_file_path)
if config:
Expand Down Expand Up @@ -348,18 +354,18 @@ def getImports(self):

def populateSlotSelection(self):
self.slot_template_comboBox.addItem("Multiple Slots")

for type in RotorOpsUnits.player_helos:
self.slot_template_comboBox.addItem(type.id)

self.slot_template_comboBox.addItem("None")

def slotChanged(self):
if self.slot_template_comboBox.currentIndex() == 0:
sd = self.slotDialog(self)
sd.exec_()
if sd.helicopter_types:
self.user_data["player_slots"] = sd.helicopter_types
self.player_slots = sd.helicopter_types
self.saveUserData()
if sd.selected_aircraft:
self.player_slots = sd.selected_aircraft


def defensiveModeChanged(self):
Expand All @@ -383,6 +389,7 @@ def loadScenarioConfig(self, filename):


def applyScenarioConfig(self, config):
self.current_config = config

# reset some UI elements
self.defense_checkBox.setEnabled(True)
Expand Down Expand Up @@ -444,6 +451,61 @@ def applyScenarioConfig(self, config):
except Exception as e:
logger.error("Error loading config file: " + str(e))

def saveScenarioConfig(self):
msg = QMessageBox()
msg.setWindowTitle("Save Mission Config")
msg.setText("This will overwrite the current mission config file and player slots. Are you sure?")
msg.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
msg.setDefaultButton(QMessageBox.No)
x = msg.exec_()
if x == QMessageBox.No:
return
config = self.current_config

config['checkboxes'] = {}
config['spinboxes'] = {}
config['radiobuttons'] = {}
config['disable_checkboxes'] = []
config['disable_spinboxes'] = []

for box in QObject.findChildren(self, QCheckBox):
config['checkboxes'][box.objectName()] = box.isChecked()

for box in QObject.findChildren(self, QSpinBox):
config['spinboxes'][box.objectName()] = box.value()

for button in QObject.findChildren(self, QRadioButton):
if button.isChecked():
config['radiobuttons'][button.objectName()] = True

for box in QObject.findChildren(self, QCheckBox):
if not box.isEnabled():
config['disable_checkboxes'].append(box.objectName())

for box in QObject.findChildren(self, QSpinBox):
if not box.isEnabled():
config['disable_spinboxes'].append(box.objectName())


config['blue_forces'] = self.forces_list[self.blueforces_comboBox.currentIndex()].basename

config['red_forces'] = self.forces_list[self.redforces_comboBox.currentIndex()].basename

if self.slot_template_comboBox.currentIndex() > 0:
config['player_spawn'] = "fixed"

config_file_path = os.path.join(self.scenario.config_file_path)
with open(config_file_path, 'w') as outfile:
yaml.dump(config, outfile)

if self.slot_template_comboBox.currentText() == "Multiple Slots":
slots = {"blue_slots": self.player_slots}
path = os.path.dirname(self.scenario.config_file_path)
slot_file = os.path.join(path, 'player_slots.yaml')
with open(slot_file, 'w') as outfile:
yaml.dump(slots, outfile)


def loadUserData(self):
prefs = {}
if os.path.exists(directories.user_datafile_path):
Expand All @@ -453,9 +515,6 @@ def loadUserData(self):
if "save_directory" in prefs:
self.user_output_dir = prefs["save_directory"]

if "player_slots" in prefs:
self.player_slots = prefs["player_slots"]

if "ratings" in prefs:
self.user_ratings = prefs["ratings"]
except:
Expand Down Expand Up @@ -507,7 +566,7 @@ def scenarioChanged(self):
self.missionImage.setPixmap(QtGui.QPixmap(directories.assets + "/briefing1.png"))

self.scenario.evaluateMiz()
self.description_textBrowser.setText(self.scenario.description)
self.description_textBrowser.setText(self.scenario.display_description)

QApplication.restoreOverrideCursor()

Expand All @@ -526,12 +585,27 @@ def scenarioChanged(self):
for button in rate_buttons:
button.setStyleSheet(star_empty_ss)


if self.user_data and 'local_ratings' in self.user_data and self.scenario.path in self.user_data["local_ratings"]:
user_rating = self.user_data['local_ratings'][self.scenario.path]
for i in range(user_rating):
rate_buttons[i].setStyleSheet(star_full_ss)

scenario_folder = os.path.dirname(self.scenario.path)

self.player_slots = []
# load the player slots for the selected scenario or from the player options

if os.path.exists(os.path.join(scenario_folder, "player_slots.yaml")):
with open(os.path.join(scenario_folder, "player_slots.yaml"), 'r') as pfile:
slots = yaml.safe_load(pfile)
self.player_slots = slots["blue_slots"]
self.player_slots_from_file = slots["blue_slots"]
print("player_slots.yaml found: loaded slots")
else:
self.player_slots = self.user_data["player_slots"]
self.player_slots_from_file = None


def generateMissionAction(self):
QApplication.setOverrideCursor(Qt.WaitCursor)

Expand Down Expand Up @@ -591,7 +665,7 @@ def generateMissionAction(self):
"advanced_defenses": self.advanced_defenses_checkBox.isChecked(),
"red_cap": self.scenario.getConfigValue("red_cap", default=True),
"blue_cap": self.scenario.getConfigValue("blue_cap", default=True),
"rotorops_server": self.scenario.getConfigValue("rotorops_server", default=False),
"rotorops_server": self.rotorops_server_checkBox.isChecked(),
"perks": self.perks_checkBox.isChecked(),
"easy_comms": self.scenario.getConfigValue("easy_comms", default=True)
}
Expand Down Expand Up @@ -659,74 +733,78 @@ def __init__(self, window, parent=None):
self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint) # remove help button
message = QLabel("Add your desired multiplayer slots here. \nIt is recommended to check placement in the \nMission Editor before flying your mission.\n")
self.layout.addWidget(message)
self.helicopter_types = None

self.selected_aircraft = None

self.slot_qty = len(window.player_slots)
self.window = window

#self.populateBoxes()

QBtn = QDialogButtonBox.Ok
self.buttonBox = QDialogButtonBox(QBtn)
self.addBtn = self.buttonBox.addButton("+", QDialogButtonBox.ActionRole)
self.removeBtn = self.buttonBox.addButton("-", QDialogButtonBox.ActionRole)
self.layout.addWidget(self.buttonBox)


self.buttonBox.accepted.connect(self.accepted)
self.buttonBox.rejected.connect(self.close)
self.addBtn.clicked.connect(self.addSlotBox)
self.removeBtn.clicked.connect(self.removeSlotBox)

self.slot_boxes = []

if "player_slots" in window.user_data:
for index in range(0, len(window.user_data["player_slots"])):
self.addSlotBox()
self.clear_and_populate(window.player_slots)

self.setLayout(self.layout)

def addSlotBox(self, aircraft_type=None):
new_slot = QComboBox()
self.slot_boxes.append(new_slot)
self.layout.addWidget(new_slot)

def populateBoxes(self):
for helicopter_id in sorted(dcs.helicopters.helicopter_map):
if dcs.helicopters.helicopter_map[helicopter_id].flyable:
new_slot.addItem(helicopter_id)

for index in range(0, self.slot_qty):
self.slot_boxes.append(QComboBox())
for type in RotorOpsUnits.player_helos:
self.slot_boxes[index].addItem(type.id)
new_slot.addItem(aircraftMods.UH_60L.id)

for index in range(0, self.slot_qty):
self.layout.addWidget(self.slot_boxes[index])
#self.slot_boxes[index].setCurrentIndex(self.slot_boxes[index].findText(self.window.user_data["player_slots"][index]))
for plane_id in sorted(dcs.planes.plane_map):
if dcs.planes.plane_map[plane_id].flyable and plane_id not in RotorOpsUnits.excluded_player_aircraft:
new_slot.addItem(plane_id)

new_slot.setCurrentIndex(0)

# use the aircraft type if provided
if aircraft_type and new_slot.findText(aircraft_type):
new_slot.setCurrentIndex(new_slot.findText(aircraft_type))

def addSlotBox(self):
new_slot = QComboBox()
self.slot_boxes.append(new_slot)
self.layout.addWidget(new_slot)
for helo_type in RotorOpsUnits.player_helos:
new_slot.addItem(helo_type.id)
# else duplicate the last slot type if it exists
elif len(self.slot_boxes) > 1:
new_slot.setCurrentIndex(self.slot_boxes[-2].currentIndex())

slot_index = len(self.slot_boxes) - 1
if "player_slots" not in self.window.user_data:
new_slot.setCurrentIndex(0)
elif slot_index < len(self.window.user_data["player_slots"]):
new_slot.setCurrentIndex(new_slot.findText(self.window.user_data["player_slots"][slot_index]))
return new_slot

def removeSlotBox(self):
last_index = len(self.slot_boxes) - 1
self.layout.removeWidget(self.slot_boxes[last_index])
self.slot_boxes.pop(last_index)

def accepted(self):
heli_types = []
self.selected_aircraft = []
for box in self.slot_boxes:
heli_types.append(box.currentText())
self.helicopter_types = heli_types
self.selected_aircraft.append(box.currentText())

if not self.window.player_slots_from_file:
# save the player slots to the user data file if they are not loaded from a file
self.window.user_data["player_slots"] = self.selected_aircraft
self.window.saveUserData()

self.window.player_slots = self.selected_aircraft
self.close()

def clear_and_populate(self, aircraft=None):
for box in self.slot_boxes:
self.layout.removeWidget(box)
self.slot_boxes = []
for aircraft_type in aircraft:
self.addSlotBox(aircraft_type)

def rateScenario(self, rating):
if "local_ratings" not in self.user_data:
self.user_data["local_ratings"] = {}
Expand Down
3 changes: 2 additions & 1 deletion Generator/MissionGeneratorTemplates.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ def __init__(self, path, name):
self.packageID = None
self.local_rating = None
self.author = "unknown"
self.display_description = ""


def applyConfig(self, config):
Expand Down Expand Up @@ -122,7 +123,7 @@ def validateTemplate():
)
if self.packageID:
description = description + "\n\nScenario module ID: " + self.packageID
self.description = description.replace("\n", "<br />")
self.display_description = description.replace("\n", "<br />")



Expand Down
Loading
Loading