----------------------------------------------------------------------------- ----------------------------------------------------------------------------- -- Title: Dynamic Range Script -- Orig. Author: "Turbine" Howland -- Version: 1.0 -- Initial Date: 2024-08-14 -- Description: This is an initial release of a range object on the Syria -- public mission. -- Changelog: Version | Date | Author | Description -- 1.0 | 2024-08-14 | Turbine | Initial Release -- 1.1 | 2024-10-12 | Turbine | Renamed the Ramon Range to the Michael Grzybowski Range ----------------------------------------------------------------------------- --Note initializatrion of script env.info("DYNAMIC RANGE SCRIPT: Ver: 1.1") ----------------------------------------------------------------------------- -- Define Local Variables ----------------------------------------------------------------------------- local DEBUGGING = false -- This will draw circles where the trigger zones should be located and turn on log messaging. local SRS_PATH = "C:\\Program Files\\DCS-SimpleRadio-Standalone\\" -- Set this as the path to your local SRS installation. local SERVER_NAME = "" -- Placeholder for storing name of server local SRS_PORT = 0000 -- Set the default port! If you have one server, this will be your port. local ACTIVE_A2A_RANGE = {} local ACTIVE_A2G_RANGE = {} local ACTIVE_GRADED_RANGE = {} local RANGE_DATA = { ["RangeInfo"] = { rangeName = "Phoenix Grzybowski Range", triggerZoneName = "A2G_Graded_Phoenix_Grzybowski_Target_Range", rangeControlUnit = "Bombing_Range_1_Non_Graded-5", rangeControlFreq = 160, rangeInstructorFreq = 165, }, ["Bombing"] = { targetUnits = {"Bombing_Range_1-1","Bombing_Range_1-2","Bombing_Range_1-3"}, goodHitRange = 25, --Defined in meters targetSmokeColor = SMOKECOLOR.Green, trackThreshold = 25, --Defined in kilometers }, ["Strafing"] = { targetUnits = "Strafing_Range_1-1", boxLength = 3000, --Defined in meters boxWidth = 300, --Defined in meters heading = 88, --Approach box heading, in deg. inverseHeading = nil, --Defined as true or false goodPass = 10, --Defined as number of hits foulLine = 2000, --Defined in feet pitSmokeColor = SMOKECOLOR.Blue, targetSmokeColor = SMOKECOLOR.Orange, }, } ----------------------------------------------------------------------------------------------------------------------------------- -- Debugging Functions, DO NOT TOUCH! ----------------------------------------------------------------------------------------------------------------------------------- --Print string debug local function DebugLogger(message) if DEBUGGING then env.info("DYNAMIC RANGE SCRIPT: " .. message) trigger.action.outText("DYNAMIC RANGE SCRIPT: " .. message, 20) end end --Add debugging information DebugLogger("DYNAMIC RANGE SCRIPT Ver: 1.0") --Print Table debug function DebugTable(_table, _indentstring) if DEBUGGING then env.info(tostring(_table) .. " = {") _indentstring = _indentstring or "" for k, v in pairs(_table) do if type(v) == "table" then env.info(_indentstring .. tostring(k) .. " = {") DebugTable(v, _indentstring .. " ") env.info(_indentstring .. "},") else env.info(_indentstring .. tostring(k) .. " = " .. tostring(v) ..",") end end env.info("}") end end --Add debugging information DebugLogger("DEBUGGING SCRIPTS LOADED") ----------------------------------------------------------------------------- -- Define Servers Information -- -- Template: -- { -- SERVER_NAME = "Name", -- SRS_PORT = "5002" -- } ----------------------------------------------------------------------------- local SERVER_INFO = { { SERVER_NAME = "NerdNavy | Public", SRS_PORT = 5002, }, { SERVER_NAME = "TACG218.com | Campaign", SRS_PORT = 5003, }, { SERVER_NAME = "TACG218.com | Test", SRS_PORT = 5004, }, { SERVER_NAME = "TACG218.com | VFA154 Round Table", SRS_PORT = 5005, }, { SERVER_NAME = "TACG218.com | 13thFS Viper Den", SRS_PORT = 5006, }, { SERVER_NAME = "TACG218.com | 82ND Division HQ", SRS_PORT = 5007, }, { SERVER_NAME = "TACG218.com | VFA22 Hen House", SRS_PORT = 5008, }, } --Add debugging information DebugLogger("SEVER LIST LOADED") ----------------------------------------------------------------------------------------------------------------------------------- -- Find Server Name and Set Port According to Server List. If not in list default to 5002. ----------------------------------------------------------------------------------------------------------------------------------- --Loop through each server instance. If it matches running server set port accordingly for i, v in ipairs(SERVER_INFO) do if v.SERVER_NAME == BASE.ServerName then -- Set Name and Port SERVER_NAME = v.SERVER_NAME SRS_PORT = v.SRS_PORT end end --Check if port was not set, If true apply default of 5002 if SRS_PORT == 0000 then SRS_PORT = 5002 DebugLogger("!!!! ERROR !!!! COULD NOT FIND SERVER NAME, SETTING PORT TO : " .. SRS_PORT) else DebugLogger("SERVER [" .. SERVER_NAME .. "] FOUND. SETTING PORT TO: " .. SRS_PORT) end --Add debugging information DebugLogger("SRS SERVER PORT INFO LOADED") ----------------------------------------------------------------------------------------------------------------------------------- -- Setup Air 2 Air Ranges ----------------------------------------------------------------------------------------------------------------------------------- --Define local variables local A2ARangeZones = SET_ZONE:New():FilterPrefixes("A2A_Range"):FilterOnce() local A2ARangeGroups = SET_GROUP:New():FilterCategoryAirplane():FilterOnce() --Loop through each zone A2ARangeZones:ForEachZone( function(Zone) --Check if zone has A2A_RANGE in the name if string.find(string.upper(Zone:GetName()), "A2A_RANGE") then --Setup the Active A2A Ranges ACTIVE_A2A_RANGE[string.gsub(string.upper(Zone:GetName()),"A2A_RANGE_","")] = { zoneObj = ZONE:New(Zone:GetName()), bfmGroupObj = {}, bvrGroupObj = {}, } end end ) --Loop through each aircraft group A2ARangeGroups:ForEachGroup( function(Group) --Check if group has A2A_Range in the group name if string.find(string.upper(Group:GetName()),"A2A_RANGE") then --Loop through each active zone for _,v in pairs(ACTIVE_A2A_RANGE) do --Check to see if group is within the active zone if v.zoneObj:IsVec2InZone(Group:GetVec2()) then --Check to see if group is a BFM group if string.find(string.upper(Group:GetName()),"BFM") then --Add to the Active A2A Ranges v.bfmGroupObj[Group:GetName()] = Group end --Check to see if group is a BVR group if string.find(string.upper(Group:GetName()),"BVR") then --Add to the Active A2A Ranges v.bvrGroupObj[Group:GetName()] = Group end end end end end ) --Add debugging information DebugLogger("A2A RANGE REGISTRATION COMPLETE") ----------------------------------------------------------------------------------------------------------------------------------- -- Setup Air 2 Ground Ranges ----------------------------------------------------------------------------------------------------------------------------------- --Define variables local A2GRangeZones = SET_ZONE:New():FilterPrefixes("A2G_Range"):FilterOnce() local A2GRangeGroups = SET_GROUP:New():FilterCategoryGround():FilterOnce() table.sort(A2GRangeZones) --Loop through each zone A2GRangeZones:ForEachZone( function(Zone) --Check if the zone name contains A2G_Range_Static or A2G_Range_Dynamic if string.find(string.upper(Zone:GetName()), "A2G_RANGE_STATIC") or string.find(string.upper(Zone:GetName()), "A2G_RANGE_DYNAMIC") then --Setup the Range Zones to be used ACTIVE_A2G_RANGE[string.gsub(string.upper(Zone:GetName()),"A2G_RANGE_","")] = { zoneObj = ZONE:New(Zone:GetName()), staticGroupObj = {}, dynamicGroupObj = {}, } end end ) --Loop through each ground group A2GRangeGroups:ForEachGroup( function(Group) --Check if group has A2G_Range in the group name if string.find(string.upper(Group:GetName()),"A2G_RANGE") then --Loop through each active zone for _,v in pairs (ACTIVE_A2G_RANGE) do --Check if group is within the active zone if v.zoneObj:IsVec2InZone(Group:GetVec2()) then --Check to see if group is a static group if string.find(string.upper(Group:GetName()),"STATIC") then --Add to the Active static Range v.staticGroupObj[Group:GetName()] = Group end --Check to see if group is a dynamic group if string.find(string.upper(Group:GetName()),"DYNAMIC") then --Add to the Active dynamic Range v.dynamicGroupObj[Group:GetName()] = Group end end end end end ) --Add debugging information DebugLogger("A2G RANGE REGISTRATION COMPLETE") -------------------------------------------------------------------------------------------------------------------------- -- Setup A2A Range Functions -------------------------------------------------------------------------------------------------------------------------- --Function to spawn an A2A group local function SpawnA2Agroup(args) --Define local variables local ZoneGroupObj = args[1] local acType = string.upper(args[2]) local acQty = args[3] --Loop through each group for _,v in pairs(ZoneGroupObj) do --Define local variables local groupName = string.gsub(string.gsub(string.gsub(string.gsub(string.gsub(string.gsub(string.gsub(string.upper(v:GetName()),"A2A_RANGE_",""),"BFM_",""),"BVR_",""),"_1",""),"_2",""),"_3",""),"_4","") --Check to see if aircraft type matches if groupName == acType then --Check to see if the aircraft quantity is correct if v:GetInitialSize() == acQty then --Spawn the group local SpawnGroupObj = SPAWN:New(v:GetName()):InitAIOn(true):Spawn() end end end end --Function to clean an A2A zone local function CleanA2Agroup(args) --Define local variables local rangeZoneObj = args[1] local aliveRangeGroups = SET_GROUP:New():FilterCategoryAirplane():FilterOnce() aliveRangeGroups:ForEachGroup( function(Group) --Check if group has A2A_Range in the group name if string.find(string.upper(Group:GetName()),"A2A_RANGE") then --Check if group is alive if Group:IsAlive() then --Destroy the group Group:Destroy() end end end ) end --Add debugging information DebugLogger("A2A RANGE FUNCTIONS LOADED") -------------------------------------------------------------------------------------------------------------------------- -- Setup A2G Range Functions -------------------------------------------------------------------------------------------------------------------------- --Zone clear function function Clear_Zone(Zone) Zone:RemoveJunk() end --Range Respawn function function CleanA2Ggroup(args) --Define variables local rangeGroup = args[1] local aliveRangeGroups = SET_GROUP:New():FilterCategoryGround():FilterOnce() --loop through each group aliveRangeGroups:ForEachGroup( function(Group) --Check to see if group is within the provided zone if rangeGroup.zoneObj:IsVec2InZone(Group:GetVec2()) then --Check if group has A2G_Range in the group name if string.find(string.upper(Group:GetName()),"A2G_RANGE") then --Destroy what's remaining of the group Group:Destroy() end end end ) --Clean up the zone Clear_Zone(rangeGroup.zoneObj) --Loop through each static group for _,v in pairs (rangeGroup.staticGroupObj) do --Check to see if object exists if v then --Respawn group with slightly randomized position local SpawnGroupObj = SPAWN:New(v:GetName()):Spawn() end end --Loop through each dynamic group for _,v in pairs (rangeGroup.dynamicGroupObj) do --Check to see if object exists if v then --Respawn group with randomized position local SpawnGroupObj = SPAWN:New(v:GetName()):SpawnInZone(rangeGroup.zoneObj,true) end end end --Add debugging information DebugLogger("A2G RANGE FUNCTIONS LOADED") ----------------------------------------------------------------------------- -- Define Graded Target Range Object and Parameters ----------------------------------------------------------------------------- --Define the new range Object TargetRange=RANGE:New(string.upper(RANGE_DATA["RangeInfo"].rangeName)) --Turn on Debugging --TargetRange:DebugON() --Define the bombing and strafing pit targets and their base parameters TargetRange:AddBombingTargets(RANGE_DATA["Bombing"].targetUnits, RANGE_DATA["Bombing"].goodHitRange) TargetRange:AddStrafePit(RANGE_DATA["Strafing"].targetUnits, RANGE_DATA["Strafing"].boxLength, RANGE_DATA["Strafing"].boxWidth, RANGE_DATA["Strafing"].heading, RANGE_DATA["Strafing"].inverseHeading,RANGE_DATA["Strafing"].goodPass, RANGE_DATA["Strafing"].foulLine) --Define the bombing range Parameters TargetRange:SetBombTargetSmokeColor(RANGE_DATA["Bombing"].targetSmokeColor) TargetRange:SetBombtrackThreshold(RANGE_DATA["Bombing"].trackThreshold) --Define the strafing portion of the range TargetRange:SetStrafePitSmokeColor(RANGE_DATA["Strafing"].pitSmokeColor) TargetRange:SetStrafeTargetSmokeColor(RANGE_DATA["Strafing"].targetSmokeColor) --Define Range Parameters TargetRange:SetRangeZone(ZONE:New(RANGE_DATA["RangeInfo"].triggerZoneName)) TargetRange:TrackRocketsON() TargetRange:TrackBombsON() TargetRange:TrackMissilesON() TargetRange:SetRangeControl(RANGE_DATA["RangeInfo"].rangeControlFreq) TargetRange:SetInstructorRadio(RANGE_DATA["RangeInfo"].rangeInstructorFreq) TargetRange:SetMessageTimeDuration(20) --Setup SRS Functions TargetRange:SetSRS(SRS_PATH,SRS_PORT,coalition.side.BLUE) TargetRange:SetSRSRangeControl(RANGE_DATA["RangeInfo"].rangeControlFreq,radio.modulation.AM,nil,"en-US",((math.random(1,2) == 1) and "male" or "female"),RANGE_DATA["RangeInfo"].rangeControlUnit) TargetRange:SetSRSRangeInstructor(RANGE_DATA["RangeInfo"].rangeInstructorFreq,radio.modulation.AM,nil,"en-US",((math.random(1,2) == 1) and "male" or "female"),RANGE_DATA["RangeInfo"].rangeControlUnit) --Turn Funkman on TargetRange:SetFunkManOn() --Setup data saving --TargetRange:SetAutosaveOn() --Add debugging information DebugLogger("GRADED RANGE FUNCTIONS LOADED") ----------------------------------------------------------------------------- -- Setup the menu system for the ranges ----------------------------------------------------------------------------- --Define range menus local rangeTopMenu = MENU_MISSION:New("TACG RANGE MENUS") --Loop through all the A2A ranges for _,range in pairs (ACTIVE_A2A_RANGE) do --Check to see if the range exists if range.zoneObj then --Define variables local rangeName = string.gsub(string.gsub(string.upper(range.zoneObj:GetName()),"A2A_RANGE_",""),"_", " ") --Load the Range Menus A2ARangeTopMenu = MENU_COALITION:New(coalition.side.BLUE, "A2A RANGES", rangeTopMenu) A2ARangeNameMenu = MENU_COALITION:New(coalition.side.BLUE, string.upper(rangeName), A2ARangeTopMenu) --Sort the BFM Group table table.sort(range.bfmGroupObj) --Loop through each BFM aircraft group for _,aircraftObj in pairs(range.bfmGroupObj) do --Define variables local aircraftType = string.gsub(string.gsub(string.gsub(string.gsub(string.gsub(string.gsub(string.upper(aircraftObj:GetName()),"A2A_RANGE_",""),"BFM_",""),"_1",""),"_2",""),"_3",""),"_4","") --DebugLogger(aircraftType) --Create sub menus A2ARangeBfmTopMenu = MENU_COALITION:New(coalition.side.BLUE, "SPAWN BFM GROUP", A2ARangeNameMenu) A2ARangeBfmACMenu = MENU_COALITION:New(coalition.side.BLUE, string.upper("SPAWN " .. aircraftType .. " GROUP"), A2ARangeBfmTopMenu) A2ARangeBfMACQtyMenu1 = MENU_COALITION_COMMAND:New(coalition.side.BLUE, string.upper("SPAWN " .. aircraftType .. " X1 SHIP "), A2ARangeBfmACMenu, SpawnA2Agroup,{range.bfmGroupObj, aircraftType, 1}) A2ARangeBfMACQtyMenu2 = MENU_COALITION_COMMAND:New(coalition.side.BLUE, string.upper("SPAWN " .. aircraftType .. " X2 SHIP "), A2ARangeBfmACMenu, SpawnA2Agroup,{range.bfmGroupObj, aircraftType, 2}) A2ARangeBfMACQtyMenu3 = MENU_COALITION_COMMAND:New(coalition.side.BLUE, string.upper("SPAWN " .. aircraftType .. " X3 SHIP "), A2ARangeBfmACMenu, SpawnA2Agroup,{range.bfmGroupObj, aircraftType, 3}) A2ARangeBfMACQtyMenu4 = MENU_COALITION_COMMAND:New(coalition.side.BLUE, string.upper("SPAWN " .. aircraftType .. " X4 SHIP "), A2ARangeBfmACMenu, SpawnA2Agroup,{range.bfmGroupObj, aircraftType, 4}) end --Sor the BVR Group table table.sort(range.bvrGroupObj) --Loop through each BVR aircraft group for _,aircraftObj in pairs(range.bvrGroupObj) do --Define variables local aircraftType = string.gsub(string.gsub(string.gsub(string.gsub(string.gsub(string.gsub(string.upper(aircraftObj:GetName()),"A2A_RANGE_",""),"BVR_",""),"_1",""),"_2",""),"_3",""),"_4","") --DebugLogger(aircraftType) --Create sub menus A2ARangeBvrTopMenu = MENU_COALITION:New(coalition.side.BLUE, "SPAWN BVR GROUP", A2ARangeNameMenu) A2ARangeBvrACMenu = MENU_COALITION:New(coalition.side.BLUE, string.upper("SPAWN " .. aircraftType .. " GROUP"), A2ARangeBvrTopMenu) A2ARangeBvrACQtyMenu1 = MENU_COALITION_COMMAND:New(coalition.side.BLUE, string.upper("SPAWN " .. aircraftType .. " X1 SHIP "), A2ARangeBvrACMenu, SpawnA2Agroup,{range.bvrGroupObj, aircraftType, 1}) A2ARangeBvrACQtyMenu2 = MENU_COALITION_COMMAND:New(coalition.side.BLUE, string.upper("SPAWN " .. aircraftType .. " X2 SHIP "), A2ARangeBvrACMenu, SpawnA2Agroup,{range.bvrGroupObj, aircraftType, 2}) A2ARangeBvrACQtyMenu3 = MENU_COALITION_COMMAND:New(coalition.side.BLUE, string.upper("SPAWN " .. aircraftType .. " X3 SHIP "), A2ARangeBvrACMenu, SpawnA2Agroup,{range.bvrGroupObj, aircraftType, 3}) A2ARangeBvrACQtyMenu4 = MENU_COALITION_COMMAND:New(coalition.side.BLUE, string.upper("SPAWN " .. aircraftType .. " X4 SHIP "), A2ARangeBvrACMenu, SpawnA2Agroup,{range.bvrGroupObj, aircraftType, 4}) end A2ARangeKillMenu = MENU_COALITION_COMMAND:New(coalition.side.BLUE, "CLEAN UP THE RANGE", A2ARangeNameMenu, CleanA2Agroup,{range.zoneObj}) end end --Loop through all the A2G ranges for _,range in pairs (ACTIVE_A2G_RANGE) do --Check to see if the range exists if range.zoneObj then --Define variables local rangeName = string.gsub(string.gsub(string.gsub(string.upper(range.zoneObj:GetName()),"A2G_RANGE_STATIC",""),"A2G_RANGE_DYNAMIC",""),"_", " ") --Load the Range Menus A2GRangeTopMenu = MENU_COALITION:New(coalition.side.BLUE, "A2G RANGES", rangeTopMenu) A2GRangeNameMenu = MENU_COALITION:New(coalition.side.BLUE, string.upper(rangeName), A2GRangeTopMenu) A2RRangeCleanMenu = MENU_COALITION_COMMAND:New(coalition.side.BLUE, "CLEAN UP THE RANGE", A2GRangeNameMenu, CleanA2Ggroup,{range}) end end --Create the Graded Ranges Menus local GradedRangeTopMenu = MENU_COALITION:New(coalition.side.BLUE, "GRADED RANGES", rangeTopMenu) TargetRange:SetMenuRoot(GradedRangeTopMenu) --Add debugging information DebugLogger("RANGE MENUS LOADED") ----------------------------------------------------------------------------- -- Start all tasks ----------------------------------------------------------------------------- --Spawn all the range objects for _,v in pairs (ACTIVE_A2G_RANGE) do CleanA2Ggroup({v}) end --Start the Range TargetRange:Start() --Add debugging information DebugLogger("RANGES STARTED") ----------------------------------------------------------------------------- -- OUTPUT DEBUGGING Information ----------------------------------------------------------------------------- env.info("DYNAMIC RANGE SCRIPT: SCRIPT LOADED SUCCESSFULLY")