diff --git a/Generator/MissionGenerator.py b/Generator/MissionGenerator.py index ea688ee..242cde4 100644 --- a/Generator/MissionGenerator.py +++ b/Generator/MissionGenerator.py @@ -177,22 +177,28 @@ class Window(QMainWindow, Ui_MainWindow): if result["success"]: print(result["filename"] + "' successfully generated in " + result["directory"]) self.statusbar.showMessage(result["filename"] + "' successfully generated in " + result["directory"], 10000) - msg = QMessageBox() - msg.setWindowTitle("Mission Generated") - msg.setText("Awesome, your mission is ready! It's located in this directory: \n" + - self.m.output_dir + "\n" + - "\n" + - "Next, you should use the DCS Mission Editor to fine tune unit placements. Don't be afraid to edit the missions that this generator produces. \n" + - "\n" + - "There are no hidden script changes, everything is visible in the ME. Triggers have been created to help you to add your own actions based on active zone and game status. \n" + - "\n" + - "Units can be changed or moved without issue. Player slots can be changed or moved without issue. \n" + - "\n" + - "Don't forget, you can also create your own templates that can include any mission options, objects, or even scripts. \n" + - "\n" + - "Have fun! \n" - ) - x = msg.exec_() + msg = QMessageBox() + msg.setWindowTitle("Mission Generated") + msg.setText("Awesome, your mission is ready! It's located in this directory: \n" + + self.m.output_dir + "\n" + + "\n" + + "Next, you should use the DCS Mission Editor to fine tune unit placements. Don't be afraid to edit the missions that this generator produces. \n" + + "\n" + + "There are no hidden script changes, everything is visible in the ME. Triggers have been created to help you to add your own actions based on active zone and game status. \n" + + "\n" + + "Units can be changed or moved without issue. Player slots can be changed or moved without issue. \n" + + "\n" + + "Don't forget, you can also create your own templates that can include any mission options, objects, or even scripts. \n" + + "\n" + + "Have fun! \n" + ) + x = msg.exec_() + elif not result["success"]: + print(result["failure_msg"]) + msg = QMessageBox() + msg.setWindowTitle("Error") + msg.setText(result["failure_msg"]) + x = msg.exec_() diff --git a/Generator/MissionGeneratorUI.py b/Generator/MissionGeneratorUI.py index ae5fdd3..d1f8dda 100644 --- a/Generator/MissionGeneratorUI.py +++ b/Generator/MissionGeneratorUI.py @@ -139,12 +139,14 @@ class Ui_MainWindow(object): font.setPointSize(11) self.awacs_checkBox.setFont(font) self.awacs_checkBox.setStatusTip("") + self.awacs_checkBox.setChecked(True) self.awacs_checkBox.setObjectName("awacs_checkBox") self.tankers_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.tankers_checkBox.setGeometry(QtCore.QRect(970, 450, 251, 31)) font = QtGui.QFont() font.setPointSize(11) self.tankers_checkBox.setFont(font) + self.tankers_checkBox.setChecked(True) self.tankers_checkBox.setObjectName("tankers_checkBox") self.apcs_spawn_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.apcs_spawn_checkBox.setGeometry(QtCore.QRect(500, 400, 251, 31)) @@ -242,7 +244,7 @@ class Ui_MainWindow(object): self.e_attack_planes_spinBox.setFont(font) self.e_attack_planes_spinBox.setMinimum(0) self.e_attack_planes_spinBox.setMaximum(50) - self.e_attack_planes_spinBox.setProperty("value", 2) + self.e_attack_planes_spinBox.setProperty("value", 1) self.e_attack_planes_spinBox.setObjectName("e_attack_planes_spinBox") self.zone_sams_checkBox = QtWidgets.QCheckBox(self.centralwidget) self.zone_sams_checkBox.setGeometry(QtCore.QRect(970, 480, 201, 31)) @@ -350,11 +352,11 @@ class Ui_MainWindow(object): 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", "This value is multiplied by the number of spawn zones in the mission template.")) + self.e_attack_helos_spinBox.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.setText(_translate("MainWindow", "Enemy Attack Planes")) - self.e_attack_planes_spinBox.setStatusTip(_translate("MainWindow", "This value is multiplied by the number of spawn zones in the mission template.")) - 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 by a large explosion at zone center. ")) + self.e_attack_planes_spinBox.setStatusTip(_translate("MainWindow", "Approximate number of enemy attack plane group spawns.")) + self.zone_sams_checkBox.setStatusTip(_translate("MainWindow", "Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed.")) self.zone_sams_checkBox.setText(_translate("MainWindow", "Inactive Zone SAMs")) self.action_generateMission.setText(_translate("MainWindow", "_generateMission")) self.action_scenarioSelected.setText(_translate("MainWindow", "_scenarioSelected")) diff --git a/Generator/MissionGeneratorUI.ui b/Generator/MissionGeneratorUI.ui index 8470f3d..3c32722 100644 --- a/Generator/MissionGeneratorUI.ui +++ b/Generator/MissionGeneratorUI.ui @@ -662,7 +662,7 @@ p, li { white-space: pre-wrap; } - This value is multiplied by the number of spawn zones in the mission template. + Approximate number of enemy attack helicopter group spawns. 0 @@ -725,7 +725,7 @@ p, li { white-space: pre-wrap; } - This value is multiplied by the number of spawn zones in the mission template. + Approximate number of enemy attack plane group spawns. 0 @@ -734,7 +734,7 @@ p, li { white-space: pre-wrap; } 50 - 2 + 1 @@ -752,7 +752,7 @@ p, li { white-space: pre-wrap; } - Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed by a large explosion at zone center. + Inactive conflict zones will be protected by SAMs. When a zone is cleared, SAMs at next active zone will be destroyed. Inactive Zone SAMs diff --git a/Generator/RotorOpsMission.py b/Generator/RotorOpsMission.py index 137f126..558e314 100644 --- a/Generator/RotorOpsMission.py +++ b/Generator/RotorOpsMission.py @@ -10,16 +10,11 @@ import time class RotorOpsMission: - conflict_zones = {} - staging_zones = {} - spawn_zones = {} - scripts = {} + def __init__(self): self.m = dcs.mission.Mission() - self.old_blue = self.m.coalition.get("blue").dict() - self.old_red = self.m.coalition.get("red").dict() os.chdir("../") self.home_dir = os.getcwd() self.scenarios_dir = self.home_dir + "\Generator\Scenarios" @@ -29,6 +24,11 @@ class RotorOpsMission: self.output_dir = self.home_dir + "\Generator\Output" self.assets_dir = self.home_dir + "\Generator/assets" + self.conflict_zones = {} + self.staging_zones = {} + self.spawn_zones = {} + self.scripts = {} + class RotorOpsZone: def __init__(self, name: str, flag: int, position: dcs.point, size: int): @@ -94,9 +94,9 @@ class RotorOpsMission: self.m.load_file(options["scenario_filename"]) - #Load the default coalitions for simplicity - self.m.coalition.get("blue").load_from_dict(self.m, self.old_blue) - self.m.coalition.get("red").load_from_dict(self.m, self.old_red) + if not self.m.country("Russia") or not self.m.country("USA"): + 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") @@ -160,7 +160,7 @@ class RotorOpsMission: self.addGroundGroups(blue_zones[zone_name], self.m.country('USA'), blue_forces, options["blue_quantity"]) - if options["zone_protect_sams"]: + if options["zone_protect_sams"] and options["defending"]: for zone_name in blue_zones: self.m.vehicle_group( self.m.country('USA'), @@ -203,13 +203,14 @@ 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, 500) + #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, - pos1.random_point_within(zone.size / 2, 500), + 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, ) @@ -225,28 +226,70 @@ class RotorOpsMission: 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 + #Find parking spots on FARPs and carriers + def getUnitParking(self, aircraft): + return + def addSinglePlayerHelos(self, helotype): + + 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") - for airport_name in friendly_airports: - fg = self.m.flight_group_from_airport(self.m.country('USA'), "Player Helos", helotype, - self.m.terrain.airports[airport_name], group_size=2) - fg.units[0].set_player() + + 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") - for airport_name in friendly_airports: - for helotype in RotorOpsUnits.client_helos: - 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.units[0].set_client() + + heading = 0 + for helotype in RotorOpsUnits.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) + elif farp: + fg = self.m.flight_group_from_unit(self.m.country('USA'), "FARP " + helotype.id, helotype, farp, + dcs.task.CAS, group_size=1) + + #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(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.units[0].set_client() class TrainingScenario(): @@ -361,6 +404,8 @@ class RotorOpsMission: fg.add_runway_waypoint(enemy_airport) fg.land_at(enemy_airport) + + if options["e_attack_helos"]: helo = random.choice(RotorOpsUnits.e_attack_helos) afg = self.m.flight_group_from_airport( @@ -392,13 +437,13 @@ class RotorOpsMission: game_flag = 100 #Add the first trigger - mytrig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Scripts") - mytrig.rules.append(dcs.condition.TimeAfter(1)) - mytrig.actions.append(dcs.action.DoScriptFile(self.scripts["mist_4_4_90.lua"])) - mytrig.actions.append(dcs.action.DoScriptFile(self.scripts["Splash_Damage_2_0.lua"])) - mytrig.actions.append(dcs.action.DoScriptFile(self.scripts["CTLD.lua"])) - mytrig.actions.append(dcs.action.DoScriptFile(self.scripts["RotorOps.lua"])) - mytrig.actions.append(dcs.action.DoScript(dcs.action.String(( + trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Scripts") + trig.rules.append(dcs.condition.TimeAfter(1)) + trig.actions.append(dcs.action.DoScriptFile(self.scripts["mist_4_4_90.lua"])) + trig.actions.append(dcs.action.DoScriptFile(self.scripts["Splash_Damage_2_0.lua"])) + trig.actions.append(dcs.action.DoScriptFile(self.scripts["CTLD.lua"])) + trig.actions.append(dcs.action.DoScriptFile(self.scripts["RotorOps.lua"])) + trig.actions.append(dcs.action.DoScript(dcs.action.String(( "--OPTIONS HERE!\n\n" + "RotorOps.CTLD_crates = " + lb("crates") + "\n\n" + "RotorOps.CTLD_sound_effects = true\n\n" + @@ -407,26 +452,26 @@ class RotorOpsMission: "RotorOps.zone_status_display = " + lb("game_display") + "\n\n" + "RotorOps.inf_spawns_per_zone = " + lb("inf_spawn_qty") + "\n\n" + "RotorOps.apcs_spawn_infantry = " + lb("apc_spawns_inf") + " \n\n")))) - self.m.triggerrules.triggers.append(mytrig) + self.m.triggerrules.triggers.append(trig) #Add the second trigger - mytrig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Zones") - mytrig.rules.append(dcs.condition.TimeAfter(2)) + trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Zones") + trig.rules.append(dcs.condition.TimeAfter(2)) for s_zone in self.staging_zones: - mytrig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.stagingZone('" + s_zone + "')"))) + trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.stagingZone('" + s_zone + "')"))) for c_zone in self.conflict_zones: zone_flag = self.conflict_zones[c_zone].flag - mytrig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.addZone('" + c_zone + "'," + str(zone_flag) + ")"))) + trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.addZone('" + c_zone + "'," + str(zone_flag) + ")"))) - mytrig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.setupConflict('" + str(game_flag) + "')"))) + trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.setupConflict('" + str(game_flag) + "')"))) - self.m.triggerrules.triggers.append(mytrig) + self.m.triggerrules.triggers.append(trig) #Add the third trigger - mytrig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict Start") - mytrig.rules.append(dcs.condition.TimeAfter(10)) - mytrig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.startConflict(100)"))) - self.m.triggerrules.triggers.append(mytrig) + trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict Start") + trig.rules.append(dcs.condition.TimeAfter(10)) + trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.startConflict(100)"))) + self.m.triggerrules.triggers.append(trig) #Add all zone-based triggers for index, zone_name in enumerate(self.conflict_zones): @@ -453,7 +498,7 @@ class RotorOpsMission: 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("mist.respawnGroup('Enemy Attack Helicopters', true)"))) + z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.spawnAttackHelos()"))) self.m.triggerrules.triggers.append(z_weak_trig) #Add attack plane triggers @@ -464,18 +509,18 @@ class RotorOpsMission: 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("mist.respawnGroup('Enemy Attack Planes', true)"))) + z_weak_trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.spawnAttackPlanes()"))) self.m.triggerrules.triggers.append(z_weak_trig) #Add game won/lost triggers - mytrig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict WON") - mytrig.rules.append(dcs.condition.FlagEquals(game_flag, 99)) - mytrig.actions.append(dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is WON"))) - self.m.triggerrules.triggers.append(mytrig) + trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict WON") + trig.rules.append(dcs.condition.FlagEquals(game_flag, 99)) + trig.actions.append(dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is WON"))) + self.m.triggerrules.triggers.append(trig) - mytrig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict LOST") - mytrig.rules.append(dcs.condition.FlagEquals(game_flag, 98)) - mytrig.actions.append(dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is LOST"))) - self.m.triggerrules.triggers.append(mytrig) + trig = dcs.triggers.TriggerOnce(comment="RotorOps Conflict LOST") + trig.rules.append(dcs.condition.FlagEquals(game_flag, 98)) + trig.actions.append(dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is LOST"))) + self.m.triggerrules.triggers.append(trig) diff --git a/Generator/Scenarios/Caucasus Conflict - Batumi to Kobuleti (GRIMM).miz b/Generator/Scenarios/Caucasus Conflict - Batumi to Kobuleti (GRIMM).miz index bdff90b..78a8300 100644 Binary files a/Generator/Scenarios/Caucasus Conflict - Batumi to Kobuleti (GRIMM).miz and b/Generator/Scenarios/Caucasus Conflict - Batumi to Kobuleti (GRIMM).miz differ diff --git a/Generator/Scenarios/Caucasus Conflict - Nalchik to Beslan (GRIMM).miz b/Generator/Scenarios/Caucasus Conflict - Nalchik to Beslan (GRIMM).miz index 3272359..693096c 100644 Binary files a/Generator/Scenarios/Caucasus Conflict - Nalchik to Beslan (GRIMM).miz and b/Generator/Scenarios/Caucasus Conflict - Nalchik to Beslan (GRIMM).miz differ diff --git a/Generator/Scenarios/Mariana Conflict - Anderson to Won Pat (GRIMM).miz b/Generator/Scenarios/Mariana Conflict - Anderson to Won Pat (GRIMM).miz index ab75887..544c62c 100644 Binary files a/Generator/Scenarios/Mariana Conflict - Anderson to Won Pat (GRIMM).miz and b/Generator/Scenarios/Mariana Conflict - Anderson to Won Pat (GRIMM).miz differ diff --git a/Generator/Scenarios/Nevada Conflict - Vegas Tour (GRIMM).miz b/Generator/Scenarios/Nevada Conflict - Vegas Tour (GRIMM).miz index 941380f..4a47022 100644 Binary files a/Generator/Scenarios/Nevada Conflict - Vegas Tour (GRIMM).miz and b/Generator/Scenarios/Nevada Conflict - Vegas Tour (GRIMM).miz differ diff --git a/Generator/Scenarios/PG Conflict - Abu Dhabi to Ras (GRIMM).miz b/Generator/Scenarios/PG Conflict - Abu Dhabi to Ras (GRIMM).miz index ef54d1f..e1e6964 100644 Binary files a/Generator/Scenarios/PG Conflict - Abu Dhabi to Ras (GRIMM).miz and b/Generator/Scenarios/PG Conflict - Abu Dhabi to Ras (GRIMM).miz differ diff --git a/Generator/Scenarios/Syria Conflict - (inv FARP) Aleppo Tour (GRIMM).miz b/Generator/Scenarios/Syria Conflict - (inv FARP) Aleppo Tour (GRIMM).miz new file mode 100644 index 0000000..aff8436 Binary files /dev/null and b/Generator/Scenarios/Syria Conflict - (inv FARP) Aleppo Tour (GRIMM).miz differ diff --git a/Generator/Scenarios/Syria Conflict - Aleppo Tour (GRIMM).miz b/Generator/Scenarios/Syria Conflict - Aleppo Tour (GRIMM).miz index d936511..940a2af 100644 Binary files a/Generator/Scenarios/Syria Conflict - Aleppo Tour (GRIMM).miz and b/Generator/Scenarios/Syria Conflict - Aleppo Tour (GRIMM).miz differ diff --git a/Generator/Scenarios/_How to create your own scenarios.txt b/Generator/Scenarios/_How to create your own scenarios.txt index f343852..24b9f90 100644 --- a/Generator/Scenarios/_How to create your own scenarios.txt +++ b/Generator/Scenarios/_How to create your own scenarios.txt @@ -1,20 +1,35 @@ -You can add your own scenarios in this directory and they will appear in the mission generator. +You can add your own scenarios in this directory and they will appear in the mission generator. See the other scenario .miz files for examples of what to include in your template. + A scenario .miz file MUST have: 1) Between 1-4 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 your staging zone). -4) A red airport (recommend somewhere near your last conflict zone). +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). +5) At least one Russian unit or static object. Anything will work, even a cow. You can set "HIDDEN ON MAP". +6) At least one USA unit or static object. See previous point. + + Optional: -You can add smaller infantry spawning zones inside conflict zones. Add near buildings to simulate infantry hiding within. Name them like "ALPHA_SPAWN", "ALPHA_SPAWN_2, etc. +7) USA FARP called "HELO_FARP" for automatic player placement. +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. -The conflict game type can be played with blue forces on defense. In this mode the last conflict zone is the only troop pickup zone. -Design your template so that it can be played in normal 'attacking' mode or 'defending' the conflict zone from enemy ground units starting from the staging zone. -Keep the zones fairly close together, both for helicopter and ground unit travel times. -You can place static objects and units in a scenario template. -You can change mission briefing and other mission options in the template. -Drop your templates in the RotorOps Discord if you'd like to have them added in a release for everyone. Maintain a similar naming convention and be sure to credit yourself in the .miz name. --Airfields can be captured with ground units. You might consider placing conflict zones over neutral airfields and adding unarmed client slots. +-Airfields can be captured with ground units. You might consider placing conflict zones over neutral airfields for a rearming area, or perhaps unarmed client slots. +-Player/client slots are placed in this priority order: Carrier named "HELO_CARRIER", FARP named "HELO_FARP", and the blue airfield. +-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. + diff --git a/Mission Templates/RotorOps_template_Caucasus.miz b/Mission Templates/RotorOps_template_Caucasus.miz deleted file mode 100644 index 841ab03..0000000 Binary files a/Mission Templates/RotorOps_template_Caucasus.miz and /dev/null differ diff --git a/Mission Templates/RotorOps_template_Mariana.miz b/Mission Templates/RotorOps_template_Mariana.miz deleted file mode 100644 index 2a0edd8..0000000 Binary files a/Mission Templates/RotorOps_template_Mariana.miz and /dev/null differ diff --git a/Mission Templates/RotorOps_template_Nevada.miz b/Mission Templates/RotorOps_template_Nevada.miz deleted file mode 100644 index 2a0edd8..0000000 Binary files a/Mission Templates/RotorOps_template_Nevada.miz and /dev/null differ diff --git a/Mission Templates/RotorOps_template_Normandy.miz b/Mission Templates/RotorOps_template_Normandy.miz deleted file mode 100644 index 2a0edd8..0000000 Binary files a/Mission Templates/RotorOps_template_Normandy.miz and /dev/null differ diff --git a/Mission Templates/RotorOps_template_Persian_Gulf.miz b/Mission Templates/RotorOps_template_Persian_Gulf.miz deleted file mode 100644 index 2a0edd8..0000000 Binary files a/Mission Templates/RotorOps_template_Persian_Gulf.miz and /dev/null differ diff --git a/Mission Templates/RotorOps_template_Syria.miz b/Mission Templates/RotorOps_template_Syria.miz deleted file mode 100644 index 2a0edd8..0000000 Binary files a/Mission Templates/RotorOps_template_Syria.miz and /dev/null differ diff --git a/Mission Templates/RotorOps_template_The_Channel.miz b/Mission Templates/RotorOps_template_The_Channel.miz deleted file mode 100644 index 2a0edd8..0000000 Binary files a/Mission Templates/RotorOps_template_The_Channel.miz and /dev/null differ diff --git a/MissionGenerator.exe b/MissionGenerator.exe index 80c0193..a01cc02 100644 Binary files a/MissionGenerator.exe and b/MissionGenerator.exe differ diff --git a/RotorOps.lua b/RotorOps.lua index b297c16..b1391fd 100644 --- a/RotorOps.lua +++ b/RotorOps.lua @@ -23,7 +23,7 @@ RotorOps.inf_spawns_per_zone = 3 --number of infantry groups to spawn per zone --RotorOps settings that are safe to change only before calling setupConflict() -RotorOps.transports = {'UH-1H', 'Mi-8MT', 'Mi-24P', 'SA342M', 'SA342L', 'SA342Mistral'} --players flying these will have ctld transport access +RotorOps.transports = {'UH-1H', 'Mi-8MT', 'Mi-24P', 'SA342M', 'SA342L', 'SA342Mistral', 'UH-60L'} --players flying these will have ctld transport access RotorOps.CTLD_crates = false RotorOps.CTLD_sound_effects = true --sound effects for troop pickup/dropoffs RotorOps.exclude_ai_group_name = "noai" --include this somewhere in a group name to exclude the group from being tasked in the active zone @@ -138,6 +138,13 @@ RotorOps.gameMsgs = { {'ENEMY TOOK CHARLIE!', 'enemy_destroying_us.ogg'}, {'ENEMY TOOK DELTA!', 'enemy_destroying_us.ogg'}, }, + attack_helos = { + {'ENEMY ATTACK HELICOPTERS INBOUND!', 'enemy_attack_choppers.ogg'}, + }, + attack_planes = { + {'ENEMY ATTACK PLANES INBOUND!', 'enemy_attack_planes.ogg'}, + }, + } @@ -1243,6 +1250,32 @@ function RotorOps.startConflict() end +function RotorOps.triggerSpawn(groupName, msg) + local group = Group.getByName(groupName) + 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.") + else + local new_group = mist.respawnGroup(groupName, true) + if new_group then + RotorOps.gameMsg(msg) + 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) +end + + +function RotorOps.spawnAttackPlanes() + RotorOps.triggerSpawn("Enemy Attack Planes", RotorOps.gameMsgs.attack_planes) +end diff --git a/sound/convoy_forward_base.ogg b/sound/convoy_forward_base.ogg new file mode 100644 index 0000000..56108e6 Binary files /dev/null and b/sound/convoy_forward_base.ogg differ diff --git a/sound/downed_pilot.ogg b/sound/downed_pilot.ogg new file mode 100644 index 0000000..c62b587 Binary files /dev/null and b/sound/downed_pilot.ogg differ diff --git a/sound/embedded/enemy_attack_choppers.ogg b/sound/embedded/enemy_attack_choppers.ogg new file mode 100644 index 0000000..b875c57 Binary files /dev/null and b/sound/embedded/enemy_attack_choppers.ogg differ diff --git a/sound/embedded/enemy_attack_planes.ogg b/sound/embedded/enemy_attack_planes.ogg new file mode 100644 index 0000000..8fba8b8 Binary files /dev/null and b/sound/embedded/enemy_attack_planes.ogg differ diff --git a/sound/embedded/enemy_chopper_inbound.ogg b/sound/embedded/enemy_chopper_inbound.ogg new file mode 100644 index 0000000..e14c1b4 Binary files /dev/null and b/sound/embedded/enemy_chopper_inbound.ogg differ diff --git a/sound/embedded/enemy_fighters_inbound.ogg b/sound/embedded/enemy_fighters_inbound.ogg new file mode 100644 index 0000000..cc1cd09 Binary files /dev/null and b/sound/embedded/enemy_fighters_inbound.ogg differ diff --git a/sound/forward_base_established.ogg b/sound/forward_base_established.ogg new file mode 100644 index 0000000..f49cbae Binary files /dev/null and b/sound/forward_base_established.ogg differ diff --git a/sound/friendly_awacs_available.ogg b/sound/friendly_awacs_available.ogg new file mode 100644 index 0000000..993ac4d Binary files /dev/null and b/sound/friendly_awacs_available.ogg differ diff --git a/sound/friendly_bombing_run_avail.ogg b/sound/friendly_bombing_run_avail.ogg new file mode 100644 index 0000000..9d08c13 Binary files /dev/null and b/sound/friendly_bombing_run_avail.ogg differ