This commit is contained in:
spencer-ki 2022-03-01 08:31:51 -08:00
parent 0860dca3c7
commit 794a1b8053
26 changed files with 679 additions and 320 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,8 +1,17 @@
You can put .miz files in this folder to be copied into the generated mission at marker points. This feature is currently very 'alpha' and may produce errors.
You can put .miz files in this folder to be copied into the generated mission at marker points. This feature is currently very 'alpha' and may produce errors. Currently, this doesn't work for ship groups or plane groups.
1) Make an empty mission on Cauacasus.
2) Place units/objects on the map.
3) Make one unit group name: 'ANCHOR' This will represent the point of insertion into the target mission.
4) In a Scenario template, place a static object (flag, etc) and call it "IMPORT-[filename of .miz created in first step]"
Tip: You can change the heading of the imported group by changing the heading of the insertion object.
2) Place units/objects on the map.
3) Make one unit group name: 'ANCHOR' This will represent the point of insertion into the target mission.
4) In a Scenario template, place a static object (flag, etc) and call it "IMPORT-[filename of .miz created in first step]" Country should be CJTF Red, CJTF Blue, or UN Peacekeepers.
5) Change the unit name of the object created in the previous step. This unit name might be used for spawn names, so you should call the unit name something like "North Base" so players know where they'll be spawning when choosing a slot.
Tips:
-You can change the heading of the imported group by changing the heading of the insertion object.
-For multiple imports of the same template, the import object group name should end with '-01' or '-whatever'.

Binary file not shown.

View File

@ -29,7 +29,7 @@ def handle_exception(exc_type, exc_value, exc_traceback):
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.")
msg.setText("Oops, there was a problem. Please check the log file for more details or post it in the RotorOps discord where some helpful people will have a look. \n\n" + str(exc_value))
x = msg.exec_()
@ -77,8 +77,6 @@ class Window(QMainWindow, Ui_MainWindow):
self.version_label.setText("Version " + version_string)
self.prefs = None # holds json from scenario preference files
def connectSignalsSlots(self):
self.action_generateMission.triggered.connect(self.generateMissionAction)
@ -122,21 +120,21 @@ class Window(QMainWindow, Ui_MainWindow):
self.red_forces_label.setText(defenders_text)
self.blue_forces_label.setText(attackers_text)
self.applyScenarioPrefs()
self.applyScenarioConfig()
def loadScenarioPrefs(self, filename):
def loadScenarioConfig(self, filename):
try:
j = open(filename)
prefs = json.load(j)
config = json.load(j)
j.close()
return prefs
return config
except:
return None
def lockedSlot(self):
return self.slot_template_comboBox.findText("Locked to Scenario")
def clearScenarioPrefs(self):
def clearScenarioConfig(self):
# reset default states
self.defense_checkBox.setEnabled(True)
if self.lockedSlot():
@ -145,16 +143,19 @@ class Window(QMainWindow, Ui_MainWindow):
self.slot_template_comboBox.setEnabled(True)
self.slot_template_comboBox.setCurrentIndex(0)
def applyScenarioPrefs(self):
def applyScenarioConfig(self):
if self.prefs['defense']['allowed'] == False:
if not self.config:
return
if self.config['defense']['allowed'] == False:
self.defense_checkBox.setChecked(False)
self.defense_checkBox.setEnabled(False)
elif self.prefs['offense']['allowed'] == False:
elif self.config['offense']['allowed'] == False:
self.defense_checkBox.setChecked(True)
self.defense_checkBox.setEnabled(False)
if self.prefs['defense']['player_spawn'] == "fixed":
if self.config['defense']['player_spawn'] == "fixed":
self.slot_template_comboBox.addItem("Locked to Scenario")
self.slot_template_comboBox.setCurrentIndex(self.lockedSlot())
self.slot_template_comboBox.setEnabled(False)
@ -180,11 +181,12 @@ class Window(QMainWindow, Ui_MainWindow):
friendly_airports = True
enemy_airports = True
self.clearScenarioPrefs()
prefs_filename = filename.removesuffix(".miz") + ".json"
self.prefs = self.loadScenarioPrefs(prefs_filename)
if self.prefs:
self.applyScenarioPrefs()
self.clearScenarioConfig()
config_filename = filename.removesuffix(".miz") + ".json"
self.config = self.loadScenarioConfig(config_filename)
if self.config:
self.applyScenarioConfig()
self.m.setConfig(self.config)
for zone in zones:

View File

@ -0,0 +1,157 @@
import dcs
import random
jtf_red = "Combined Joint Task Forces Red"
jtf_blue = "Combined Joint Task Forces Blue"
def triggerSetup(rops, options):
# get the boolean value from ui option and convert to lua string
def lb(var):
return str(options[var]).lower()
game_flag = 100
# Add the first trigger
trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Scripts")
trig.rules.append(dcs.condition.TimeAfter(1))
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["mist_4_4_90.lua"]))
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["Splash_Damage_2_0.lua"]))
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["CTLD.lua"]))
trig.actions.append(dcs.action.DoScriptFile(rops.scripts["RotorOps.lua"]))
script = ""
script = ("--OPTIONS HERE!\n\n" +
"RotorOps.CTLD_crates = " + lb("crates") + "\n\n" +
"RotorOps.CTLD_sound_effects = true\n\n" +
"RotorOps.force_offroad = " + lb("force_offroad") + "\n\n" +
"RotorOps.voice_overs = " + lb("voiceovers") + "\n\n" +
"RotorOps.zone_status_display = " + lb("game_display") + "\n\n" +
"RotorOps.inf_spawn_messages = " + lb("inf_spawn_msgs") + "\n\n" +
"RotorOps.inf_spawns_per_zone = " + lb("inf_spawn_qty") + "\n\n" +
"RotorOps.apcs_spawn_infantry = " + lb("apc_spawns_inf") + " \n\n")
if not options["smoke_pickup_zones"]:
script = script + 'RotorOps.pickup_zone_smoke = "none"\n\n'
trig.actions.append(dcs.action.DoScript(dcs.action.String((script))))
rops.m.triggerrules.triggers.append(trig)
# Add the second trigger
trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Zones")
trig.rules.append(dcs.condition.TimeAfter(2))
for s_zone in rops.staging_zones:
trig.actions.append(dcs.action.DoScript(dcs.action.String("RotorOps.stagingZone('" + s_zone + "')")))
for c_zone in rops.conflict_zones:
zone_flag = rops.conflict_zones[c_zone].flag
trig.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.setupConflict('" + str(game_flag) + "')")))
rops.m.triggerrules.triggers.append(trig)
# Add the third trigger
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)")))
rops.m.triggerrules.triggers.append(trig)
# Add generic zone-based triggers
for index, zone_name in enumerate(rops.conflict_zones):
z_active_trig = dcs.triggers.TriggerOnce(comment=zone_name + " Active")
z_active_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_active_trig.actions.append(dcs.action.DoScript(dcs.action.String("--Add any action you want here!")))
rops.m.triggerrules.triggers.append(z_active_trig)
# Zone protection SAMs
if options["zone_protect_sams"]:
for index, zone_name in enumerate(rops.conflict_zones):
z_sams_trig = dcs.triggers.TriggerOnce(comment="Deactivate " + zone_name + " SAMs")
z_sams_trig.actions.append(dcs.action.DoScript(
dcs.action.String("Group.destroy(Group.getByName('" + zone_name + " Protection SAM'))")))
rops.m.triggerrules.triggers.append(z_sams_trig)
# Zone FARPS always
if options["zone_farps"] == "farp_always" and not options["defending"]:
for index, zone_name in enumerate(rops.conflict_zones):
if index > 0:
previous_zone = list(rops.conflict_zones)[index - 1]
if not rops.m.country(jtf_blue).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(rops.m.country(jtf_blue).find_group(previous_zone + " FARP Static").id))
# z_farps_trig.actions.append(dcs.action.SoundToAll(str(rops.res_map['forward_base_established.ogg'])))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"RotorOps.farpEstablished(" + str(index) + ")")))
rops.m.triggerrules.triggers.append(z_farps_trig)
# Zone FARPS conditional on staged units remaining
if options["zone_farps"] == "farp_gunits" and not options["defending"]:
for index, zone_name in enumerate(rops.conflict_zones):
if index > 0:
previous_zone = list(rops.conflict_zones)[index - 1]
if not rops.m.country(jtf_blue).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(rops.m.country(jtf_blue).find_group(previous_zone + " FARP Static").id))
# z_farps_trig.actions.append(dcs.action.SoundToAll(str(rops.res_map['forward_base_established.ogg'])))
z_farps_trig.actions.append(dcs.action.DoScript(dcs.action.String(
"RotorOps.farpEstablished(" + str(index) + ")")))
rops.m.triggerrules.triggers.append(z_farps_trig)
# Add attack helos triggers
for index in range(options["e_attack_helos"]):
random_zone_obj = random.choice(list(rops.conflict_zones.items()))
zone = random_zone_obj[1]
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 " + 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()")))
rops.m.triggerrules.triggers.append(z_weak_trig)
# Add attack plane triggers
for index in range(options["e_attack_planes"]):
random_zone_obj = random.choice(list(rops.conflict_zones.items()))
zone = random_zone_obj[1]
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 " + 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()")))
rops.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(rops.conflict_zones))
random_zone_obj = list(rops.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"]) + ")")))
rops.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))
trig.actions.append(
dcs.action.DoScript(dcs.action.String("---Add an action you want to happen when the game is WON")))
rops.m.triggerrules.triggers.append(trig)
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")))
rops.m.triggerrules.triggers.append(trig)

234
Generator/RotorOpsImport.py Normal file
View File

@ -0,0 +1,234 @@
import math
import dcs
from MissionGenerator import logger
class ImportObjects:
def __init__(self, mizfile, source_point=None, source_heading=0):
self.pad_unit = True #todo: use this to hold a unit for helicopter placement on ships ie flight_group_from_unit
logger.info("Importing objects from " + mizfile)
self.source_mission = dcs.mission.Mission()
self.source_mission.load_file(mizfile)
self.source_heading = source_heading
if source_point:
self.source_point = source_point
else:
self.source_point = dcs.Point(self.source_mission.terrain.bullseye_blue["x"], self.source_mission.terrain.bullseye_blue["y"])
self.statics = []
self.vehicles = []
self.helicopters = []
self.extractUnits()
def getStatics(self):
return self.statics
def getVehicles(self):
return self.vehicles
def getHelicopters(self):
return self.helicopters
def copyAll(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
return self.copyStatics(mission, dest_country_name, dest_name, dest_point, dest_heading), \
self.copyVehicles(mission, dest_country_name, dest_name, dest_point, dest_heading), \
self.copyHelicopters(mission, dest_country_name, dest_name, dest_point, dest_heading)
def anchorByGroupName(self, group_name):
group = self.source_mission.find_group(group_name)
if group:
self.source_point = group.units[0].position
self.source_heading = group.units[0].heading
else:
logger.warning("Unable to find group for anchor.")
def extractUnits(self):
for side in "red", "blue", "neutrals":
coalition = self.source_mission.coalition.get(side)
for country_name in coalition.countries:
group_types = [coalition.countries[country_name].static_group, coalition.countries[country_name].vehicle_group, coalition.countries[country_name].helicopter_group, coalition.countries[country_name].plane_group,
coalition.countries[country_name].ship_group]
for index, group_type in enumerate(group_types):
for group in group_type:
if index == 0: # Statics
self.statics.append(group)
elif index == 1: # Vehicles
self.vehicles.append(group)
elif index == 2: # Helicopters
self.helicopters.append(group)
elif index == 3:
logger.warn(group.name + ": Planes not available for import")
elif index == 4:
logger.warn(group.name + ": Ships not available for import")
def copyStatics(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
logger.info("Copying " + str(len(self.statics)) + " static objects as " + dest_name)
new_groups = []
if not dest_point:
dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
#Statics
statics_copy = self.statics.copy()
for group in statics_copy:
self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
class temp(dcs.unittype.StaticType):
id = group.units[0].type
name = group.units[0].name
shape_name = group.units[0].shape_name
rate = group.units[0].rate
can_cargo = group.units[0].can_cargo
mass = group.units[0].mass
ng = mission.static_group(mission.country(dest_country_name),
dest_name + " " + group.name,
temp,
group.units[0].position,
group.units[0].heading,
hidden=False)
ng.units[0].name = group.units[0].name
new_groups.append(ng)
# if ng.units[0].type == "Invisible FARP":
# self.pad_unit = ng
return new_groups
def copyVehicles(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
logger.info("Copying " + str(len(self.vehicles)) + " vehicle groups as " + dest_name)
new_groups = []
if not dest_point:
dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
vehicles_copy = self.vehicles
for group in vehicles_copy:
self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
for i, unit in enumerate(group.units):
if i == 0:
ng = mission.vehicle_group(mission.country(dest_country_name),
dest_name + " " + group.name,
dcs.vehicles.vehicle_map[group.units[0].type],
group.units[0].position,
group.units[0].heading)
new_groups.append(ng) # will this hold units we add later?
else:
u = mission.vehicle(dest_name + " " + group.units[i].name, dcs.vehicles.vehicle_map[group.units[i].type])
u.position = group.units[i].position
u.heading = group.units[i].heading
ng.add_unit(u)
return new_groups
def copyHelicopters(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
logger.info("Copying " + str(len(self.helicopters)) + " helicopters as " + dest_name)
new_groups = []
if not dest_point:
dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
helicopters_copy = self.helicopters.copy()
for group in helicopters_copy:
self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
if self.pad_unit:
if group.units[0].skill == dcs.unit.Skill.Client or group.units[0].skill == dcs.unit.Skill.Player:
# we'll create a new FARP for each helicopter. we've tried adding the flight group to an existing FARP, but they stack on top of each other
# trying to move the units into position after adding the flight group moves the 2D graphic of the helicopter, but the unit marker remains stacked on top
# of the unit marker in ME
# farp = mission.country(country_name).find_group(self.pad_unit.name)
farp = mission.farp(mission.country(dest_country_name), dest_name + " " + group.name + " Pad", group.units[0].position, hidden=True, dead=False,
farp_type=dcs.unit.InvisibleFARP)
ng = mission.flight_group_from_unit(mission.country(dest_country_name),
dest_name + " " + group.name,
dcs.helicopters.helicopter_map[group.units[0].type],
farp,
group_size=1)
ng.points[0].action = dcs.point.PointAction.FromGroundArea
ng.points[0].type = "TakeOffGround"
ng.units[0].heading = group.units[0].heading
ng.units[0].skill = group.units[0].skill
ng.units[0].livery_id = group.units[0].livery_id
ng.units[0].pylons = group.units[0].pylons
new_groups.append(ng)
else:
logger.warn("No pad unit (ie FARP, carrier) found, so can't add helicopters.")
return new_groups
def copyVehiclesAsGroup(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
logger.info("Copying " + str(len(self.vehicles)) + " vehicle groups as single group name: " + dest_name)
new_group = None
if not dest_point:
dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
unit_count = 0
vehicles_copy = self.vehicles.copy()
for group in vehicles_copy:
self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
for i, unit in enumerate(group.units):
if unit_count == 0:
print("Group:" + group.name)
new_group = mission.vehicle_group(mission.country(dest_country_name),
dest_name,
dcs.vehicles.vehicle_map[group.units[0].type],
group.units[0].position,
group.units[0].heading)
unit_count = unit_count + 1
else:
print("Unit:" + group.units[i].name)
u = mission.vehicle(dest_name + " " + group.units[i].name, dcs.vehicles.vehicle_map[group.units[i].type])
u.position = group.units[i].position
u.heading = group.units[i].heading
new_group.add_unit(u)
unit_count = unit_count + 1
print("Made a group with units: " + str(unit_count))
print("group actually has units: " + str(len(new_group.units)))
return new_group
@staticmethod
def groupToPoint(group, src_point, dest_point, src_heading=0, dest_heading=0):
for unit in group.units:
heading_to_unit = dcs.mapping.heading_between_points(src_point.x, src_point.y, unit.position.x,
unit.position.y)
new_heading_to_unit = dest_heading + heading_to_unit
unit_distance = src_point.distance_to_point(unit.position)
unit.position = dest_point.point_from_heading(new_heading_to_unit, unit_distance)
unit.heading = unit.heading + dest_heading
return group

View File

@ -7,6 +7,8 @@ import random
import RotorOpsGroups
import RotorOpsUnits
import RotorOpsUtils
import RotorOpsConflict
from RotorOpsImport import ImportObjects
import time
from MissionGenerator import logger
@ -32,6 +34,7 @@ class RotorOpsMission:
self.spawn_zones = {}
self.scripts = {}
self.res_map = {}
self.config = None
class RotorOpsZone:
def __init__(self, name: str, flag: int, position: dcs.point, size: int):
@ -44,6 +47,9 @@ class RotorOpsMission:
def getMission(self):
return self.m
def setConfig(self,config):
self.config = config
def addZone(self, zone_dict, zone: RotorOpsZone):
zone_dict[zone.name] = zone
@ -125,7 +131,10 @@ class RotorOpsMission:
self.importObjects()
if not self.m.country(jtf_red) or not self.m.country(jtf_blue):
#todo: test
self.m.coalition.get("neutrals").add_country(dcs.countries.UnitedNationsPeacekeepers())
if not self.m.country(jtf_red) or not self.m.country(jtf_blue) or not self.m.country(dcs.countries.UnitedNationsPeacekeepers.name):
failure_msg = "You must include a CombinedJointTaskForcesBlue and CombinedJointTaskForcesRed unit in the scenario template. See the instructions in " + self.scenarios_dir
return {"success": False, "failure_msg": failure_msg}
@ -135,6 +144,8 @@ class RotorOpsMission:
# Add coalitions (we may be able to add CJTF here instead of requiring templates to have objects of those coalitions)
self.m.coalition.get("red").add_country(dcs.countries.Russia())
self.m.coalition.get("blue").add_country(dcs.countries.USA())
# blue = self.m.coalition.get("blue")
# blue.add_country(dcs.countries.CombinedJointTaskForcesBlue())
self.m.add_picture_blue(self.assets_dir + '/briefing1.png')
self.m.add_picture_blue(self.assets_dir + '/briefing2.png')
@ -168,16 +179,45 @@ class RotorOpsMission:
#Populate Red zones with ground units
for zone_name in red_zones:
if red_forces["vehicles"]:
self.addGroundGroups(red_zones[zone_name], self.m.country(jtf_red), red_forces["vehicles"], options["red_quantity"])
#Add red FARPS
if options["zone_farps"] != "farp_never" and not options["defending"]:
RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.zone_farp(self.m, self.m.country(jtf_blue),
self.m.country(jtf_blue),
red_zones[zone_name].position,
180, zone_name + " FARP", late_activation=True)
# RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.zone_farp(self.m, self.m.country(jtf_blue),
# self.m.country(jtf_blue),
# red_zones[zone_name].position,
# 180, zone_name + " FARP", late_activation=True)
#new_statics, new_vehicles, new_helicopters = i.copyAll(self.m, dcs.countries.UnitedNationsPeacekeepers.name, zone_name, red_zones[zone_name].position)
farp_flag = self.m.find_group(zone_name)
if farp_flag:
farp_position = farp_flag.units[0].position
farp_heading = farp_flag.units[0].heading
else:
farp_position = red_zones[zone_name].position
farp_heading = 0
farp = self.m.farp(self.m.country(jtf_blue), zone_name + " FARP", farp_position,
hidden=False, dead=False,
farp_type=dcs.unit.InvisibleFARP)
os.chdir(self.imports_dir)
if self.config and self.config["zone_farp_file"]:
filename = self.config["zone_farp_file"]
else:
filename = "FARP_DEFAULT_ZONE.miz"
i = ImportObjects(filename)
i.anchorByGroupName("ANCHOR")
farp_group = i.copyVehiclesAsGroup(self.m, jtf_blue, zone_name + " FARP Static", farp_position, farp_heading)
farp_group.late_activation = True
if options["zone_protect_sams"]:
self.m.vehicle_group(
@ -206,9 +246,24 @@ class RotorOpsMission:
#add logistics sites
if options["crates"] and zone_name in self.staging_zones:
RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.logistics_site(self.m, self.m.country(jtf_blue),
blue_zones[zone_name].position,
180, zone_name)
# RotorOpsGroups.VehicleTemplate.CombinedJointTaskForcesBlue.logistics_site(self.m, self.m.country(jtf_blue),
# blue_zones[zone_name].position,
# 180, zone_name)
os.chdir(self.imports_dir)
staging_flag = self.m.find_group(zone_name)
if staging_flag:
staging_position = staging_flag.units[0].position
staging_heading = staging_flag.units[0].heading
else:
staging_position = blue_zones[zone_name].position
staging_heading = 0
i = ImportObjects("STAGING_LOGISITIC_HUB.miz")
i.anchorByGroupName("ANCHOR")
i.copyAll(self.m, jtf_blue, "Staging Logistics Zone",
staging_position, staging_heading)
@ -239,7 +294,7 @@ class RotorOpsMission:
#add files and triggers necessary for RotorOps.lua script
self.addResources(self.sound_directory, self.script_directory)
self.scriptTriggerSetup(options)
RotorOpsConflict.triggerSetup(self, options)
# test adding static objects from a .miz
#self.addStatics()
@ -705,167 +760,34 @@ class RotorOpsMission:
unit.pylons = source_helo.pylons
unit.livery_id = source_helo.livery_id
def scriptTriggerSetup(self, options):
#get the boolean value from ui option and convert to lua string
def lb(var):
return str(options[var]).lower()
game_flag = 100
#Add the first trigger
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"]))
script = ""
script = ("--OPTIONS HERE!\n\n" +
"RotorOps.CTLD_crates = " + lb("crates") + "\n\n" +
"RotorOps.CTLD_sound_effects = true\n\n" +
"RotorOps.force_offroad = " + lb("force_offroad") + "\n\n" +
"RotorOps.voice_overs = " + lb("voiceovers") + "\n\n" +
"RotorOps.zone_status_display = " + lb("game_display") + "\n\n" +
"RotorOps.inf_spawn_messages = " + lb("inf_spawn_msgs") + "\n\n" +
"RotorOps.inf_spawns_per_zone = " + lb("inf_spawn_qty") + "\n\n" +
"RotorOps.apcs_spawn_infantry = " + lb("apc_spawns_inf") + " \n\n")
if not options["smoke_pickup_zones"]:
script = script + 'RotorOps.pickup_zone_smoke = "none"\n\n'
trig.actions.append(dcs.action.DoScript(dcs.action.String((script))))
self.m.triggerrules.triggers.append(trig)
#Add the second trigger
trig = dcs.triggers.TriggerOnce(comment="RotorOps Setup Zones")
trig.rules.append(dcs.condition.TimeAfter(2))
for s_zone in self.staging_zones:
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
trig.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.setupConflict('" + str(game_flag) + "')")))
self.m.triggerrules.triggers.append(trig)
#Add the third trigger
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 generic zone-based triggers
for index, zone_name in enumerate(self.conflict_zones):
z_active_trig = dcs.triggers.TriggerOnce(comment= zone_name + " Active")
z_active_trig.rules.append(dcs.condition.FlagEquals(game_flag, index + 1))
z_active_trig.actions.append(dcs.action.DoScript(dcs.action.String("--Add any action you want here!")))
self.m.triggerrules.triggers.append(z_active_trig)
#Zone protection SAMs
if options["zone_protect_sams"]:
for index, zone_name in enumerate(self.conflict_zones):
z_sams_trig = dcs.triggers.TriggerOnce(comment="Deactivate " + zone_name + " SAMs")
z_sams_trig.actions.append(dcs.action.DoScript(dcs.action.String("Group.destroy(Group.getByName('" + zone_name + " Protection SAM'))")))
self.m.triggerrules.triggers.append(z_sams_trig)
#Zone FARPS always
if options["zone_farps"] == "farp_always" and not options["defending"]:
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(jtf_blue).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(jtf_blue).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)
#Zone FARPS conditional on staged units remaining
if options["zone_farps"] == "farp_gunits" and not options["defending"]:
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(jtf_blue).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(jtf_blue).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)
#Add attack helos triggers
for index in range(options["e_attack_helos"]):
random_zone_obj = random.choice(list(self.conflict_zones.items()))
zone = random_zone_obj[1]
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 " + 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)
#Add attack plane triggers
for index in range(options["e_attack_planes"]):
random_zone_obj = random.choice(list(self.conflict_zones.items()))
zone = random_zone_obj[1]
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 " + 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))
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)
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)
#
# def addStatics(self):
# os.chdir(self.home_dir + "/Generator/Statics")
# logger.info("Looking for .miz files in '" + os.getcwd())
# dest_point = self.conflict_zones["ALPHA"].position
# grps = RotorOpsUtils.extractUnits.toPoint("test.miz", dest_point, 180)
# for grp in grps:
# self.m.country(jtf_blue).add_vehicle_group(grp)
def importObjects(self):
os.chdir(self.imports_dir)
logger.info("Looking for import .miz files in '" + os.getcwd())
for group in self.m.country(jtf_blue).static_group:
prefix = "IMPORT-"
if group.name.find(prefix) == 0:
filename = group.name.removeprefix(prefix) + ".miz"
i = RotorOpsUtils.ImportObjects(filename)
i.anchorByGroupName("ANCHOR")
i.copyTo(self.m, group.units[0].name, group.units[0].position, group.units[0].heading)
for side in "red", "blue", "neutrals":
coalition = self.m.coalition.get(side)
for country_name in coalition.countries:
for group in self.m.country(country_name).static_group:
prefix = "IMPORT-"
if group.name.find(prefix) == 0:
if group.units[0].name.find('IMPORT-') == 0:
logger.error(
group.units[0].name + " IMPORT group's unit name cannot start with 'IMPORT'. Check the scenario template.")
raise Exception("Scenario file error: " + group.units[0].name + " IMPORT group's unit name cannot start with 'IMPORT'")
# trim the groupname to our filename convention
filename = group.name.removeprefix(prefix)
i = filename.find('-')
if i > 8:
filename = filename[0:i]
print(filename)
filename = filename + ".miz"
i = ImportObjects(filename)
i.anchorByGroupName("ANCHOR")
new_statics, new_vehicles, new_helicopters = i.copyAll(self.m, country_name, group.units[0].name, group.units[0].position, group.units[0].heading)

View File

@ -18,135 +18,165 @@ def convertMeterToNM(meters=int):
return nm
class ImportObjects:
def __init__(self, mizfile, source_point=None, source_heading=0):
logger.info("Importing objects from " + mizfile)
self.source_mission = dcs.mission.Mission()
self.source_mission.load_file(mizfile)
self.source_heading = source_heading
if source_point:
self.source_point = source_point
else:
self.source_point = dcs.Point(self.source_mission.terrain.bullseye_blue["x"], self.source_mission.terrain.bullseye_blue["y"])
def anchorByGroupName(self, group_name):
group = self.source_mission.find_group(group_name)
if group:
self.source_point = group.units[0].position
self.source_heading = group.units[0].heading
else:
logger.warning("Unable to find group for anchor.")
def copyTo(self, mission, dest_name, dest_point=None, dest_heading=0):
logger.info("Copying objects as " + dest_name)
if not dest_point:
dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
for side in "red", "blue":
coalition = self.source_mission.coalition.get(side)
for country_name in coalition.countries:
group_types = [coalition.countries[country_name].static_group, coalition.countries[country_name].vehicle_group, coalition.countries[country_name].helicopter_group, coalition.countries[country_name].plane_group,
coalition.countries[country_name].ship_group]
for index, group_type in enumerate(group_types):
for group in group_type:
self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
if index == 0: # Statics
type_name = group.units[0].type
type_maps = [dcs.statics.cargo_map, dcs.statics.warehouse_map, dcs.statics.groundobject_map, dcs.statics.fortification_map]
classed = False
for type_map in type_maps:
if type_name in type_map:
classed = True
unit_type = type_map[type_name]
ng = mission.static_group(mission.country(country_name),
group.name,
unit_type,
group.units[0].position,
group.units[0].heading,
hidden=False)
if not classed:
print("No pydcs class for " + type_name)
class temp(dcs.unittype.StaticType):
id = group.units[0].type
name = group.units[0].name
shape_name = group.units[0].shape_name
rate = group.units[0].rate
ng = mission.static_group(mission.country(country_name),
group.name,
temp,
group.units[0].position,
group.units[0].heading,
hidden=False)
elif index == 1: # Vehicles
for i, unit in enumerate(group.units):
if i == 0:
ng = mission.vehicle_group(mission.country(country_name),
group.name,
dcs.vehicles.vehicle_map[group.units[0].type],
group.units[0].position,
group.units[0].heading)
else:
u = mission.vehicle(group.units[i].name, dcs.vehicles.vehicle_map[group.units[i].type])
u.position = group.units[i].position
u.heading = group.units[i].heading
ng.add_unit(u)
mission.country(country_name).add_vehicle_group(ng)
elif index == 2: # Helicopters
if group.units[0].skill == dcs.unit.Skill.Client or group.units[0].skill == dcs.unit.Skill.Player:
farp = mission.farp(mission.country(country_name), dest_name + " " + group.name + " Pad", group.units[0].position, hidden=True, dead=False,
farp_type=dcs.unit.InvisibleFARP)
ng = mission.flight_group_from_unit(mission.country(country_name),
dest_name + " " + group.name,
dcs.helicopters.helicopter_map[group.units[0].type],
farp,
group_size=1)
ng.points[0].action = dcs.point.PointAction.FromGroundArea
ng.points[0].type = "TakeOffGround"
ng.units[0].heading = group.units[0].heading
ng.units[0].skill = group.units[0].skill
ng.units[0].livery_id = group.units[0].livery_id
ng.units[0].pylons = group.units[0].pylons
elif index == 3:
#mission.country(country).add_plane_group(group)
print("not yet avail")
elif index == 4:
#mission.country(country).add_ship_group(group)
print("not yet avail")
@staticmethod
def groupToPoint(group, src_point, dest_point, src_heading=0, dest_heading=0):
for unit in group.units:
heading_to_unit = dcs.mapping.heading_between_points(src_point.x, src_point.y, unit.position.x,
unit.position.y)
new_heading_to_unit = dest_heading + heading_to_unit
unit_distance = src_point.distance_to_point(unit.position)
unit.position = dest_point.point_from_heading(new_heading_to_unit, unit_distance)
unit.heading = unit.heading + dest_heading
return group
#
#
# class ImportObjects:
#
# def __init__(self, mizfile, source_point=None, source_heading=0):
# self.pad_unit = None
# logger.info("Importing objects from " + mizfile)
# self.source_mission = dcs.mission.Mission()
# self.source_mission.load_file(mizfile)
# self.source_heading = source_heading
# if source_point:
# self.source_point = source_point
# else:
# self.source_point = dcs.Point(self.source_mission.terrain.bullseye_blue["x"], self.source_mission.terrain.bullseye_blue["y"])
#
#
# def anchorByGroupName(self, group_name):
# group = self.source_mission.find_group(group_name)
# if group:
# self.source_point = group.units[0].position
# self.source_heading = group.units[0].heading
# else:
# logger.warning("Unable to find group for anchor.")
#
#
# def copyTo(self, mission, dest_country_name, dest_name, dest_point=None, dest_heading=0):
# logger.info("Copying objects as " + dest_name)
#
# if not dest_point:
# dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"])
#
# for side in "red", "blue", "neutrals":
# coalition = self.source_mission.coalition.get(side)
# for country_name in coalition.countries:
#
# group_types = [coalition.countries[country_name].static_group, coalition.countries[country_name].vehicle_group, coalition.countries[country_name].helicopter_group, coalition.countries[country_name].plane_group,
# coalition.countries[country_name].ship_group]
#
#
#
# for index, group_type in enumerate(group_types):
# for group in group_type:
# self.groupToPoint(group, self.source_point, dest_point, self.source_heading, dest_heading)
#
# # add the country to the destination mission if it doesn't exist already
# # if not mission.country(country_name):
# # print(country_name + " not found in destination mission")
# # for index, c in enumerate(dcs.countries.country_dict):
# # if dcs.countries.country_dict[c].name == country_name:
# #
# # mission.coalition.get(side).add_country(dcs.countries.country_dict[c]())
# # print(country_name + " added to " + side)
#
#
#
#
# if index == 0: # Statics
# type_name = group.units[0].type
# type_maps = [dcs.statics.cargo_map, dcs.statics.warehouse_map, dcs.statics.groundobject_map, dcs.statics.fortification_map]
# classed = False
# for type_map in type_maps:
# if type_name in type_map:
# classed = True
# unit_type = type_map[type_name]
# ng = mission.static_group(mission.country(dest_country_name),
# group.name,
# unit_type,
# group.units[0].position,
# group.units[0].heading,
# hidden=False)
#
#
#
# if not classed:
# print("No pydcs class for " + type_name)
#
#
# class temp(dcs.unittype.StaticType):
# id = group.units[0].type
# name = group.units[0].name
# shape_name = group.units[0].shape_name
# rate = group.units[0].rate
#
#
# ng = mission.static_group(mission.country(dest_country_name),
# group.name,
# temp,
# group.units[0].position,
# group.units[0].heading,
# hidden=False)
#
# if ng.units[0].type == "Invisible FARP":
# self.pad_unit = ng
#
# elif index == 1: # Vehicles
#
# for i, unit in enumerate(group.units):
# if i == 0:
# ng = mission.vehicle_group(mission.country(dest_country_name),
# group.name,
# dcs.vehicles.vehicle_map[group.units[0].type],
# group.units[0].position,
# group.units[0].heading)
#
#
# else:
#
# u = mission.vehicle(group.units[i].name, dcs.vehicles.vehicle_map[group.units[i].type])
# u.position = group.units[i].position
# u.heading = group.units[i].heading
# ng.add_unit(u)
#
# mission.country(dest_country_name).add_vehicle_group(ng)
#
#
# elif index == 2: # Helicopters
# if self.pad_unit:
# if group.units[0].skill == dcs.unit.Skill.Client or group.units[0].skill == dcs.unit.Skill.Player:
#
# # we'll create a new FARP for each helicopter. we've tried adding the flight group to an existing FARP, but they stack on top of each other
# # trying to move the units into position after adding the flight group moves the 2D graphic of the helicopter, but the unit marker remains stacked on top
# # of the unit marker in ME
# # farp = mission.country(country_name).find_group(self.pad_unit.name)
#
# farp = mission.farp(mission.country(country_name), dest_name + " " + group.name + " Pad", group.units[0].position, hidden=True, dead=False,
# farp_type=dcs.unit.InvisibleFARP)
#
#
#
# ng = mission.flight_group_from_unit(mission.country(dest_country_name),
# dest_name + " " + group.name,
# dcs.helicopters.helicopter_map[group.units[0].type],
# farp,
# group_size=1)
#
# ng.points[0].action = dcs.point.PointAction.FromGroundArea
# ng.points[0].type = "TakeOffGround"
# ng.units[0].heading = group.units[0].heading
# ng.units[0].skill = group.units[0].skill
# ng.units[0].livery_id = group.units[0].livery_id
# ng.units[0].pylons = group.units[0].pylons
# else:
# logger.warn("No pad unit (ie FARP, carrier) found, so can't add helicopters.")
#
# elif index == 3:
# #mission.country(country).add_plane_group(group)
# print("not yet avail")
# elif index == 4:
# #mission.country(country).add_ship_group(group)
# print("not yet avail")
#
#
# @staticmethod
# def groupToPoint(group, src_point, dest_point, src_heading=0, dest_heading=0):
# for unit in group.units:
# heading_to_unit = dcs.mapping.heading_between_points(src_point.x, src_point.y, unit.position.x,
# unit.position.y)
# new_heading_to_unit = dest_heading + heading_to_unit
# unit_distance = src_point.distance_to_point(unit.position)
# unit.position = dest_point.point_from_heading(new_heading_to_unit, unit_distance)
# unit.heading = unit.heading + dest_heading
# return group

View File

@ -39,3 +39,8 @@ Tips:
-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.
-Pay attention to rivers and bridges, as a far away bridge crossing may break routing if it's the only way across. See the testing notes above.
v0.6:
You can now control the FARP spawning location and heading by adding a static object (such as a mark flag) with group name 'ALPHA' etc. Same for staging area logistics site..but the group name should be 'STAGING'. Change the object heading to better align with roads or map objects. The flags for these must be CJTFB country.
You can dynamically insert complex arangements of objects such as large bases with multiplayer spawns. See the 'Imports' folder for more details.