diff --git a/Generator/Imports/How to use imports.txt b/Generator/Imports/How to use imports.txt new file mode 100644 index 0000000..413eb51 --- /dev/null +++ b/Generator/Imports/How to use imports.txt @@ -0,0 +1,8 @@ +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. + +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. diff --git a/Generator/MissionGenerator.py b/Generator/MissionGenerator.py index ccb4384..6bbf24a 100644 --- a/Generator/MissionGenerator.py +++ b/Generator/MissionGenerator.py @@ -36,7 +36,7 @@ sys.excepthook = handle_exception maj_version = 0 -minor_version = 4 +minor_version = 5 version_string = str(maj_version) + "." + str(minor_version) scenarios = [] red_forces_files = [] diff --git a/Generator/RotorOpsMission.py b/Generator/RotorOpsMission.py index d92cf6c..58f05d4 100644 --- a/Generator/RotorOpsMission.py +++ b/Generator/RotorOpsMission.py @@ -6,11 +6,11 @@ import random import RotorOpsGroups import RotorOpsUnits +import RotorOpsUtils import time from MissionGenerator import logger - class RotorOpsMission: def __init__(self): @@ -23,6 +23,7 @@ class RotorOpsMission: self.sound_directory = self.home_dir + "\sound\embedded" self.output_dir = self.home_dir + "\Generator\Output" self.assets_dir = self.home_dir + "\Generator/assets" + self.imports_dir = self.home_dir + "\Generator\Imports" self.conflict_zones = {} self.staging_zones = {} @@ -119,6 +120,8 @@ class RotorOpsMission: self.m.load_file(options["scenario_filename"]) + self.importObjects() + if not self.m.country("Combined Joint Task Forces Red") or not self.m.country("Combined Joint Task Forces Blue"): 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} @@ -134,7 +137,6 @@ class RotorOpsMission: self.m.add_picture_blue(self.assets_dir + '/briefing2.png') - # add zones to target mission zone_names = ["ALPHA", "BRAVO", "CHARLIE", "DELTA"] zone_flag = 101 @@ -235,6 +237,9 @@ class RotorOpsMission: self.addResources(self.sound_directory, self.script_directory) self.scriptTriggerSetup(options) + # test adding static objects from a .miz + #self.addStatics() + #Save the mission file os.chdir(self.output_dir) output_filename = options["scenario_filename"].removesuffix('.miz') + " " + time.strftime('%a%H%M%S') + '.miz' @@ -631,7 +636,7 @@ class RotorOpsMission: else: return - if source_helo: + if source_helo and afg: for unit in afg.units: unit.pylons = source_helo.pylons unit.livery_id = source_helo.livery_id @@ -661,10 +666,10 @@ class RotorOpsMission: group_size=group_size) zone_attack(afg, airport) - if source_plane: - for unit in afg.units: - unit.pylons = source_plane.pylons - unit.livery_id = source_plane.livery_id + if source_plane: + for unit in afg.units: + unit.pylons = source_plane.pylons + unit.livery_id = source_plane.livery_id if options["e_transport_helos"]: source_helo = None @@ -690,10 +695,10 @@ class RotorOpsMission: afg.late_activation = True afg.units[0].skill = dcs.unit.Skill.Excellent - if source_helo: - for unit in afg.units: - unit.pylons = source_helo.pylons - unit.livery_id = source_helo.livery_id + if source_helo: + for unit in afg.units: + unit.pylons = source_helo.pylons + unit.livery_id = source_helo.livery_id def scriptTriggerSetup(self, options): @@ -841,3 +846,23 @@ class RotorOpsMission: 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("Combined Joint Task Forces 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("Combined Joint Task Forces 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].position) + + diff --git a/Generator/RotorOpsUtils.py b/Generator/RotorOpsUtils.py index 2df38f6..59f4902 100644 --- a/Generator/RotorOpsUtils.py +++ b/Generator/RotorOpsUtils.py @@ -1,5 +1,6 @@ import math import dcs +from MissionGenerator import logger def getDistance(point1=dcs.Point, point2=dcs.Point): @@ -15,3 +16,111 @@ def getDistance(point1=dcs.Point, point2=dcs.Point): def convertMeterToNM(meters=int): nm = meters / 1852 return nm + + + + +class ImportObjects: + + def __init__(self, mizfile, ref_point=None, ref_heading=0): + self.source_mission = dcs.mission.Mission() + self.source_mission.load_file(mizfile) + self.ref_heading = ref_heading + if ref_point: + self.ref_point = ref_point + else: + self.ref_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.ref_point = group.units[0].position + self.ref_heading = group.units[0].heading + else: + logger.warning("Unable to find group for anchor.") + + + def copyTo(self, mission, dest_point=None, dest_heading=0): + if not dest_point: + dest_point = dcs.Point(mission.terrain.bullseye_blue["x"], mission.terrain.bullseye_blue["y"]) + + #iterate over group types first? + for side in "red", "blue": + coalition = self.source_mission.coalition.get(side) + for country in coalition.countries: + + group_types = [coalition.countries[country].static_group, coalition.countries[country].vehicle_group, coalition.countries[country].helicopter_group, coalition.countries[country].plane_group, + coalition.countries[country].ship_group] + + for index, group_type in enumerate(group_types): + for group in group_type: + self.groupToPoint(group, self.ref_point, dest_point, self.ref_heading, dest_heading) + if index == 0: + mission.country(country).add_static_group(group) + elif index == 1: + mission.country(country).add_vehicle_group(group) + elif index == 2: + #mission.country(country).add_helicopter_group(group) + print("helicopter groups not available for import") + elif index == 3: + #mission.country(country).add_plane_group(group) + print("plane groups not available for import") + elif index == 4: + mission.country(country).add_ship_group(group) + + + + + @staticmethod + def groupToPoint(group, ref_point, dest_point, ref_heading=0, dest_heading=0): + for unit in group.units: + heading_to_unit = dcs.mapping.heading_between_points(ref_point.x, ref_point.y, unit.position.x, + unit.position.y) + new_heading_to_unit = dest_heading + heading_to_unit + unit_distance = ref_point.distance_to_point(unit.position) + unit.position = dest_point.point_from_heading(new_heading_to_unit, unit_distance) + return group + + + +# class extractUnits: +# +# @staticmethod +# def toPoint(filename, group_type, dest_point, dest_heading=0, side="blue"): +# print("Attempting to extract units from " + filename + " relative to 'HELO_FARP' initial point.") +# +# source_mission = dcs.mission.Mission() +# source_mission.load_file(filename) +# +# +# # country = source_mission.country('Combined Joint Task Forces Blue') +# # country.find +# +# #group_types = [] +# +# groups = [] +# +# for country in source_mission.coalition.get(side).countries: +# +# ref_point = country.find_static_group("HELO_FARP").position #units position instead of group? +# ref_heading = country.find_static_group("HELO_FARP").heading +# group_types = [country.static_group, country.vehicle_group, country.helicopter_group, country.plane_group, country.ship_group] +# +# for group_type in group_types: +# for group in group_type: +# for unit in group.units: +# x_rel = ref_point.x - unit.position.x +# y_rel = ref_point.y - unit.position.y +# #heading_rel = ref_heading - unit.heading # heading of unit relative to heading of the reference object +# heading_to_unit = dcs.mapping.heading_between_points(ref_point.x, ref_point.y, unit.position.x, unit.position.y) +# new_heading_to_unit = dest_heading + heading_to_unit +# unit_distance = ref_point.distance_to_point(unit.position) +# unit.position = dest_point.point_from_heading(new_heading_to_unit, unit_distance) +# +# # unit.position.x = x - x_rel +# # unit.position.y = y - y_rel +# +# groups.append(group) +# return groups + diff --git a/MissionGenerator.exe b/MissionGenerator.exe index 0f309bf..ac87405 100644 Binary files a/MissionGenerator.exe and b/MissionGenerator.exe differ diff --git a/RotorOps.lua b/RotorOps.lua index 6e2b9a2..07f9324 100644 --- a/RotorOps.lua +++ b/RotorOps.lua @@ -1,5 +1,5 @@ RotorOps = {} -RotorOps.version = "1.2.6" +RotorOps.version = "1.2.7" local debug = true @@ -345,6 +345,7 @@ end function RotorOps.isUnitInZone(unit, zone_name) local zone = trigger.misc.getZone(zone_name) local distance = getDistance(unit:getPoint(), zone.point) + --local distance = mist.utils.get2DDist(unit:getPoint(), zone.point) if distance <= zone.radius then return true else @@ -1497,3 +1498,43 @@ function RotorOps.spawnTranspHelos(troops, max_drops) end + +--- USEFUL PUBLIC 'LUA PREDICATE' FUNCTIONS FOR MISSION EDITOR TRIGGERS + +--determine if any players have broken a defined ceiling above ground level +function RotorOps.predPlayerMaxAGL(max_agl, hide_display) + for uName, uData in pairs(mist.DBs.humansByName) do + local player_unit = Unit.getByName(uData.unitName) + if player_unit then + local player_pos = player_unit:getPosition().p + local terrain_height = land.getHeight({x = player_pos.x, y = player_pos.z}) + local player_agl = player_pos.y - terrain_height + if player_agl > max_agl then + env.info(uData.unitName.." broke the AGL limit of "..max_agl) + if not hide_display then + trigger.action.outText(uData.unitName.." is above the maximum altitude of "..max_agl.."m AGL.", 1, true) + end + return true + else + return false + end + end + end +end + +--determine if any players are in a zone (not currently working) +function RotorOps.predPlayerInZone(zone_name) + local players_in_zone = 0 + for uName, uData in pairs(mist.DBs.humansByName) do + local player_unit = Unit.getByName(uData.unitName) + if player_unit and RotorOps.isUnitInZone(player_unit, zone_name) then + players_in_zone = players_in_zone + 1 + end + end + if players_in_zone > 0 then + return true + else + return false + end +end +