--[[ DCS FAC v2.1.25 ------- Authors: Pb_Magnet (github.com/jweisner), modified by Shadow NOTE: Almost all of the hard stuff here is copied/adapted from CTLD: https://github.com/ciribob/DCS-CTLD This script was originally submitted as a PR to include in CTLD, but there didn't seem to be any interest from CTLD vOv New features: Required Scripts for this scrip to function: Mist markManager Reworked Artillery control via F10 Auto Map Marking RECCE Units --> Cant Lase but will mark all units in an area Manual Targeting mode Offset Mortar aimpoint to compensate for rounds falling short Added arty fire type choice Added AI Artillery Spotters Added Air Ops Menu for TALD and Carpet Bomb Map Attack Integrated Naval Fire Support Added AI RECCE support Readded MLRS support ]] local facPlayerSpawn ={} fac = {} -- do not modify this line local CrptBmbDesig = {} local RECCEDesig = {} function contains(t, e) for i = 1,#t do if t[i] == e then return true end end return false end function removebyKey(tab, val) for i, v in ipairs (tab) do if (v.id == val) then tab[i] = nil end end end fac.facACTypes ={ "SA342L", "UH-1H", "Mi-8MTV2", --"TF-51", --"Hawk", } fac.artyDirectorTypes = { "Soldier M249", --"Paratrooper AKS-74", --"Soldier M4", } -- ***************** FAC CONFIGURATION ***************** fac.FAC_maxDistance = 18520 -- How far a FAC can "see" in meters (with Line of Sight) fac.AutoOn = true -- when enabled turns auto on station for AFAC fac.FAC_smokeOn_RED = true -- enables marking of target with smoke for RED forces fac.FAC_smokeOn_BLUE = true -- enables marking of target with smoke for BLUE forces fac.FAC_smokeColour_RED = 0 -- RED side smoke colour -- Green = 0 , Red = 1, White = 2, Orange = 3, Blue = 4 (if using flares limit to green and orange) fac.FAC_smokeColour_BLUE = 3 -- BLUE side smoke colour -- Green = 0 , Red = 1, White = 2, Orange = 3, Blue = 4 (if using flares limit to green and orange) fac.FAC_FACStatusF10 = true -- enables F10 FAC Status menu fac.FAC_location = true -- shows location of target in FAC message fac.FAC_lock = "all" -- "vehicle" OR "troop" OR "all" forces FAC to only lock vehicles or troops or all ground units fac.FAC_laser_codes = { '1688', '1677', '1666', '1113','1115' ,'1111'} fac.fireMissionRounds = 24 -- number of shells per fire mission request fac.illumHeight = 500 --height for illumination bomb fac.facOffsetDist = 5000 fac.markID = 1000 --intial MarkerID fac.recceID = 50000 --Initial recce ID number -- ******************** FAC names ********************** function fac.isAFAC(acUnit) local playerGroup = Unit.getGroup(acUnit) local playerGroupName = playerGroup:getName() local AFACmatch = 0 if (string.find(playerGroupName, "AFAC") == nil) and (string.find(playerGroupName, "RECON") == nil) then AFACmatch = 0 else AFACmatch = 1 end if contains(fac.facACTypes,acUnit:getTypeName()) then AFACmatch = 1 end return AFACmatch end function fac.isRECCE(acUnit) local playerGroup = Unit.getGroup(acUnit) local playerGroupName = playerGroup:getName() local RECCEmatch = 0 --trigger.action.outText(acUnit:getTypeName(),5) if (string.find(playerGroupName, "RECCE") == nil) and (string.find(playerGroupName, "RECON") == nil) then RECCEmatch = 0 else RECCEmatch = 1 end if contains(fac.facACTypes,acUnit:getTypeName()) then RECCEmatch = 1 end return RECCEmatch end function fac.isArtyD(acUnit) local adMatch = 0 local playerGroup = Unit.getGroup(acUnit) if playerGroup then local playerGroupName = playerGroup:getName() if playerGroupName then if contains(fac.artyDirectorTypes,acUnit:getTypeName()) then adMatch = 1 end end end return adMatch end -- Use any of the predefined names or set your own ones fac.facPilotNames = { "Chevy 6-1", "Chevy 6-2", "Chevy 6-3", "Chevy 6-4", "Chevy 5-1", "Chevy 5-2", "Chevy 5-3", "Chevy 5-4", "Chevy 4-1", "Chevy 4-2", "Chevy 4-3", "Chevy 4-4", "Chevy 2-1", "Chevy 2-2", "Chevy 2-3", "Chevy 2-4", "Chevy 1-1", "Chevy 1-2", "Chevy 1-3", "Chevy 1-4", "837", "838", "839", "840", "841", "842", "843", "844", -- "Red AFAC #001", -- "Red AFAC #002", -- "Red AFAC #003", -- "Red AFAC #004", -- "Red AFAC #005", -- "Red AFAC #006", -- "Red AFAC #007", -- "Red AFAC #008", -- "Red AFAC #009", -- "Red AFAC #010", -- "Blue AFAC #001", -- "Blue AFAC #002", -- "Blue AFAC #003", -- "Blue AFAC #004", -- "Blue AFAC #005", -- "Blue AFAC #006", -- "Blue AFAC #007", -- "Blue AFAC #008", -- "Blue AFAC #009", -- "Blue AFAC #010", -- "helicargo4", -- "helicargo8", -- "FAC #001", -- "FAC #002", -- "FAC #003", -- "FAC #004", -- "FAC #005", -- "FAC #006", -- "FAC #007", -- "FAC #008", -- "RED Mobile FOB TRANSPORT #001", -- "RED Mobile FOB TRANSPORT #002", -- "BLUE Mobile FOB TRANSPORT #001", -- "BLUE Mobile FOB TRANSPORT #002", } --Define RECCE pilots fac.reccePilotNames = { --Enter RECCE pilot names here, "RECCE1", "RECCE2", } fac.artDirectNames = { "RECCE1", "RECCE2", "RECCE3", "RECCE4", } --init FAC -- Auto Detects Group names and adds unit to FAC and RECCE list function facPlayerSpawn:onEvent(e) if e.id == world.event.S_EVENT_BIRTH then local objType = e.initiator:getDesc() if Object.getCategory(e.initiator) == 1 then if objType.category < 2 then local AFAC = fac.isAFAC(e.initiator) local RECCE = fac.isRECCE(e.initiator) local test2 = Unit.getGroup(e.initiator) local gid = test2:getID() local afacUnitName = e.initiator:getName() local checkAFACName, afacIdx = contains(fac.facPilotNames,afacUnitName) local checkRECCEName, afacIdx = contains(fac.reccePilotNames,afacUnitName) --trigger.action.outText(RECCE .. afacUnitName,5) if AFAC == 1 then if contains(fac.facPilotNames,afacUnitName) == false then table.insert(fac.facPilotNames, afacUnitName) trigger.action.outTextForGroup(gid,"Your A/C is an AFAC and added to AFAC List \nUse your F10 menu to spot targets for your team and call in artillery strikes", 15) else trigger.action.outTextForGroup(gid,"Your A/C is an AFAC \nUse your F10 menu to spot targets for your team and call in artillery strikes", 15) end if fac.AutoOn == true then fac.setFacOnStation({afacUnitName,true}) end --trigger.action.outTextForGroup(gid,"Your A/C is an AFAC "..afacUnitName.." "..#fac.facPilotNames, 15) --trigger.action.outText(rampcheck,5) elseif checkAFACName == true then trigger.action.outTextForGroup(gid,"Your A/C is an AFAC \nUse your F10 menu to spot targets for your team and call in artillery strikes", 15) end if RECCE == 1 then if contains(fac.reccePilotNames,afacUnitName) == false then table.insert(fac.reccePilotNames, afacUnitName) trigger.action.outTextForGroup(gid,"Your A/C is an RECCE and added to RECCE List \nUse your F10 menu to spot all targets in an area for your team and mark them on the F10 map", 15) else trigger.action.outTextForGroup(gid,"Your A/C is an Recon A/C \nUse your F10 menu to spot all targets in an area for your team and mark them on the F10 map", 15) end elseif checkRECCEName == true then trigger.action.outTextForGroup(gid,"Your A/C is an RECCE \nUse your F10 menu to spot all targets in an area for your team and mark them on the F10 map", 15) end elseif objType.category == 2 then local artDirect = fac.isArtyD(e.initiator) local afacUnitName = e.initiator:getName() local test2 = Unit.getGroup(e.initiator) local gid = test2:getCoalition() if artDirect == 1 then if contains(fac.artDirectNames,afacUnitName) == false then table.insert(fac.artDirectNames, afacUnitName) --trigger.action.outText("Artillery Spotter has been deployed" .. e.initiator:getTypeName() , 15) end end end end end end world.addEventHandler(facPlayerSpawn) --Arty properties from Mbot's AES script fac.ArtilleryProperties = { ["2B11 mortar"] = { minrange = 500, --Minimal firing range maxrange = 7000, --Maximal firing range FM_rounds = 24, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 0, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 0 --Time the battery waits between firing and moving }, ["SAU 2-C9"] = { minrange = 500, --Minimal firing range maxrange = 7000, --Maximal firing range FM_rounds = 24, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 0, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 10 --Time the battery waits between firing and moving }, ["M-109"] = { minrange = 300, --Minimal firing range maxrange = 22000, --Maximal firing range FM_rounds = 24, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 160, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 10 --Time the battery waits between firing and moving }, ["SAU Gvozdika"] = { minrange = 300, --Minimal firing range maxrange = 15000, --Maximal firing range FM_rounds = 24, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 0, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 10 --Time the battery waits between firing and moving }, ["SAU Akatsia"] = { minrange = 300, --Minimal firing range maxrange = 17000, --Maximal firing range FM_rounds = 24, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 0, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 10 --Time the battery waits between firing and moving }, ["SAU Msta"] = { minrange = 300, --Minimal firing range maxrange = 23500, --Maximal firing range FM_rounds = 24, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 300, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 10 --Time the battery waits between firing and moving }, ["MLRS"] = { minrange = 10000, --Minimal firing range maxrange = 32000, --Maximal firing range FM_rounds = 12, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 12, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 10 --Time the battery waits between firing and moving }, ["Grad-URAL"] = { minrange = 5000, --Minimal firing range maxrange = 19000, --Maximal firing range FM_rounds = 120, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 40, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 120 --Time the battery waits between firing and moving }, ["Smerch"] = { minrange = 20000, --Minimal firing range maxrange = 70000, --Maximal firing range FM_rounds = 24, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 12, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 120 --Time the battery waits between firing and moving }, ["Uragan_BM-27"] = { minrange = 11500, --Minimal firing range maxrange = 35800, --Maximal firing range FM_rounds = 16, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 12, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 120 --Time the battery waits between firing and moving }, ["SpGH_Dana"] = { minrange = 300, --Minimal firing range maxrange = 18700, --Maximal firing range FM_rounds = 16, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 12, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 120 --Time the battery waits between firing and moving }, ["Smerch_HE"] = { minrange = 20000, --Minimal firing range maxrange = 70000, --Maximal firing range FM_rounds = 16, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 12, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 120 --Time the battery waits between firing and moving }, ["T155_Firtina"] = { minrange = 300, --Minimal firing range maxrange = 41000, --Maximal firing range FM_rounds = 16, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 12, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 120 --Time the battery waits between firing and moving }, ["PLZ05"] = { minrange = 300, --Minimal firing range maxrange = 23500, --Maximal firing range FM_rounds = 16, --The total amount of shots of a fire mission for a battery of this unit type minAmmo = 12, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire displacementTime = 120 --Time the battery waits between firing and moving }, -- ["hy_launcher"] = { -- doesn't work do not use -- minrange = 3000, --Minimal firing range -- maxrange = 40000, --Maximal firing range -- FM_rounds = 16, --The total amount of shots of a fire mission for a battery of this unit type -- minAmmo = 12, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire -- displacementTime = 120 --Time the battery waits between firing and moving -- }, -- ["TomahawkLauncher"] = { -- minrange = 18520, --Minimal firing range -- maxrange = 460000, --Maximal firing range -- FM_rounds = 16, --The total amount of shots of a fire mission for a battery of this unit type -- minAmmo = 12, --The amount of rounds left in a individual unit when switching from rapid fire to sustained fire -- displacementTime = 120 --Time the battery waits between firing and moving -- } } ------------ FAC ----------- fac.facManTGT = {} fac.facLaserPoints = {} fac.facIRPoints = {} fac.facSmokeMarks = {} fac.facUnits = {} -- list of FAC units for f10 command fac.facCurrentTargets = {} fac.facAddedTo = {} -- keeps track of who's had the fac command menu added fac.RECCEAddedTo = {} -- keeps track of who's had the RECCE command menu added fac.facRadioAdded = {} -- keeps track of who's had the radio command added fac.facLaserPointCodes = {} -- keeps track of what laser code is used by each fac fac.facOnStation = {} -- keeps track of which facs are on station fac.markerType = {} -- keeps track of marker type per FAC fac.markerTypeColor = {} -- keeps track of marker color per FAC fac.redArty = {} -- keeps track of available arty for Red fac.bluArty = {} --keeps track of available arty for Blue fac.ArtyTasked = {} --keeps track of Arty with current fire missions fac.RECCETasked = {} fac.AITgted = {} -- search for activated FAC units and schedule facAutoLase function fac.checkFacStatus() --env.info("FAC checkFacStatus") timer.scheduleFunction(fac.checkFacStatus, nil, timer.getTime() + 1.0) local _status, _result = pcall(function() for _, _facUnitName in ipairs(fac.facPilotNames) do local _facUnit = fac.getFacUnit(_facUnitName) if _facUnit ~= nil then --[[ if fac.facOnStation[_facUnitName] == true then env.info("FAC DEBUG: fac.checkFacStatus() " .. _facUnitName .. " on-station") end if fac.facOnStation[_facUnitName] == nil then env.info("FAC DEBUG: fac.checkFacStatus() " .. _facUnitName .. " off-station") end ]] -- if fac is off-station and is AI, set onStation if fac.facUnits[_facUnitName] == nil and _facUnit:getPlayerName() == nil then --env.info("FAC: setting onStation for AI fac unit " .. _facUnitName) fac.setFacOnStation({_facUnitName, true}) end -- start facAutoLase if the FAC is on station and not already scheduled if fac.facUnits[_facUnitName] == nil and fac.facOnStation[_facUnitName] == true then env.info("FAC: found new FAC unit. Starting facAutoLase for " .. _facUnitName) fac.facAutoLase(_facUnitName) --(_facUnitName, _laserCode, _smoke, _lock, _colour) end end end end) if (not _status) then env.error(string.format("FAC ERROR: %s", _result)) end end -- gets the FAC status and displays to coalition units function fac.getFacStatus(_args) --returns the status of all FAC units local _playerUnit = fac.getFacUnit(_args[1]) local colorString = {["0"] = "GREEN" ,["1"] = "RED" ,["2"] = "WHITE", ["3"] = "ORANGE" , ["4"] = "BLUE"} if _playerUnit == nil then return end local _side = _playerUnit:getCoalition() local _mkrColor if _side == 1 then _mkrColor = fac.FAC_smokeColour_BLUE elseif _side == 2 then _mkrColor = fac.FAC_smokeColour_RED else _mkrColor = 2 end local _facUnit = nil local _message = "FAC STATUS: \n\n" for _facUnitName, _facDetails in pairs(fac.facUnits) do --look up units _facUnit = Unit.getByName(_facDetails.name) if _facUnit ~= nil and _facUnit:getLife() > 0 and _facUnit:isActive() == true and _facUnit:getCoalition() == _side and fac.facOnStation[_facUnitName] == true then local _enemyUnit = fac.getCurrentFacUnit(_facUnit, _facUnitName) local _laserCode = fac.facLaserPointCodes[_facUnitName] -- get player name if available local _facName = _facUnitName if _facUnit:getPlayerName() ~= nil then _facName = _facUnit:getPlayerName() end if fac.markerTypeColor[_facName] ~= nil then _mkrColor = fac.markerTypeColor[_facName] end if _laserCode == nil then _laserCode = "UNKNOWN" end if fac.markerType[_facUnitName] == nil then fac.markerType[_facUnitName] = "FLARES" end if _enemyUnit ~= nil and _enemyUnit:getLife() > 0 and _enemyUnit:isActive() == true then _message = _message .. "" .. _facName .. " targeting " .. _enemyUnit:getTypeName() .. " CODE: " .. _laserCode .. fac.getFacPositionString(_enemyUnit) .. "\nMarked with " .. colorString[tostring(_mkrColor)] .." ".. fac.markerType[_facUnitName].. "\n" else _message = _message .. "" .. _facName .. " on-station and searching for targets" .. " CODE: " .. _laserCode .. "\n" end end end if _message == "FAC STATUS: \n\n" then _message = "No Active FACs, Join a slot labeled RECON or AFAC to play as a flying JTAC and Artillery Spotter" end fac.notifyCoalition(_message, 60, _side) end function fac.getFacPositionString(_unit) if fac.FAC_location == false then return "" end local _lat, _lon = coord.LOtoLL(_unit:getPosition().p) local unitPos = _unit:getPoint() -- local _latDeg,_latMinf = math.modf(_lat) -- local _longDeg,_longMinf = math.modf(_lat) -- local _latMin, _latSecf = math.modf(_latMinf*60) -- local _longMin, _longSecf = math.modf(_longMinf*60) -- local _latSec = _latSecf*605 -- local _longSec = _longSecf*60 local _latLngStr = mist.tostringLL(_lat, _lon, 3, false) local _latLngSecStr = mist.tostringLL(_lat, _lon, 3, true) local _mgrsString = mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(_unit:getPosition().p)), 5) return " @\n- DD " .. _latLngStr .." \n- DMS: " .. _latLngSecStr .. " \n- MGRS: " .. _mgrsString .."\nAltitude: ".. math.floor(unitPos.y) .."m/" .. math.floor(unitPos.y*3.28084) .."ft" end -- get currently selected unit and check if the FAC is still in range function fac.getCurrentFacUnit(_facUnit, _facUnitName) local _unit = nil if fac.facCurrentTargets[_facUnitName] ~= nil then _unit = Unit.getByName(fac.facCurrentTargets[_facUnitName].name) end local _tempPoint = nil local _tempDist = nil local _tempPosition = nil local _facPosition = _facUnit:getPosition() local _facPoint = _facUnit:getPoint() if _unit ~= nil and _unit:getLife() > 0 and _unit:isActive() == true then -- calc distance _tempPoint = _unit:getPoint() -- tempPosition = unit:getPosition() _tempDist = fac.getDistance(_unit:getPoint(), _facUnit:getPoint()) if _tempDist < fac.FAC_maxDistance then -- calc visible -- check slightly above the target as rounding errors can cause issues, plus the unit has some height anyways local _offsetEnemyPos = { x = _tempPoint.x, y = _tempPoint.y + 2.0, z = _tempPoint.z } local _offsetFacPos = { x = _facPoint.x, y = _facPoint.y + 2.0, z = _facPoint.z } if land.isVisible(_offsetEnemyPos, _offsetFacPos) then return _unit end end end return nil end function fac.getFacUnit(_facUnitName) if _facUnitName == nil then return nil end local _fac = Unit.getByName(_facUnitName) if _fac ~= nil and _fac:isActive() and _fac:getLife() > 0 then return _fac end return nil end -- gets the FAC player name if available function fac.getFacName(_facUnitName) local _facUnit = Unit.getByName(_facUnitName) local _facName = _facUnitName if _facUnit == nil then --env.info('FAC: fac.getFacName: unit not found: '.._facUnitName) return _facUnitName end if _facUnit:getPlayerName() ~= nil then _facName = _facUnit:getPlayerName() end return _facName end function fac.facAutoLase(_facUnitName, _laserCode, _smoke, _lock, _colour,_knwnTarget) local colorString = { ["0"] = "GREEN" ,["1"] = "RED" ,["2"] = "WHITE", ["3"] = "ORANGE" ,["4"] = "BLUE"} --env.info('FAC DEBUG: ' .. _facUnitName .. ' autolase') if _lock == nil then _lock = fac.FAC_lock end local _mkrColor local _facUnit = Unit.getByName(_facUnitName) if _facUnit == nil then --env.info('FAC: ' .. _facUnitName .. ' dead.') -- FAC was in the list, now the unit is missing: probably dead if fac.facUnits[_facUnitName] ~= nil then fac.notifyCoalition("[Forward Air Controller \"" ..fac.getFacName(_facUnitName).. "\" MIA.]", 10, fac.facUnits[_facUnitName].side) end --remove fac fac.cleanupFac(_facUnitName) return end local side = _facUnit:getCoalition() if side == 1 then _mkrColor = fac.FAC_smokeColour_BLUE elseif side == 2 then _mkrColor = fac.FAC_smokeColour_RED else _mkrColor = 2 end -- stop fac activity if fac is marked off-station CANCELS AUTO-LASE if fac.facOnStation[_facUnitName] == nil then env.info('FAC: ' .. _facUnitName .. ' is marked off-station, stopping autolase') fac.cancelFacLase(_facUnitName) fac.facCurrentTargets[_facUnitName] = nil return end if fac.facLaserPointCodes[_facUnitName] == nil then --env.info('FAC: fac.facAutoLase() ' .. _facUnitName .. ' has no laserCode, setting default') fac.facLaserPointCodes[_facUnitName] = fac.FAC_laser_codes[1] end _laserCode = fac.facLaserPointCodes[_facUnitName] --env.info('FAC: ' .. _facUnitName .. ' laser code: ' .. _laserCode) if fac.facUnits[_facUnitName] == nil then --env.info('FAC: ' .. _facUnitName .. ' not in fac.facUnits list, adding') --add to list fac.facUnits[_facUnitName] = { name = _facUnit:getName(), side = _facUnit:getCoalition() } -- work out smoke colour if _colour == nil then if _facUnit:getCoalition() == 1 then _colour = fac.FAC_smokeColour_RED else _colour = fac.FAC_smokeColour_BLUE end end if fac.markerTypeColor[_facUnitName] ~= nil then _colour = fac.markerTypeColor[_facUnitName] end if _smoke == nil then if _facUnit:getCoalition() == 1 then _smoke = fac.FAC_smokeOn_RED else _smoke = fac.FAC_smokeOn_BLUE end end end if fac.markerType[_facUnitName] == nil then fac.markerType[_facUnitName] = "FLARES" end -- search for current unit if _facUnit:isActive() == false then fac.cleanupFac(_facUnitName) env.info('FAC: ' .. _facUnitName .. ' Not Active - Waiting 30 seconds') timer.scheduleFunction(fac.timerFacAutoLase, { _facUnitName, _laserCode, _smoke, _lock, _colour }, timer.getTime() + 30) return end local _enemyUnit = fac.getCurrentFacUnit(_facUnit, _facUnitName) if _enemyUnit == nil and fac.facCurrentTargets[_facUnitName] ~= nil then local _tempUnitInfo = fac.facCurrentTargets[_facUnitName] local _tempUnit = Unit.getByName(_tempUnitInfo.name) if _tempUnit ~= nil and _tempUnit:getLife() > 0 and _tempUnit:isActive() == true then fac.notifyCoalition("["..fac.getFacName(_facUnitName) .. " target " .. _tempUnitInfo.unitType .. " lost. Scanning for Targets.]", 10, _facUnit:getCoalition()) else fac.notifyCoalition("["..fac.getFacName(_facUnitName) .. " target " .. _tempUnitInfo.unitType .. " KIA. Good Job! Scanning for Targets.]", 10, _facUnit:getCoalition()) --trigger.action.removeMark(fac.markID+_tempUnit:getID()) end --remove from smoke list fac.facSmokeMarks[_tempUnitInfo.name] = nil -- remove from target list fac.facCurrentTargets[_facUnitName] = nil --stop lasing fac.cancelFacLase(_facUnitName) end if _enemyUnit == nil then if _knwnTarget == nil then _enemyUnit = fac.findFacNearestVisibleEnemy(_facUnit, _lock) else _enemyUnit = _knwnTarget end if _enemyUnit ~= nil then local tgtMarkID = timer.getTime() * 1000 -- store current target for easy lookup fac.facCurrentTargets[_facUnitName] = { name = _enemyUnit:getName(), unitType = _enemyUnit:getTypeName(), unitId = _enemyUnit:getID() } local _vel = _enemyUnit:getVelocity() local _spd = 0 if _vel ~=nil then _spd = math.sqrt(_vel.x^2+_vel.z^2) end local unitPos = _enemyUnit:getPoint() local _lat, _lon = coord.LOtoLL(_enemyUnit:getPosition().p) local _latLngStr = mist.tostringLL(_lat, _lon, 3, false) local _latLngSecStr = mist.tostringLL(_lat, _lon, 3, true) local _mgrsString = mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(_enemyUnit:getPosition().p)), 5) local _eTypeName = _enemyUnit:getTypeName() trigger.action.markToCoalition(tgtMarkID,_eTypeName.. " - DMS: " .. _latLngSecStr .." Altitude: ".. math.floor(unitPos.y) .."m/" .. math.floor(unitPos.y*3.28084) .."ft".. "\nHeading: ".. math.floor(getHeading(_enemyUnit) * 180/math.pi) .. "\nSpeed: " .. math.floor(_spd*2) .. " MPH" .."\nSpotted by: " .. fac.getFacName(_facUnitName), _enemyUnit:getPoint(), _facUnit:getCoalition(),false,fac.getFacName(_facUnitName).." marked a target") timer.scheduleFunction(removeSetMark,{tgtMarkID},timer.getTime() + 120) fac.notifyCoalition("["..fac.getFacName(_facUnitName) .. " lasing new target " .. _eTypeName .. '. CODE: ' .. _laserCode .. fac.getFacPositionString(_enemyUnit).."\nMarked with "..colorString[tostring(_colour)] .." "..fac.markerType[_facUnitName].."]" , 10, _facUnit:getCoalition()) local tgtMark = fac.markID+1 --local tgtMark = curMark fac.markID = tgtMark -- create smoke if _smoke == true then --trigger.action.removeMark(tgtMark) --timer.scheduleFunction(trigger.action.removeMark,{tgtMark},timer.getTime() + 30) --create first smoke fac.createSmokeMarker(_enemyUnit, _colour,_facUnitName) end end end if _enemyUnit ~= nil then fac.facLaseUnit(_enemyUnit, _facUnit, _facUnitName, _laserCode) -- DEBUG --env.info('FAC: Timer timerSparkleLase '.._facUnitName.." ".._laserCode.." ".._enemyUnit:getName()) -- local _vel = _enemyUnit:getVelocity() local _spd = 0 if _vel ~=nil then _spd = math.sqrt(_vel.x^2+_vel.z^2) end local timeNext if _spd < 1 then timeNext = 1 else timeNext = 1/(_spd) end --trigger.action.outText(timeNext,10) timer.scheduleFunction(fac.timerFacAutoLase, { _facUnitName, _laserCode, _smoke, _lock, _colour }, timer.getTime() + timeNext) if _smoke == true then local _nextSmokeTime = fac.facSmokeMarks[_enemyUnit:getName()] --recreate smoke marker after 5 mins if _nextSmokeTime ~= nil and _nextSmokeTime < timer.getTime() then fac.createSmokeMarker(_enemyUnit, _colour,_facUnitName) end end else --env.info('FAC: LASE: No Enemies Nearby') -- stop lazing the old spot fac.cancelFacLase(_facUnitName) timer.scheduleFunction(fac.timerFacAutoLase, { _facUnitName, _laserCode, _smoke, _lock, _colour }, timer.getTime() + 5) end end -- used by the timer function function fac.timerFacAutoLase(_args) fac.facAutoLase(_args[1], _args[2], _args[3], _args[4], _args[5]) end function fac.cleanupFac(_facUnitName) -- clear laser - just in case fac.cancelFacLase(_facUnitName) -- Cleanup fac.facLaserPoints[_facUnitName] = nil fac.facIRPoints[_facUnitName] = nil fac.facSmokeMarks[_facUnitName] = nil fac.facUnits[_facUnitName] = nil fac.facCurrentTargets[_facUnitName] = nil fac.facAddedTo[_facUnitName] = nil fac.facRadioAdded[_facUnitName] = nil fac.facLaserPointCodes[_facUnitName] = nil fac.facOnStation[_facUnitName] = nil fac.markerType[_facUnitName] = nil end function fac.createFacSmokeMarker(_enemyUnit, _colour,_facUnitName) --recreate in 5 mins if fac.markerType[_facUnitName] == "SMOKE" then fac.facSmokeMarks[_enemyUnit:getName()] = timer.getTime() + 300.0 else fac.facSmokeMarks[_enemyUnit:getName()] = timer.getTime() + 5 end -- move smoke 2 meters above target for ease local _enemyPoint = _enemyUnit:getPoint() if fac.markerType[_facUnitName] =="SMOKE" then trigger.action.smoke({ x = _enemyPoint.x + 5.0, y = _enemyPoint.y + 5.0, z = _enemyPoint.z }, _colour) else trigger.action.signalFlare({ x = _enemyPoint.x + 5.0, y = _enemyPoint.y + 5.0, z = _enemyPoint.z }, _colour,0) end end function fac.cancelFacLase(_facUnitName) local _tempLase = fac.facLaserPoints[_facUnitName] if _tempLase ~= nil then Spot.destroy(_tempLase) fac.facLaserPoints[_facUnitName] = nil _tempLase = nil end local _tempIR = fac.facIRPoints[_facUnitName] if _tempIR ~= nil then Spot.destroy(_tempIR) fac.facIRPoints[_facUnitName] = nil _tempIR = nil end end function fac.facLasePoint(_Point, _facUnit, _facUnitName, _laserCode) --cancelLase(_facUnitName) local _spots = {} local _enemyVector = _Point local _enemyVectorUpdated = { x = _enemyVector.x, y = _enemyVector.y + 2.0, z = _enemyVector.z } local _oldLase = fac.facLaserPoints[_facUnitName] local _oldIR = fac.facIRPoints[_facUnitName] if _oldLase == nil or _oldIR == nil then -- create lase local _status, _result = pcall(function() _spots['irPoint'] = Spot.createInfraRed(_facUnit, { x = 0, y = 2.0, z = 0 }, _enemyVectorUpdated) _spots['laserPoint'] = Spot.createLaser(_facUnit, { x = 0, y = 2.0, z = 0 }, _enemyVectorUpdated, _laserCode) return _spots end) if not _status then env.error('FAC: ERROR: ' .. _result, false) else if _result.irPoint then -- DEBUG --env.info('FAC:' .. _facUnitName .. ' placed IR Pointer on '.._enemyUnit:getName()) fac.facIRPoints[_facUnitName] = _result.irPoint --store so we can remove after end if _result.laserPoint then -- DEBUG --env.info('FAC:' .. _facUnitName .. ' is Lasing '.._enemyUnit:getName()..'. CODE:'.._laserCode) fac.facLaserPoints[_facUnitName] = _result.laserPoint end end else -- update lase if _oldLase ~= nil then _oldLase:setPoint(_enemyVectorUpdated) end if _oldIR ~= nil then _oldIR:setPoint(_enemyVectorUpdated) end end end function fac.facLaseUnit(_enemyUnit, _facUnit, _facUnitName, _laserCode) --cancelLase(_facUnitName) local _spots = {} local _enemyVector = _enemyUnit:getPoint() local _enemyVectorUpdated = { x = _enemyVector.x, y = _enemyVector.y + 2.0, z = _enemyVector.z } local _oldLase = fac.facLaserPoints[_facUnitName] local _oldIR = fac.facIRPoints[_facUnitName] if _oldLase == nil or _oldIR == nil then -- create lase local _status, _result = pcall(function() _spots['irPoint'] = Spot.createInfraRed(_facUnit, { x = 0, y = 2.0, z = 0 }, _enemyVectorUpdated) _spots['laserPoint'] = Spot.createLaser(_facUnit, { x = 0, y = 2.0, z = 0 }, _enemyVectorUpdated, _laserCode) return _spots end) if not _status then env.error('FAC: ERROR: ' .. _result, false) else if _result.irPoint then -- DEBUG --env.info('FAC:' .. _facUnitName .. ' placed IR Pointer on '.._enemyUnit:getName()) fac.facIRPoints[_facUnitName] = _result.irPoint --store so we can remove after end if _result.laserPoint then -- DEBUG --env.info('FAC:' .. _facUnitName .. ' is Lasing '.._enemyUnit:getName()..'. CODE:'.._laserCode) fac.facLaserPoints[_facUnitName] = _result.laserPoint end end else -- update lase if _oldLase ~= nil then _oldLase:setPoint(_enemyVectorUpdated) end if _oldIR ~= nil then _oldIR:setPoint(_enemyVectorUpdated) end end end -- Find nearest enemy to FAC that isn't blocked by terrain function fac.findFacNearestVisibleEnemy(_facUnit, _targetType,_distance) -- DEBUG --local _facUnitName = _facUnit:getName() --env.info('FAC:' .. _facUnitName .. ' fac.findFacNearestVisibleEnemy() ') local _maxDistance = _distance or fac.FAC_maxDistance local _x = 1 local _i = 1 local _units = nil local _groupName = nil local _nearestUnit = nil local _nearestDistance = _maxDistance local _enemyGroups local _enemyStatic local _facSide = _facUnit:getCoalition() if _facUnit:getCoalition() == 1 then _enemyGroups = coalition.getGroups(2, Group.Category.GROUND) _enemyShips = coalition.getGroups(2, Group.Category.SHIP) _enemyStatic = coalition.getStaticObjects(2) else _enemyGroups = coalition.getGroups(1, Group.Category.GROUND) _enemyShips = coalition.getGroups(1, Group.Category.SHIP) _enemyStatic = coalition.getStaticObjects(1) end local _facPoint = _facUnit:getPoint() local _facPosition = _facUnit:getPosition() local _tempPoint = nil local _tempPosition = nil local _tempDist = nil local dist = { id = world.VolumeType.SPHERE, params = { point = _facPoint, radius = fac.FAC_maxDistance --max range ARTY } } local findClosest = function(foundItem, val) -- generic search for all scenery local _unit = foundItem local foundOutput = nil local foundObjectPos = nil local sideCheck = foundItem:getCoalition() if foundItem:getLife() > 1 and foundItem:inAir() == false then if sideCheck ~= _facSide then local samFactor = 1 local _unitPos = _unit:getPoint() if _unit:hasAttribute("SAM TR") then samFactor = 0.1 elseif _unit:hasAttribute("IR Guided SAM") then samFactor = 0.5 elseif _unit:hasAttribute("AA_flak") then samFactor = 0.7 end local _tempADist = fac.getDistance(_unitPos,_facPoint) _tempDist = _tempADist*samFactor --trigger.action.outText("Found ".._tempDist.." " ..samFactor,10) local _offsetEnemyPos = { x = _unitPos.x, y = _unitPos.y + 2.0, z = _unitPos.z } local _offsetFacPos = { x = _facPoint.x, y = _facPoint.y + 2.0, z = _facPoint.z } if land.isVisible(_offsetEnemyPos, _offsetFacPos) and _unit:isActive() then local _type = fac.tgtCatType(foundItem) if _tempADist < fac.FAC_maxDistance then if _nearestDistance > _tempDist then _nearestDistance = _tempDist _nearestUnit = _unit end end end end end end world.searchObjects(Object.Category.UNIT,dist,findClosest) -- -- finish this function -- local _vhpriority = false -- local _vpriority = false -- local _thpriority = false -- local _tpriority = false -- for _i = 1, #_enemyGroups do -- if _enemyGroups[_i] ~= nil then -- _groupName = _enemyGroups[_i]:getName() -- _units = fac.getGroup(_groupName) -- if #_units > 0 then -- for _y = 1, #_units do -- local _targeted = false -- local _targetedJTAC = false -- if not _distance then -- _targeted = fac.alreadyFacTarget(_facUnit, _units[_x]) -- end -- -- calc distance -- _tempPoint = _units[_y]:getPoint() -- _tempDist = fac.getDistance(_tempPoint, _facPoint) -- if _tempDist < _maxDistance and _tempDist < _nearestDistance then -- local _offsetEnemyPos = { x = _tempPoint.x, y = _tempPoint.y + 2.0, z = _tempPoint.z } -- local _offsetFacPos = { x = _facPoint.x, y = _facPoint.y + 2.0, z = _facPoint.z } -- -- calc visible -- if land.isVisible(_offsetEnemyPos, _offsetFacPos) and _targeted == false and _targetedJTAC == false then -- if (string.match(_units[_y]:getName(), "hpriority") ~= nil) and fac.isVehicle(_units[_y]) then -- _vhpriority = true -- elseif (string.match(_units[_y]:getName(), "priority") ~= nil) and fac.isVehicle(_units[_y]) then -- _vpriority = true -- elseif (string.match(_units[_y]:getName(), "hpriority") ~= nil) and fac.isInfantry(_units[_y]) then -- _thpriority = true -- elseif (string.match(_units[_y]:getName(), "priority") ~= nil) and fac.isInfantry(_units[_y]) then -- _tpriority = true -- end -- end -- end -- end -- end -- end -- end -- for _i = 1, #_enemyGroups do -- if _enemyGroups[_i] ~= nil then -- _groupName = _enemyGroups[_i]:getName() -- _units = fac.getGroup(_groupName) -- if #_units > 0 then -- for _x = 1, #_units do -- --check to see if a FAC has already targeted this unit only if a distance -- --wasnt passed in -- local _targeted = false -- if not _distance then -- _targeted = fac.alreadyFacTarget(_facUnit, _units[_x]) -- end -- local _allowedTarget = true -- if _targetType == "vehicle" and _vhpriority == true then -- _allowedTarget = (string.match(_units[_x]:getName(), "hpriority") ~= nil) and fac.isVehicle(_units[_x]) -- elseif _targetType == "vehicle" and _vpriority == true then -- _allowedTarget = (string.match(_units[_x]:getName(), "priority") ~= nil) and fac.isVehicle(_units[_x]) -- elseif _targetType == "vehicle" then -- _allowedTarget = fac.isVehicle(_units[_x]) -- elseif _targetType == "troop" and _hpriority == true then -- _allowedTarget = (string.match(_units[_x]:getName(), "hpriority") ~= nil) and fac.isInfantry(_units[_x]) -- elseif _targetType == "troop" and _priority == true then -- _allowedTarget = (string.match(_units[_x]:getName(), "priority") ~= nil) and fac.isInfantry(_units[_x]) -- elseif _targetType == "troop" then -- _allowedTarget = fac.isInfantry(_units[_x]) -- elseif _vhpriority == true or _thpriority == true then -- _allowedTarget = (string.match(_units[_x]:getName(), "hpriority") ~= nil) -- elseif _vpriority == true or _tpriority == true then -- _allowedTarget = (string.match(_units[_x]:getName(), "priority") ~= nil) -- else -- _allowedTarget = true -- end -- if _units[_x]:isActive() == true and _targeted == false and _allowedTarget == true then -- -- calc distance -- _tempPoint = _units[_x]:getPoint() -- _tempDist = fac.getDistance(_tempPoint, _facPoint) -- if _tempDist < _maxDistance and _tempDist < _nearestDistance then -- local _offsetEnemyPos = { x = _tempPoint.x, y = _tempPoint.y + 2.0, z = _tempPoint.z } -- local _offsetFacPos = { x = _facPoint.x, y = _facPoint.y + 2.0, z = _facPoint.z } -- -- calc visible -- if land.isVisible(_offsetEnemyPos, _offsetFacPos) then -- _nearestDistance = _tempDist -- _nearestUnit = _units[_x] -- end -- end -- end -- end -- end -- end -- end if _nearestUnit == nil then return nil end return _nearestUnit end -- tests whether the unit is targeted by another FAC function fac.alreadyFacTarget(_facUnit, _enemyUnit) for _, _facTarget in pairs(fac.facCurrentTargets) do if _facTarget.unitId == _enemyUnit:getID() then -- env.info("FAC: ALREADY TARGET") return true end end return false end function fac.scanForTGToff(_args) --fac.facManTGT[_args[1]] = {} local _fac = Unit.getByName(_args[1]) local _side = _fac:getCoalition() fac.setFacOnStation({_args[1], nil}) --fac.cancelFacLase(_args[1]) --fac.notifyCoalition("Forward Air Controller \"" .. fac.getFacName(_args[1]) .. "\" off-station.", 10, _fac:getCoalition()) end function fac.scanForTGT (_args) --trigger.action.outText("scanning ",10) local _fac = Unit.getByName(_args[1]) local _side = _fac:getCoalition() local _facPos = _fac:getPoint() local _facGID = fac.getGroupId(_fac) local _i local _j local _offsetFacPos = { x = _facPos.x, y = _facPos.y + 2.0, z = _facPos.z } local dist2 = { id = world.VolumeType.SPHERE, params = { point = _fac:getPoint(), radius = fac.FAC_maxDistance --max range ARTY } } --fac.cancelFacLase(_args[1]) --fac.facCurrentTargets[_args[1]] = nil --trigger.action.outText("scanning ",10) fac.facManTGT[_args[1]] = {} local tempFound = {} local aaTempFound = {} local count = 0 local getTGT = function(foundItemM, val) -- generic search for all scenery --trigger.action.outText("scanning ",10) --local _checkArty = fac.isArty(foundItem) --local _tempTGTGroup = foundItem:getGroup() if _side ~= foundItemM:getCoalition() then -- check for friendly --if count <6 then --trigger.action.outText("scanning ",10) --trigger.action.outText("scanning "..foundItemM:getTypeName(),10) if foundItemM:inAir() == false and foundItemM:isActive() and foundItemM:getLife() > 1 then local _tempPoint= foundItemM:getPoint() local _offsetEnemyPos = { x = _tempPoint.x, y = _tempPoint.y + 2.0, z = _tempPoint.z } if land.isVisible(_offsetEnemyPos, _offsetFacPos) then --trigger.action.outText("scanning ",10) --trigger.action.outText("FOUND "..foundItemM:getTypeName(),10) if foundItemM:hasAttribute("SAM TR") or foundItemM:hasAttribute("IR Guided SAM") or foundItemM:hasAttribute("AA_flak") then table.insert(aaTempFound,foundItemM) else table.insert(tempFound,foundItemM) --count = count + 1 end end end --end --return end end world.searchObjects(Object.Category.UNIT,dist2,getTGT) for count = 1,10 do if #aaTempFound >= count then table.insert(fac.facManTGT[_args[1]],aaTempFound[count]) else table.insert(fac.facManTGT[_args[1]],tempFound[count]) end end local _tgtList = fac.facManTGT[_args[1]] local count = 0 for _i=1, #_tgtList do local tgtp = _tgtList[_i]:getPoint() local _TGTdist = math.sqrt(((tgtp.z-_facPos.z)^2)+((tgtp.x-_facPos.x)^2)) -- local _TGTheading = math.atan((tp.z-_facPos.z)/(tp.x-_facPos.x)) -- if _TGTheading > 0 then -- _TGTheading= _TGTheading + math.pi -- end -- _TGTheadDeg = _TGTheading*180/math.pi -- if _TGTheadDeg <0 then -- _TGTheadDeg = _TGTheadDeg +360 -- end --trigger.action.outText("FOUND "..foundItem:getTypeName(),10) local dy = tgtp.z-_facPos.z local dx = tgtp.x-_facPos.x count = count + 1 local _TGTheading = math.atan(dy/dx) --correcting for coordinate space local recceMarkID = timer.getTime()*1000 + count if dy < 0 then -- dy = -1 90-270 if dx < 0 then --dy/dx = 1 180-270 --trigger.action.outText(_artyInRange:getName().." Firing SW:\n".. (_fireheading/math.pi)*180 .."\n", 300) _TGTheading= _TGTheading + math.pi else --trigger.action.outText(_artyInRange:getName().." Firing SE:\n".. (_fireheading/math.pi)*180 .."\n", 300) _TGTheading= _TGTheading + math.pi end else --dy = 1 270-90 if dx < 0 then --dy/dx = -1 270-0 --trigger.action.outText(_artyInRange:getName().." Firing NW:\n".. (_fireheading/math.pi)*180 .."\n", 300) _TGTheading= _TGTheading + 2*math.pi else --dy/dx = 1 0-90 --trigger.action.outText(_artyInRange:getName().." Firing NE:\n".. (_fireheading/math.pi)*180 .."\n", 300) _TGTheading= _TGTheading end end local _TGTheadDeg =(_TGTheading)/math.pi*180 --math.floor(_TGTdist) .."m/" .. math.floor(_TGTdist*3.28084) .."ft" trigger.action.outTextForGroup(_facGID,"Target ".._i .. ":" .. _tgtList[_i]:getTypeName() .. " Bearing:" ..math.floor(_TGTheadDeg) .. " Range:"..math.floor(_TGTdist) .."m/" .. math.floor(_TGTdist*3.28084) .."ft",30) trigger.action.markToGroup(recceMarkID,"Target ".._i ..":".. _tgtList[_i]:getTypeName(), _tgtList[_i]:getPoint(),_facGID,false,"") timer.scheduleFunction(removeSetMark,{recceMarkID},timer.getTime() + 60) end end function fac.scanForTGTai (_args) --trigger.action.outText("scanning 1" .. _args[1] ,10) local _fac = Unit.getByName(_args[1]) local _tgtList = {} if _fac ~= nil then local _side = _fac:getCoalition() local _facPos = _fac:getPoint() --local _facGID = fac.getGroupId(_fac) local _i local _j local _offsetFacPos = { x = _facPos.x, y = _facPos.y + 2.0, z = _facPos.z } local dist2 = { id = world.VolumeType.SPHERE, params = { point = _fac:getPoint(), radius = fac.FAC_maxDistance/10 * 5 + _facPos.y --max range ARTY } } --fac.cancelFacLase(_args[1]) --fac.facCurrentTargets[_args[1]] = nil --trigger.action.outText("scanning 2",10) local tempFound = {} local aaTempFound = {} local count = 0 local getTGT = function(foundItemM, val) -- generic search for all scenery --trigger.action.outText("scanning ",10) --local _checkArty = fac.isArty(foundItem) --local _tempTGTGroup = foundItem:getGroup() if _side ~= foundItemM:getCoalition() then -- check for friendly --if count <6 then --trigger.action.outText("scanning ",10) --trigger.action.outText("scanning "..foundItemM:getTypeName(),10) if foundItemM:inAir() == false and foundItemM:isActive() and foundItemM:getLife() > 1 then local _tempPoint= foundItemM:getPoint() local _offsetEnemyPos = { x = _tempPoint.x, y = _tempPoint.y + 2.0, z = _tempPoint.z } if land.isVisible(_offsetEnemyPos, _offsetFacPos) then --trigger.action.outText("scanning ",10) --trigger.action.outText("FOUND "..foundItemM:getTypeName(),10) local _vel = foundItemM:getVelocity() local _spd if _vel ~=nil then _spd = math.sqrt(_vel.x^2+_vel.z^2) end if _spd == 0 then if foundItemM:hasAttribute("SAM TR") or foundItemM:hasAttribute("IR Guided SAM") or foundItemM:hasAttribute("AA_flak") then table.insert(aaTempFound,foundItemM) else table.insert(tempFound,foundItemM) --count = count + 1 end end end end --end --return end end world.searchObjects(Object.Category.UNIT,dist2,getTGT) for count = 1,10 do if #aaTempFound >= count then table.insert(_tgtList,aaTempFound[count]) else table.insert(_tgtList,tempFound[count]) end end --local _tgtList = fac.facManTGT[_args[1]] end return _tgtList end function fac.setManualTgt(_args) fac.cancelFacLase(_args[1]) local _fac = Unit.getByName(_args[1]) local _facGID = fac.getGroupId(_fac) fac.notifyCoalition("[Forward Air Controller \"" .. fac.getFacName(_args[1]) .. "\" starting manual laze. Reseting to new target]", 10, _fac:getCoalition()) --fac.facCurrentTargets[_args[1]] = nil fac.setFacOnStation({_args[1],true}) --fac.cancelFacLase(_args[1]) --fac.facCurrentTargets[_facUnitName] --fac.facCurrentTargets[_args[1]] = nil --fac.facUnits[_facUnitName] = nil local _tgtList = fac.facManTGT[_args[1]] if _tgtList == nil then trigger.action.outTextForGroup(_facGID,"Error loading tgts, please reset FAC",10) return end local _enemyUnit = _tgtList[_args[2]] fac.facCurrentTargets[_args[1]] = { name = _enemyUnit:getName(), unitType = _enemyUnit:getTypeName(), unitId = _enemyUnit:getID() } local _lock = "all" if _fac:getCoalition() == 1 then local _colour = fac.FAC_smokeColour_RED local _smoke = fac.FAC_smokeOn_RED else local _colour = fac.FAC_smokeColour_BLUE local _smoke = fac.FAC_smokeOn_BLUE end if fac.markerTypeColor[_args[1]] ~= nil then _colour = fac.markerTypeColor[_args[1]] end local _laserCode = fac.facLaserPointCodes[_args[1]] if _laserCode == nil then fac.setFacLaserCode({_args[1], fac.FAC_laser_codes[1]}) _laserCode = fac.facLaserPointCodes[_args[1]]+1 end --local _facGroup = trigger.action.outTextForGroup(_facGID,"Designating Target ".._args[2]..": ".._tgtList[_args[2]]:getTypeName(),10) if _args[2] > #_tgtList then trigger.action.outTextForGroup(_facGID,"Invalid Target",10) elseif _tgtList[_args[2]]:getLife() > 0 then fac.notifyCoalition("[Forward Air Controller \"" .. fac.getFacName(_args[1]) .. "\" starting manual laze.]", 10, _fac:getCoalition()) fac.facAutoLase(_args[1], _laserCode, _smoke, _lock, _colour) fac.createSmokeMarker(_tgtList[_args[2]], _colour,_args[1]) --fac.facLaseUnit(_tgtList[_args[2]], _fac, _args[1], _laserCode) -- --fac.notifyCoalition(fac.getFacName(_args[1]) .. " lasing new target " .. _tgtList[_args[2]]:getTypeName() .. '. CODE: ' .. _laserCode .. fac.getFacPositionString(_tgtList[_args[2]]), 10, _fac:getCoalition()) -- --trigger.action.outTextForGroup(_facGID,"Designated Target ".._args[2].. " " .. _tgtList[_args[2]]:getTypeName().." for attack",10) -- if _smoke == true then -- local _nextSmokeTime = fac.facSmokeMarks[_tgtList[_args[2]]:getName()] -- --recreate smoke marker after 5 mins -- if _nextSmokeTime ~= nil and _nextSmokeTime < timer.getTime() then -- fac.createSmokeMarker(_tgtList[_args[2]], _colour,_args[1]) -- end -- end trigger.action.outTextForGroup(_facGID,"Designated Target ".._args[2].. " " .. _tgtList[_args[2]]:getTypeName().." for attack",10) elseif _tgtList[_args[2]]:getLife() < 1 then trigger.action.outTextForGroup(_facGID,"Designated Target ".._args[2].. " " .. _tgtList[_args[2]]:getTypeName().." is already dead",10) end end -- Adds menuitem to all FAC units that are active function fac.addFacF10MenuOptions() -- Loop through all FAC units timer.scheduleFunction(fac.addFacF10MenuOptions, nil, timer.getTime() + 10) for _, _facUnitName in pairs(fac.facPilotNames) do local status, error = pcall(function() local _unit = fac.getFacUnit(_facUnitName) if _unit ~= nil then local _groupId = fac.getGroupId(_unit) if _groupId then if fac.facAddedTo[tostring(_groupId)] == nil then local _rootPath = missionCommands.addSubMenuForGroup(_groupId, "FAC") local _TGTModePath = missionCommands.addSubMenuForGroup(_groupId, "Targeting Mode",_rootPath) local _AutoTGTModePath = missionCommands.addSubMenuForGroup(_groupId, "Auto Mode",_TGTModePath) local _ManTGTModePath = missionCommands.addSubMenuForGroup(_groupId, "Manual Mode",_TGTModePath) missionCommands.addCommandForGroup(_groupId, "Auto Laze On", _AutoTGTModePath, fac.setFacOnStation, { _facUnitName, true}) missionCommands.addCommandForGroup(_groupId, "Auto Laze Off", _AutoTGTModePath, fac.setFacOnStation, { _facUnitName, nil}) missionCommands.addCommandForGroup(_groupId, "Scan for Close Targets", _ManTGTModePath, fac.scanForTGT, { _facUnitName}) missionCommands.addCommandForGroup(_groupId, "Stop Manual Designating", _ManTGTModePath, fac.scanForTGToff, { _facUnitName}) local _TGTSelectPath = missionCommands.addSubMenuForGroup(_groupId, "Select Found Target",_ManTGTModePath) missionCommands.addCommandForGroup(_groupId, "Target 1", _TGTSelectPath, fac.setManualTgt, { _facUnitName, 1}) missionCommands.addCommandForGroup(_groupId, "Target 2", _TGTSelectPath, fac.setManualTgt, { _facUnitName, 2}) missionCommands.addCommandForGroup(_groupId, "Target 3", _TGTSelectPath, fac.setManualTgt, { _facUnitName, 3}) missionCommands.addCommandForGroup(_groupId, "Target 4", _TGTSelectPath, fac.setManualTgt, { _facUnitName, 4}) missionCommands.addCommandForGroup(_groupId, "Target 5", _TGTSelectPath, fac.setManualTgt, { _facUnitName, 5}) missionCommands.addCommandForGroup(_groupId, "Target 6", _TGTSelectPath, fac.setManualTgt, { _facUnitName, 6}) missionCommands.addCommandForGroup(_groupId, "Target 7", _TGTSelectPath, fac.setManualTgt, { _facUnitName, 7}) missionCommands.addCommandForGroup(_groupId, "Target 8", _TGTSelectPath, fac.setManualTgt, { _facUnitName, 8}) missionCommands.addCommandForGroup(_groupId, "Target 9", _TGTSelectPath, fac.setManualTgt, { _facUnitName, 9}) missionCommands.addCommandForGroup(_groupId, "Target 10", _TGTSelectPath, fac.setManualTgt, { _facUnitName, 10}) missionCommands.addCommandForGroup(_groupId, "Call artillery strikes on all manual targets", _ManTGTModePath, fac.multiStrike, { _facUnitName}) -- add each possible laser code as a menu option local _lzrpath = missionCommands.addSubMenuForGroup(_groupId, "Avaliable Laser Codes",_rootPath) for _, _laserCode in pairs(fac.FAC_laser_codes) do missionCommands.addCommandForGroup(_groupId, string.format("Laser code: %s", _laserCode), _lzrpath, fac.setFacLaserCode, { _facUnitName, _laserCode}) end local _lzerCustPath = missionCommands.addSubMenuForGroup(_groupId, "Custom Laser Code", _lzrpath) local _digCount local _lzerCode1Path = missionCommands.addSubMenuForGroup(_groupId, "Digit 1", _lzerCustPath) for _digCount = 1 ,1 do missionCommands.addCommandForGroup(_groupId, _digCount, _lzerCode1Path, fac.setCustCode, { _facUnitName, 1,_digCount}) end local _lzerCode2Path = missionCommands.addSubMenuForGroup(_groupId, "Digit 2", _lzerCustPath) for _digCount = 1 ,6 do missionCommands.addCommandForGroup(_groupId, _digCount, _lzerCode2Path, fac.setCustCode, { _facUnitName, 2,_digCount}) end local _lzerCode3Path = missionCommands.addSubMenuForGroup(_groupId, "Digit 3", _lzerCustPath) for _digCount = 1 ,8 do missionCommands.addCommandForGroup(_groupId, _digCount, _lzerCode3Path, fac.setCustCode, { _facUnitName, 3,_digCount}) end local _lzerCode4Path = missionCommands.addSubMenuForGroup(_groupId, "Digit 4", _lzerCustPath) for _digCount = 1 ,8 do missionCommands.addCommandForGroup(_groupId, _digCount, _lzerCode4Path, fac.setCustCode, { _facUnitName, 4,_digCount}) end local _artyPath = missionCommands.addSubMenuForGroup(_groupId, "Artillery Control",_rootPath) missionCommands.addCommandForGroup(_groupId, "Check Avaliable Arty Groups", _artyPath , fac.checkTask, {_facUnitName}) missionCommands.addCommandForGroup(_groupId, "Call Artillery Fire Mission", _artyPath , fac.callFireMission, { _facUnitName,fac.fireMissionRounds,0}) missionCommands.addCommandForGroup(_groupId, "Call Illummination", _artyPath , fac.callFireMission, { _facUnitName,fac.fireMissionRounds,1}) missionCommands.addCommandForGroup(_groupId, "Call Mortar Strike Only(Anti-infantry)", _artyPath , fac.callFireMission, { _facUnitName,fac.fireMissionRounds,2}) missionCommands.addCommandForGroup(_groupId, "Call Heavy Artillery Strike Only (Anti-Material)", _artyPath , fac.callFireMission, { _facUnitName,10,3}) local _cMissilePath = missionCommands.addSubMenuForGroup(_groupId, "Air/Naval THAWK Strike Menu",_artyPath) missionCommands.addCommandForGroup(_groupId, "Single Target", _cMissilePath , fac.callFireMission, { _facUnitName,1,4}) missionCommands.addCommandForGroup(_groupId, "Multi Target (Manual Targeting Required), GPS weapons only", _cMissilePath , fac.callFireMissionMulti, { _facUnitName,1,4}) --missionCommands.addCommandForGroup(_groupId, "Carpet Bomb (Define on F10 Map with syntax: AttackAz CBRQT), Dumb bombs only", _cMissilePath , world.addEventHandler, CrptBmbDesig) missionCommands.addCommandForGroup(_groupId, "Carpet Bomb (Turn your aircraft to desired attack azimuth), Dumb bombs only", _cMissilePath , fac.callFireMissionCarpet2, { _facUnitName,1,5}) local _mkrpath = missionCommands.addSubMenuForGroup(_groupId, "Marker Type",_rootPath) local _colorSmokePath = missionCommands.addSubMenuForGroup(_groupId, "Smoke",_mkrpath) missionCommands.addCommandForGroup(_groupId, "GREEN", _colorSmokePath, fac.setMarkerColor, { _facUnitName, "SMOKE",0}) missionCommands.addCommandForGroup(_groupId, "RED", _colorSmokePath , fac.setMarkerColor, { _facUnitName, "SMOKE",1}) missionCommands.addCommandForGroup(_groupId, "ORANGE", _colorSmokePath , fac.setMarkerColor, { _facUnitName, "SMOKE",3}) missionCommands.addCommandForGroup(_groupId, "BLUE", _colorSmokePath , fac.setMarkerColor, { _facUnitName, "SMOKE",4}) missionCommands.addCommandForGroup(_groupId, "WHITE", _colorSmokePath , fac.setMarkerColor, { _facUnitName, "SMOKE",2}) local _colorFlarePath = missionCommands.addSubMenuForGroup(_groupId, "FLARES",_mkrpath) missionCommands.addCommandForGroup(_groupId, "GREEN", _colorFlarePath, fac.setMarkerColor, { _facUnitName, "FLARES",0}) missionCommands.addCommandForGroup(_groupId, "WHITE", _colorFlarePath , fac.setMarkerColor, { _facUnitName, "FLARES",2}) missionCommands.addCommandForGroup(_groupId, "ORANGE", _colorFlarePath , fac.setMarkerColor, { _facUnitName, "FLARES",3}) --missionCommands.addCommandForGroup(_groupId, "Smoke", _mkrpath, fac.setMarkerType, { _facUnitName, "SMOKE"}) --missionCommands.addCommandForGroup(_groupId, "FLARES", _mkrpath , fac.setMarkerType, { _facUnitName, "FLARES"}) missionCommands.addCommandForGroup(_groupId, "Map Marker", _mkrpath , fac.setMapMarker, { _facUnitName}) --missionCommands.addCommandForGroup(_groupId, "RECCE", _mkrpath , fac.recceDetect, { _facUnitName}) fac.facAddedTo[tostring(_groupId)] = true end end --[[else env.info(string.format("FAC DEBUG: unit nil %s",_facUnitName)) ]] end end) end for _, _facUnitName in pairs(fac.reccePilotNames) do local status, error = pcall(function() local _unitR = fac.getFacUnit(_facUnitName) if _unitR ~= nil then local _groupIdR = fac.getGroupId(_unitR) if _groupIdR then if fac.RECCEAddedTo[tostring(_groupIdR)] == nil then local _rootPathR = missionCommands.addSubMenuForGroup(_groupIdR, "RECCE") missionCommands.addCommandForGroup(_groupIdR, "RECCE", _rootPathR, fac.recceDetect, { _facUnitName}) missionCommands.addCommandForGroup(_groupIdR, "Strategic Strike", _rootPathR, fac.stratStrike, { _facUnitName}) --missionCommands.addCommandForGroup(_groupId, "Go Off-Station", _rootPathR, fac.recceDetect, { _facUnitName, nil}) fac.RECCEAddedTo[tostring(_groupIdR)] = true end end --[[else env.info(string.format("FAC DEBUG: unit nil %s",_facUnitName)) ]] end end) if (not status) then env.error(string.format("Error adding f10 to RECCE: %s", error), false) end end local status, error = pcall(function() -- now do any player controlled aircraft that ARENT FAC units if fac.FAC_FACStatusF10 then -- get all BLUE players fac.addFacRadioCommand(2) -- get all RED players fac.addFacRadioCommand(1) end end) if (not status) then env.error(string.format("Error adding f10 to other players: %s", error), false) end end function fac.setMapMarker(_args) local _facUnitName = _args[1] local _unit = nil local _facUnit = fac.getFacUnit(_facUnitName) local _groupId = fac.getGroupId(_facUnit) local tgtMarkID = timer.getTime()*1000 local recceMarkID = timer.getTime()*1000 trigger.action.outTextForGroup(_groupId,"Processing Mark",10) if fac.facCurrentTargets[_facUnitName] ~= nil then _unit = Unit.getByName(fac.facCurrentTargets[_facUnitName].name) tempMarkID = tgtMarkID --fac.markID = tgtMarkID + 1 elseif _args[2] ~= nil then _unit = _args[2] tempMarkID = recceMarkID --fac.recceID = recceMarkID + 1 else trigger.action.outTextForGroup(_groupId,"No Target to Mark",10) end if _unit ~=nil and _unit:isActive() then local _vel = _unit:getVelocity() local _spd = 0 if _vel ~=nil then _spd = math.sqrt(_vel.x^2+_vel.z^2) end local unitPos = _unit:getPoint() local _lat, _lon = coord.LOtoLL(_unit:getPosition().p) local _latLngStr = mist.tostringLL(_lat, _lon, 3, false) local _latLngSecStr = mist.tostringLL(_lat, _lon, 3, true) local _mgrsString = mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(_unit:getPosition().p)), 5) trigger.action.markToCoalition(tgtMarkID,_unit:getTypeName().. " - DMS: " .. _latLngSecStr .." Altitude: ".. math.floor(unitPos.y) .."m/" .. math.floor(unitPos.y*3.28084) .."ft".. "\nHeading: ".. math.floor(getHeading(_unit) * 180/math.pi) .. "\nSpeed: " .. math.floor(_spd*2) .. " MPH" .."\nSpotted by: " .. fac.getFacName(_facUnitName), _unit:getPoint(), _facUnit:getCoalition(),false,fac.getFacName(_facUnitName).." marked a target") timer.scheduleFunction(removeSetMark,{tgtMarkID},timer.getTime() + 300) end end function fac.setMarkerColor(_args) local _facUnitName = _args[1] local _mkrType = _args[2] fac.cancelFacLase(_facUnitName) fac.setFacOnStation({_args[1],nil}) fac.markerType[_facUnitName] = _mkrType fac.markerTypeColor[_facUnitName] = _args[3] fac.setMarkerType(_args) fac.setFacOnStation({_args[1],true}) end function fac.setMarkerType(_args) local _facUnitName = _args[1] local _mkrType = _args[2] local _facUnit = fac.getFacUnit(_facUnitName) local _groupId = fac.getGroupId(_facUnit) local colorString = { ["0"] = "GREEN" ,["1"] = "RED" ,["2"] = "WHITE", ["3"] = "ORANGE" ,["4"] = "BLUE"} local _mkrColor local _facUnit = Unit.getByName(_facUnitName) local side = _facUnit:getCoalition() if side == 1 then _mkrColor = fac.FAC_smokeColour_BLUE elseif side == 2 then _mkrColor = fac.FAC_smokeColour_RED else _mkrColor = 2 end if _args[3]~=nil then _mkrColor = _args[3] end if _facUnit == nil then --env.info('FAC DEBUG: fac.setFacLaserCode() _facUnit is null, aborting.') return end fac.markerTypeColor[_facUnitName] = _args[3] fac.markerType[_facUnitName] = _mkrType if fac.facOnStation[_facUnitName] == true then fac.notifyCoalition("[Forward Air Controller \"" .. fac.getFacName(_facUnitName) .. "\" on-station marking with: "..colorString[tostring(_mkrColor)].." "..fac.markerType[_facUnitName]..".]", 10, _facUnit:getCoalition()) else trigger.action.outTextForGroup(_groupId,"Marker set to ".. colorString[tostring(_mkrColor)].." "..fac.markerType[_facUnitName],10) end --fac.setFacOnStation({ _facUnitName, nil}) --fac.setFacOnStation( {_facUnitName, true}) end function fac.addFacRadioCommand(_side) local _players = coalition.getPlayers(_side) if _players ~= nil then for _, _playerUnit in pairs(_players) do local _groupId = fac.getGroupId(_playerUnit) if _groupId then -- env.info("adding command for "..index) if fac.facRadioAdded[tostring(_groupId)] == nil then -- env.info("about command for "..index) missionCommands.addCommandForGroup(_groupId, "FAC Status", nil, fac.getFacStatus, { _playerUnit:getName() }) local _airstrikeMenu = missionCommands.addSubMenuForGroup(_groupId, "Air OPS Menu") missionCommands.addCommandForGroup(_groupId, "Map Attack (Define on F10 Map with syntax: AttackAz CBRQT or TDRQT), CB for Carpet/TD for TALD", _airstrikeMenu , fac.carpetMapDesignate, {nil}) missionCommands.addCommandForGroup(_groupId, "RECCE FLT (Define on F10 Map with syntax: RECCE)", _airstrikeMenu , fac.RECCEDesignate, {nil}) --missionCommands.addCommandForGroup(_groupId, "TALD Strike (Define on F10 Map with syntax: AttackAz TDRQT)", _airstrikeMenu , fac.carpetMapDesignate, {nil}) --local _cMissilePath = missionCommands.addSubMenuForGroup(_groupId, "Air Strike Menu",_airstrikeMenu) fac.facRadioAdded[tostring(_groupId)] = true -- env.info("Added command for " .. index) end end end end end function fac.setFacLaserCode(_args) local _facUnitName = _args[1] local _laserCode = _args[2] local _facUnit = fac.getFacUnit(_facUnitName) --fac.setFacOnStation( {_facUnitName, nil}) --fac.setFacOnStation( {_facUnitName, true}) if _facUnit == nil then --env.info('FAC DEBUG: fac.setFacLaserCode() _facUnit is null, aborting.') return end fac.facLaserPointCodes[_facUnitName] = _laserCode if fac.facOnStation[_facUnitName] == true then fac.notifyCoalition("[Forward Air Controller \"" .. fac.getFacName(_facUnitName) .. "\" on-station using CODE: "..fac.facLaserPointCodes[_facUnitName]..".]", 10, _facUnit:getCoalition()) end end function fac.setCustCode(_args) local _facUnitName = _args[1] local _facUnit = fac.getFacUnit(_facUnitName) if fac.facLaserPointCodes[_facUnitName] == nil then fac.facLaserPointCodes[_facUnitName] = "1688" end local tempCode = fac.facLaserPointCodes[_facUnitName] tempCode = fac.replace_char(_args[2],tempCode,_args[3]) fac.facLaserPointCodes[_facUnitName] = tempCode fac.notifyCoalition("[Forward Air Controller \"" .. fac.getFacName(_facUnitName) .. "\" on-station using CODE: "..fac.facLaserPointCodes[_facUnitName]..".]", 10, _facUnit:getCoalition()) end function fac.replace_char(pos, str, r) return str:sub(1, pos-1) .. r .. str:sub(pos+1) end function fac.setFacOnStation(_args) local _facUnitName = _args[1] local _onStation = _args[2] local _facUnit = fac.getFacUnit(_facUnitName) local colorString = { ["0"] = "GREEN" ,["1"] = "RED" ,["2"] = "WHITE", ["3"] = "ORANGE" ,["4"] = "BLUE"} local _mkrColor = tostring(fac.markerTypeColor[_facUnitName]) -- going on-station if _facUnit == nil then --env.info('FAC DEBUG: fac.setFacOnStation() _facUnit is null, aborting.') return end if fac.facLaserPointCodes[_facUnitName] == nil then -- set default laser code --env.info('FAC: ' .. _facUnitName .. ' no laser code, assigning default ' .. fac.FAC_laser_codes[1]) fac.setFacLaserCode( {_facUnitName, fac.FAC_laser_codes[1]} ) end -- going on-station from off-station if fac.facOnStation[_facUnitName] == nil and _onStation == true then env.info('FAC: ' .. _facUnitName .. ' going on-station') fac.cancelFacLase(_facUnitName) --fac.scanForTGToff({_facUnitName}) fac.notifyCoalition("[Forward Air Controller \"" .. fac.getFacName(_facUnitName) .. "\" on-station using CODE: "..fac.facLaserPointCodes[_facUnitName]..".]", 10, _facUnit:getCoalition()) fac.setFacLaserCode( {_facUnitName, fac.facLaserPointCodes[_facUnitName]} ) end -- going off-station from on-station if fac.facOnStation[_facUnitName] == true and _onStation == nil then env.info('FAC: ' .. _facUnitName .. ' going off-station') fac.notifyCoalition("[Forward Air Controller \"" .. fac.getFacName(_facUnitName) .. "\" off-station.]", 10, _facUnit:getCoalition()) fac.cancelFacLase(_facUnitName) fac.facUnits[_facUnitName] = nil --fac.scanForTGToff({_facUnitName}) end fac.facOnStation[_facUnitName] = _onStation end --get distance in meters assuming a Flat world function fac.getDistance(_point1, _point2) local xUnit = _point1.x local yUnit = _point1.z local xZone = _point2.x local yZone = _point2.z local xDiff = xUnit - xZone local yDiff = yUnit - yZone return math.sqrt(xDiff * xDiff + yDiff * yDiff) end function fac.notifyCoalition(_message, _displayFor, _side) trigger.action.outTextForCoalition(_side, _message, _displayFor) trigger.action.outSoundForCoalition(_side, "radiobeep.ogg") end -- Returns only alive units from group but the group / unit may not be active function fac.getGroup(groupName) local _groupUnits = Group.getByName(groupName) local _filteredUnits = {} --contains alive units local _x = 1 if _groupUnits ~= nil and _groupUnits:isExist() then _groupUnits = _groupUnits:getUnits() if _groupUnits ~= nil and #_groupUnits > 0 then for _x = 1, #_groupUnits do if _groupUnits[_x]:getLife() > 0 then -- removed and _groupUnits[_x]:isExist() as isExist doesnt work on single units! table.insert(_filteredUnits, _groupUnits[_x]) end end end end return _filteredUnits end function fac.isInfantry(_unit) local _typeName = _unit:getTypeName() --type coerce tostring _typeName = string.lower(_typeName .. "") local _soldierType = { "infantry", "paratrooper", "stinger", "manpad", "mortar" } for _key, _value in pairs(_soldierType) do if string.match(_typeName, _value) then return true end end return false end function fac.isArty(_Aunit) local _typeName = _Aunit:getTypeName() -- --type coerce tostring -- _typeName = string.lower(_typeName .. "") --trigger.action.outText( _typeName.." found",10) -- local _artyType = { "mrls", "sph", "mortar" } -- for _key, _value in pairs(_artyType) do -- if string.match(_typeName, _value) then -- return true -- end -- end --trigger.action.outText( _typeName.." found",10) if _Aunit:hasAttribute('Artillery') or _Aunit:hasAttribute('Strategic bombers') or _Aunit:hasAttribute('Cruisers') or _Aunit:hasAttribute('Frigates') or _Aunit:hasAttribute('Corvettes') or _Aunit:hasAttribute('Landing Ships') then --or _Aunit:hasAttribute('MLRS') or _Aunit:hasAttribute('Bombers') or _Aunit:hasAttribute('Multirole fighters') then if _typeName == "Silkworm_SR" or _typeName == "hy_launcher" then -- or _Aunit:hasAttribute('MLRS') then return false else --trigger.action.outText( _typeName.." found",10) return true end else return false end end function fac.isBomber(_Aunit) local _typeName = _Aunit:getTypeName() -- --type coerce tostring -- _typeName = string.lower(_typeName .. "") --trigger.action.outText( _typeName.." found",10) -- local _artyType = { "mrls", "sph", "mortar" } -- for _key, _value in pairs(_artyType) do -- if string.match(_typeName, _value) then -- return true -- end -- end if _Aunit:hasAttribute('Strategic bombers') or _Aunit:hasAttribute('Bombers') or _Aunit:hasAttribute('Multirole fighters') then return true else return false end end -- assume anything that isnt soldier is vehicle function fac.isVehicle(_unit) if fac.isInfantry(_unit) then return false end return true end -- copied from CTLD function fac.getGroupId(_unit) local _unitDB = mist.DBs.unitsById[tonumber(_unit:getID())] local _gID = _unit:getGroup():getID() if _unitDB ~= nil and _unitDB.groupId then return _unitDB.groupId elseif _gID ~= nil then return _gID end return nil end function fac.createSmokeMarker(_enemyUnit, _colour,_facUnitName) --recreate in 5 mins if fac.markerType[_facUnitName] == "SMOKE" then fac.facSmokeMarks[_enemyUnit:getName()] = timer.getTime() + 300.0 else fac.facSmokeMarks[_enemyUnit:getName()] = timer.getTime() + 2 end -- move smoke 2 meters above target for ease local _enemyPoint = _enemyUnit:getPoint() if fac.markerType[_facUnitName] == "SMOKE" then trigger.action.smoke({ x = _enemyPoint.x, y = _enemyPoint.y + 2.0, z = _enemyPoint.z }, _colour) else trigger.action.signalFlare({ x = _enemyPoint.x, y = _enemyPoint.y + 2.0, z = _enemyPoint.z }, _colour,0) end end --fire mission control -- function fac.checkArty(_side, _artyTable) -- --trigger.action.outText( "Found " ..#_artyTable.." arty units".._side,10) -- local _artyIDX = 1 -- local _artyGroups = coalition.getGroups(_side, Group.Category.GROUND) -- if #_artyGroups == 0 then -- trigger.action.outText( "ERROR no Units",10) -- --_artyGroups = coalition.getGroups(_side, Group.Category.GROUND) -- elseif _artyGroups[1] == nil then -- trigger.action.outText( "ERROR ground returned Nil",10) -- end -- for _artyIDX = 1, #_artyGroups do -- local _artyunits = _artyGroups[_artyIDX]:getUnits() -- if _artyunits[1] ~= nil then -- if fac.isArty(_artyunits[1]) == true then -- if contains(_artyTable,_artyGroups[_artyIDX]:getName()) == false then -- table.insert(_artyTable,_artyGroups[_artyIDX]:getName()) -- --trigger.action.outText( "Found " ..#_artyTable.." arty units out of" ..#_artyGroups ,10) -- end -- end -- end -- end -- end function getHeading(unit) local unitpos = unit:getPosition() if unitpos then local Heading = math.atan2(unitpos.x.z, unitpos.x.x) Heading = Heading + getNorthCorrection(unitpos.p) if Heading < 0 then Heading = Heading + 2*math.pi -- put heading in range of 0 to 2*pi end return Heading end end getNorthCorrection = function(point) --gets the correction needed for true north if not point.z then --Vec2; convert to Vec3 point.z = point.y point.y = 0 end local lat, lon = coord.LOtoLL(point) local north_posit = coord.LLtoLO(lat + 1, lon) return math.atan2(north_posit.z - point.z, north_posit.x - point.x) end function fac.facOffsetMaker(_fac) local _facOffset = {} local angle = getHeading(_fac) local xofs = math.cos(angle) * fac.facOffsetDist local yofs = math.sin(angle) * fac.facOffsetDist local _facPoint = _fac:getPoint() _facOffset.x = _facPoint.x + xofs _facOffset.y = _facPoint.y _facOffset.z = _facPoint.z +yofs return _facOffset end function fac.getBomber(_mapPt,_col,_artyType) local _attackPoint = _mapPt local _i = 1 local _j = 1 local _k = 1 --local _gndGroups = {} local _tempPoint = nil local _tempDist = nil local _tempPosition = nil local _lastArty = {ammo = 0, group = {}} local _chosenArty = nil local _tempArty = {} local _tempList = {} local _artyGroups = {} local side = _col local lastAmmo = 0 local tempFound = {} local _foundArty = {} local dist = { id = world.VolumeType.SPHERE, params = { point = _attackPoint, radius = 4600000 --max range ARTY } } local getArty = function(foundItem, val) -- generic search for all scenery local _checkArty = fac.isBomber(foundItem) local _tempArtyGroup = foundItem:getGroup() local _tGC = _tempArtyGroup:getController() if side == foundItem:getCoalition() and foundItem:getPlayerName() == nil then -- check for friendly and not a player if contains(tempFound,_tempArtyGroup:getName()) == false then --check for redundant groups if _checkArty == true then --trigger.action.outText(foundItem:getTypeName(),10) --if _tGC:hasTask() == false then -- check for tasked arty --if contains(fac.ArtyTasked,_tempArtyGroup:getName()) == false then -- check for tasked arty if fac.ArtyTasked[_tempArtyGroup:getName()] == nil then fac.ArtyTasked[_tempArtyGroup:getName()] = { name = _tempArtyGroup:getName(), tasked = 0, timeTasked = nil,tgt = nil} end --trigger.action.outText(_tempArtyGroup:getName() .. " " .. fac.ArtyTasked[_tempArtyGroup:getName()].tasked,10) if fac.ArtyTasked[_tempArtyGroup:getName()].tasked == 0 then _tempPoint = foundItem:getPoint() _tempDist = fac.getDistance(_tempPoint, _attackPoint) --foundItem --trigger.action.outText(_tempArtyGroup:getName() .. " " .. fac.ArtyTasked[_tempArtyGroup:getName()].tasked,10) local _type = Unit.getTypeName(foundItem) if fac.artyGetAmmo(_tempArtyGroup:getUnits()) > 0 and foundItem:isActive() == true then --trigger.action.outText(_tempDist.. " "..fac.ArtilleryProperties[_type].minrange .. " " .. fac.ArtilleryProperties[_type].maxrange,10) if foundItem:hasAttribute('Strategic bombers') or foundItem:hasAttribute('Bombers') or foundItem:hasAttribute('Multirole fighters') then --trigger.action.outText(foundItem:getTypeName().." "..fac.artyGetAmmo(_tempArtyGroup:getUnits()),10) table.insert(tempFound,_tempArtyGroup:getName()) end end end elseif foundItem:getTypeName() == "USS_Arleigh_Burke_IIa" or foundItem:getTypeName() == "TICONDEROG" and _artyType == 4 then table.insert(tempFound,_tempArtyGroup:getName()) end end end end world.searchObjects(Object.Category.UNIT,dist,getArty) if _artyType == 5 then for _i = 1, #tempFound do if Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Strategic bombers') or Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Bombers') then --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .." ".._artyFilter,10) local payloadCheck = Group.getByName(tempFound[_i]):getUnit(1):getAmmo() if payloadCheck ~= nil then if payloadCheck[1].desc.guidance == 1 then --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " " .. payloadCheck[1].desc.guidance,10) else --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " unguided bombs",10) table.insert(_foundArty,tempFound[_i]) end end end end elseif _artyType == 4 then for _i = 1, #tempFound do --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .." ".._artyFilter,10) if Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Strategic bombers') or Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Bombers') or Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Multirole fighters') then local payloadCheck = Group.getByName(tempFound[_i]):getUnit(1):getAmmo() if payloadCheck ~= nil then if payloadCheck[1].desc.guidance == 1 then table.insert(_foundArty,tempFound[_i]) --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " " .. payloadCheck[1].desc.guidance,10) else --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " unguided bombs",10) end end elseif Unit.getByName(tempFound[_i]):getTypeName() == "USS_Arleigh_Burke_IIa" or Unit.getByName(tempFound[_i]):getTypeName() == "TICONDEROG" then --trigger.action.outText( Unit.getByName(tempFound[_i]):getTypeName() .." Found",10) if fac.artyGetGuidedAmmo(Group.getByName(tempFound[_i]):getUnits()) > 0 then table.insert(_foundArty,tempFound[_i]) end end end elseif _artyType == 3 then for _i = 1, #tempFound do --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .." ".._artyFilter,10) if Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Multirole fighters') then local payloadCheck = Group.getByName(tempFound[_i]):getUnit(1):getAmmo() if payloadCheck ~= nil then for _k = 1,#payloadCheck do --trigger.action.outText(payloadCheck[_k].desc.typeName,10) if payloadCheck[_k].desc.typeName == "weapons.missiles.ADM_141A" then table.insert(_foundArty,tempFound[_i]) --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " " .. payloadCheck[1].desc.guidance,10) else --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " unguided bombs",10) end end end end end else _foundArty = tempFound end for _j = 1, #_foundArty do -- find arty with most ammo --trigger.action.outText(_foundArty[_j] .. " unguided bombs",10) --trigger.action.outText(#Group.getByName(_foundArty[_j]):getUnits().. " unguided bombs",10) local curAmmo = fac.artyGetAmmo(Group.getByName(_foundArty[_j]):getUnits()) if curAmmo > lastAmmo then _chosenArty = _foundArty[_j] end end if _chosenArty ~=nil then --trigger.action.outText(_chosenArty,10) return Group.getByName(_chosenArty) -- if retask == true then -- trigger.action.outTextForCoalition(side,fac.getFacName(_fac:getName()) .. " is re-tasking ".. _chosenArty .. "(".. Group.getByName(tempFound[_j]):getUnit(1) ..") to a new target",10) -- end else return nil end end function fac.getArty(_enemyUnit,_fac,_artyType) local _attackPoint = {} if _enemyUnit == nil then _attackPoint = fac.facOffsetMaker(_fac) else _attackPoint = _enemyUnit:getPoint() end local _i = 1 local _j = 1 --local _gndGroups = {} local _tempPoint = nil local _tempDist = nil local _tempPosition = nil local _lastArty = {ammo = 0, group = {}} local _chosenArty = nil local _tempArty = {} local _tempList = {} local _artyGroups = {} local side = _fac:getCoalition() local lastAmmo = 0 -- if overide == 2 then -- local retask = true -- --trigger.action.outText("retask",10) -- else -- local retask = false -- end -- finds all avaliable arty and chooses any untasked arty for firemission -- NEW arty check local dist = { id = world.VolumeType.SPHERE, params = { point = _attackPoint, radius = 4600000 --max range ARTY } } local tempFound = {} local _foundArty = {} local getArty = function(foundItem, val) -- generic search for all scenery --trigger.action.outTextForCoalition(side,foundItem:getTypeName() .. " found1 ",10) if side == foundItem:getCoalition() and foundItem:isActive() == true and foundItem:getPlayerName() == nil then -- check for friendly and not a player local _checkArty = fac.isArty(foundItem) local _tempArtyGroup = foundItem:getGroup() local _tGC = _tempArtyGroup:getController() --trigger.action.outText(_tempArtyGroup:getName() .. " found ",10) --trigger.action.outTextForCoalition(side,foundItem:getTypeName() .. " found1 ",10) if contains(tempFound,_tempArtyGroup:getName()) == false then --check for redundant groups --trigger.action.outTextForCoalition(side,foundItem:getTypeName() .. " found2 ",10) if _checkArty == true then --trigger.action.outTextForCoalition(side,foundItem:getTypeName() .. " found3 ",10) --trigger.action.outText(foundItem:getTypeName(),10) --if _tGC:hasTask() == false then -- check for tasked arty --if contains(fac.ArtyTasked,_tempArtyGroup:getName()) == false then -- check for tasked arty if fac.ArtyTasked[_tempArtyGroup:getName()] == nil then fac.ArtyTasked[_tempArtyGroup:getName()] = { name = _tempArtyGroup:getName(), tasked = 0, timeTasked = nil,tgt = nil, requestor = nil} end --trigger.action.outText(_tempArtyGroup:getName() .. " " .. fac.ArtyTasked[_tempArtyGroup:getName()].tasked,10) if fac.ArtyTasked[_tempArtyGroup:getName()].tasked == 0 then _tempPoint = foundItem:getPoint() _tempDist = fac.getDistance(_tempPoint, _attackPoint) --foundItem --trigger.action.outText(_tempArtyGroup:getName() .. " " .. fac.ArtyTasked[_tempArtyGroup:getName()].requestor,10) local _type = Unit.getTypeName(foundItem) if fac.artyGetAmmo(_tempArtyGroup:getUnits()) > 0 and foundItem:isActive() == true then --trigger.action.outText(_tempDist.. " "..fac.ArtilleryProperties[_type].minrange .. " " .. fac.ArtilleryProperties[_type].maxrange,10) if foundItem:hasAttribute('Strategic bombers') or foundItem:hasAttribute('Bombers') then --trigger.action.outText(foundItem:getTypeName().." "..fac.artyGetAmmo(_tempArtyGroup:getUnits()),10) table.insert(tempFound,_tempArtyGroup:getName()) elseif foundItem:hasAttribute('Naval') then if _artyType == 4 then if foundItem:getTypeName() == "USS_Arleigh_Burke_IIa" or foundItem:getTypeName() == "TICONDEROG" then table.insert(tempFound,_tempArtyGroup:getName()) end else local gunStats = {} gunStats = fac.artyGetNavalGunAmmo(_tempArtyGroup:getUnits()) --trigger.action.outText(foundItem:getTypeName().." "..gunStats[2],10) if gunStats[2] >= _tempDist then table.insert(tempFound,_tempArtyGroup:getName()) end end elseif (_tempDist > fac.ArtilleryProperties[_type].minrange and _tempDist < fac.ArtilleryProperties[_type].maxrange) then --check if in arty params --trigger.action.outText(foundItem:getTypeName().." "..fac.artyGetAmmo(_tempArtyGroup:getUnits()),10) -- check for ammo and if arty is active --if foundItem:getLife() > 1 then table.insert(tempFound,_tempArtyGroup:getName()) --end end end elseif fac.ArtyTasked[_tempArtyGroup:getName()].requestor == "AI Spotter" and _artyType ~= -1 then _tempPoint = foundItem:getPoint() _tempDist = fac.getDistance(_tempPoint, _attackPoint) --foundItem --trigger.action.outText(_tempArtyGroup:getName() .. " " .. fac.ArtyTasked[_tempArtyGroup:getName()].requestor,10) --trigger.action.outText(_tempArtyGroup:getName() .. " " .. fac.ArtyTasked[_tempArtyGroup:getName()].tasked,10) local _type = Unit.getTypeName(foundItem) if fac.artyGetAmmo(_tempArtyGroup:getUnits()) > 0 and foundItem:isActive() == true then trigger.action.outText(_tempDist.. " "..fac.ArtilleryProperties[_type].minrange .. " " .. fac.ArtilleryProperties[_type].maxrange,10) if foundItem:hasAttribute('Strategic bombers') or foundItem:hasAttribute('Bombers') then --trigger.action.outText(foundItem:getTypeName().." "..fac.artyGetAmmo(_tempArtyGroup:getUnits()),10) table.insert(tempFound,_tempArtyGroup:getName()) elseif (_tempDist > fac.ArtilleryProperties[_type].minrange and _tempDist < fac.ArtilleryProperties[_type].maxrange) then --check if in arty params --trigger.action.outText(foundItem:getTypeName().." "..fac.artyGetAmmo(_tempArtyGroup:getUnits()),10) -- check for ammo and if arty is active --if foundItem:getLife() > 1 then table.insert(tempFound,_tempArtyGroup:getName()) --end end end end end end end end world.searchObjects(Object.Category.UNIT,dist,getArty) --trigger.action.outTextForCoalition(side,#tempFound .. " found ",10) local _artyFilter = "2B11 mortar" if _artyType == 2 then --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName().. " ".._artyFilter,10) for _i = 1, #tempFound do if Group.getByName(tempFound[_i]):getUnit(1):getTypeName() == _artyFilter then table.insert(_foundArty,tempFound[_i]) end end elseif _artyType == 3 then for _i = 1, #tempFound do --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .." ".._artyFilter,10) if Group.getByName(tempFound[_i]):getUnit(1):getTypeName() ~= _artyFilter and (not Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('MissilesSS')) then local payloadCheck = Group.getByName(tempFound[_i]):getUnit(1):getAmmo() if payloadCheck[1].desc.guidance ~= nil then --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " " .. payloadCheck[1].desc.guidance,10) else --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " unguided bombs",10) table.insert(_foundArty,tempFound[_i]) end end end elseif _artyType == 5 then for _i = 1, #tempFound do if Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Strategic bombers') or Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Bombers') then --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .." ".._artyFilter,10) local payloadCheck = Group.getByName(tempFound[_i]):getUnit(1):getAmmo() if payloadCheck[1].desc.guidance == 1 then --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " " .. payloadCheck[1].desc.guidance,10) else --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " unguided bombs",10) table.insert(_foundArty,tempFound[_i]) end end end elseif _artyType == 4 then for _i = 1, #tempFound do --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .." ".._artyFilter,10) if Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Strategic bombers') or Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Bombers') then local payloadCheck = Group.getByName(tempFound[_i]):getUnit(1):getAmmo() if payloadCheck[1].desc.guidance == 1 then table.insert(_foundArty,tempFound[_i]) --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " " .. payloadCheck[1].desc.guidance,10) else --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " unguided bombs",10) end elseif Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Naval') then table.insert(_foundArty,tempFound[_i]) end end elseif _artyType == -1 then for _i = 1, #tempFound do if Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Strategic bombers') == false or Group.getByName(tempFound[_i]):getUnit(1):hasAttribute('Bombers') == false then --local payloadCheck = Group.getByName(tempFound[_i]):getUnit(1):getAmmo() --if payloadCheck[1].desc.guidance == 1 then table.insert(_foundArty,tempFound[_i]) end end else _foundArty = tempFound end for _j = 1, #_foundArty do -- find arty with most ammo --trigger.action.outText(_foundArty[_j] .. " unguided bombs",10) --trigger.action.outText(#Group.getByName(_foundArty[_j]):getUnits().. " unguided bombs",10) local curAmmo = fac.artyGetAmmo(Group.getByName(_foundArty[_j]):getUnits()) if curAmmo > lastAmmo then _chosenArty = _foundArty[_j] end end if _chosenArty ~=nil then return Group.getByName(_chosenArty) -- if retask == true then -- trigger.action.outTextForCoalition(side,fac.getFacName(_fac:getName()) .. " is re-tasking ".. _chosenArty .. "(".. Group.getByName(tempFound[_j]):getUnit(1) ..") to a new target",10) -- end else return nil end end function fac.artyGetAmmo(_units) local BatteryAmmo = 0 local n for n = 1, #_units do --Iterate through all units of the battery --if _units[n]:getTypeName() == groupType then --Check if a unit is of the same type as the battery local ammo = _units[n]:getAmmo() --Get ammo for this unit if ammo ~= nil then if ammo[1] then --Check if ammo[1] exists. If the ammo is used up, it returns nil... local UnitAmmo = ammo[1].count --Get the shell count for this unit --if UnitAmmo > minAmmo then --Check if there is ready ammo left local UnitReadyAmmo = UnitAmmo BatteryAmmo = BatteryAmmo + UnitReadyAmmo --Add unit ready ammo to total of group --end end end --end end return BatteryAmmo end function fac.artyGetNavalGunAmmo(_units) local BatteryAmmo = 0 local n local i local MaxRange = 0 local tempMaxRange = 0 for n = 1, #_units do --Iterate through all units of the battery --if _units[n]:getTypeName() == groupType then --Check if a unit is of the same type as the battery local ammo = _units[n]:getAmmo() --Get ammo for this unit if ammo ~= nil then for i = 1, #ammo do if ammo[i] then --Check if ammo[1] exists. If the ammo is used up, it returns nil... if ammo[i].desc.warhead.caliber >=75 and ammo[i].desc.category == 0 then local UnitAmmo = ammo[i].count --Get the shell count for this unit --if UnitAmmo > minAmmo then --Check if there is ready ammo left local UnitReadyAmmo = UnitAmmo BatteryAmmo = BatteryAmmo + UnitReadyAmmo --Add unit ready ammo to total of group if ammo[i].desc.warhead.caliber >= 120 then tempMaxRange = 22222 if tempMaxRange > MaxRange then MaxRange = tempMaxRange end else tempMaxRange = 18000 if tempMaxRange > MaxRange then MaxRange = tempMaxRange end end end end end end --end end return {BatteryAmmo, MaxRange} end function fac.artyGetGuidedAmmo(_units) local BatteryAmmo = 0 local n local i for n = 1, #_units do --Iterate through all units of the battery --if _units[n]:getTypeName() == groupType then --Check if a unit is of the same type as the battery local ammo = _units[n]:getAmmo() --Get ammo for this unit if ammo ~= nil then for i = 1, #ammo do if ammo[i].desc.guidance == 1 then --Check if ammo[1] exists. If the ammo is used up, it returns nil... if ammo[i].desc.category == 1 then if ammo[i].desc.missileCategory == 5 then local UnitAmmo = ammo[i].count --Get the shell count for this unit --if UnitAmmo > minAmmo then --Check if there is ready ammo left local UnitReadyAmmo = UnitAmmo BatteryAmmo = BatteryAmmo + UnitReadyAmmo --Add unit ready ammo to total of group end else local UnitAmmo = ammo[i].count --Get the shell count for this unit --if UnitAmmo > minAmmo then --Check if there is ready ammo left local UnitReadyAmmo = UnitAmmo BatteryAmmo = BatteryAmmo + UnitReadyAmmo --Add unit ready ammo to total of group end end end end --end end return BatteryAmmo end function fac.purgeArtList(_args) -- local element = fac.ArtyTasked[_args[1]] -- local tempTbl = {} --local I = 1 -- fac.ArtyTasked[_args[1]] = nil -- for I = 1, #fac.ArtyTasked do -- if(fac.ArtyTasked[I] ~= nil) then -- table.insert(tempTbl, fac.ArtyTasked[I]) -- end -- end -- fac.ArtyTasked = {} -- trigger.action.outText("clear" .. #fac.ArtyTasked,10) -- fac.ArtyTasked = tempTbl -- trigger.action.outText(_args[1].."clearing " .. #fac.ArtyTasked,10) -- local test, outIdx = contains(fac.ArtyTasked,_args[1]) -- trigger.action.outText(_args[1].."clearing " .. fac.ArtyTasked[outIdx],10) -- if test == true and fac.ArtyTasked[outIdx] == _args[1] then -- table.remove(fac.ArtyTasked,outIdx) -- trigger.action.outText(_args[1].." cleared " .. #fac.ArtyTasked,10) -- elseif test == true and fac.ArtyTasked[outIdx] ~= _args[1] then -- trigger.action.outText(" error clearing ".._args[1],10) -- for I = 1, #fac.ArtyTasked do -- if fac.ArtyTasked[I] ~= nil then -- trigger.action.outText(I .. " ".. fac.ArtyTasked[I],10) -- end -- end -- fac.purgeArtList(_args[1]) -- end --table.remove(fac.ArtyTasked) local curTime = timer.getTime() --trigger.action.outText(curTime .. " " .. fac.ArtyTasked[_args[1]].timeTasked,5) if Group.getByName(_args[1]):getCategory() >= 2 then if fac.ArtyTasked[_args[1]].timeTasked ~= nil then if fac.ArtyTasked[_args[1]].tasked == _args[2] then fac.ArtyTasked[_args[1]].tasked = 0 fac.ArtyTasked[_args[1]].tgt = nil fac.ArtyTasked[_args[1]].timeTasked = nil local leaderType = Group.getByName(_args[1]):getUnit(1):getDesc() trigger.action.outTextForCoalition(Group.getByName(_args[1]):getCoalition(),leaderType.displayName .. " time out, canceling tasking ",0.5) Group.getByName(_args[1]):getController():popTask() elseif fac.artyGetAmmo(Group.getByName(_args[1]):getUnits()) < fac.ArtyTasked[_args[1]].tasked then fac.ArtyTasked[_args[1]].tasked = 0 fac.ArtyTasked[_args[1]].tgt = nil fac.ArtyTasked[_args[1]].timeTasked = nil local leaderType = Group.getByName(_args[1]):getUnit(1):getDesc() trigger.action.outTextForCoalition(Group.getByName(_args[1]):getCoalition(),leaderType.displayName .. " insufficent ammo, canceling tasking ",0.5) Group.getByName(_args[1]):getController():popTask() end end end end function fac.tgtCatType(target) --trigger.action.outText("Assessing Type "..target:getName(), 15) --local _TGT_Type = Group.getByName(target:getName()):getCategory() local _TGT_Type = target:getCategory() --trigger.action.outText(_TGT_Type, 15) if _TGT_Type == 3 then --trigger.action.outText("TGT is Static Object", 15) return "Static" elseif _TGT_Type == 1 then --local _leadUnit = Group.getByName(target):getUnit(1) local _unitType = target:getCategory() --trigger.action.outText("TGT is Unit Object " .. _unitType, 15) return "Unit" end --end end function removeSetMark(_args) trigger.action.removeMark(_args[1]) end function fac.recceDetect(_args) local _facUnitName = _args[1] local _unit = nil fac.facManTGT[_args[1]] = {} local recceUnit = fac.getFacUnit(_facUnitName) local recceSide = recceUnit:getCoalition() local reccePos = recceUnit:getPoint() local _groupId = fac.getGroupId(recceUnit) local tempFound = {} local dist = { id = world.VolumeType.SPHERE, params = { point = reccePos, radius = 40000 } } --trigger.action.outText("FINDING STUFF", 15) --remove old Marks local _i --local recceMarkID = timer.getTime() * 1000 --for _i = 5000, fac.recceID do --trigger.action.removeMark(_i) --end local count = 0 local recceMarkTagets = function(foundItem, val) -- generic search for all scenery local foundOutput = nil local foundObjectPos = nil local sideCheck = foundItem:getCoalition() count = count + 1 if foundItem:getLife() >= 1 then if sideCheck ~= recceSide then _unit = foundItem local _unitPos = _unit:getPoint() local _offsetEnemyPos = { x = _unitPos.x, y = _unitPos.y + 2.0, z = _unitPos.z } local _offsetFacPos = { x = reccePos.x, y = reccePos.y + 2.0, z = reccePos.z } --trigger.action.outText("FOUND STUFF ".. foundItem:getLife(), 15) local _type = fac.tgtCatType(foundItem) if land.isVisible(_offsetEnemyPos, _offsetFacPos) then if _type == "Static" or _unit:isActive() then local recceMarkID = timer.getTime() * 1000 + count --trigger.action.outText("FOUND STUFF ".. _unit:getTypeName() .. recceMarkID .." "..fID, 15) local _vel = _unit:getVelocity() local _spd = 0 if _vel ~=nil then _spd = math.sqrt(_vel.x^2+_vel.z^2) end local unitPos = _unit:getPosition() local head = math.atan2(unitPos.x.z, unitPos.x.x) local _unitPos = _unit:getPosition().p --trigger.action.outText("FOUND STUFF ".. _unitPos.z, 15) if _unit:getTypeName() == "outpost_road" then _unitPos.x = _unitPos.x + math.cos(head+math.pi/2)*18 _unitPos.z = _unitPos.z + math.sin(head+math.pi/2)*18 end local _lat, _lon = coord.LOtoLL(_unitPos) local _latLngStr = mist.tostringLL(_lat, _lon, 3, false) local _latLngSecStr = mist.tostringLL(_lat, _lon, 3, true) local _mgrsString = mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(_unit:getPosition().p)), 5) --timer.scheduleFunction(fac.msgDraw, {_unit,recceSide,_facUnitName},timer.getTime() + 0.1) trigger.action.markToCoalition(recceMarkID,_unit:getTypeName() .." - DMS: " .. _latLngSecStr .." Altitude: ".. math.floor(_unitPos.y) .."m/" .. math.floor(_unitPos.y*3.28084) .."ft" .. "\nHeading: ".. math.floor(getHeading(_unit) * 180/math.pi) .. "\nSpeed: " .. math.floor(_spd*2) .. " MPH" .."\nSpotted by: " .. fac.getFacName(_facUnitName), _unitPos, recceSide, false,"") timer.scheduleFunction(removeSetMark,{recceMarkID},timer.getTime() + 300) table.insert(tempFound,_unit) fac.recceID = recceMarkID +1 end end end end end world.searchObjects(1,dist,recceMarkTagets) --world.searchObjects(Group.Category.GROUND,dist,recceMarkTagets) count = 0 world.searchObjects(3,dist,recceMarkTagets) --timer.scheduleFunction(fac.recceDetect, {_args,true}, timer.getTime() + 180) fac.facManTGT[_args[1]] = tempFound end function fac.stratStrike(_args) local i = 0 local _tgtList = fac.facManTGT[_args[1]] --local roundsExpended = fac.callFireMissionMulti({_args[1],1,4,_tgtList}) local roundsExpended = 1 --trigger.action.outText("FOUND STUFF "..#_tgtList .. " " .. roundsExpended, 30) while roundsExpended ~= nil do local tempList = {} for i = roundsExpended+1, #_tgtList do table.insert(tempList,_tgtList[i]) end _tgtList = {} _tgtList = tempList --trigger.action.outText(i .. " Targeting "..#_tgtList .. " " .. roundsExpended , 30) if #_tgtList >0 then roundsExpended = fac.callFireMissionMulti({_args[1],1,4,_tgtList}) else roundsExpended = nil end end end function fac.multiStrike(_args) local i = 0 local _tgtList = fac.facManTGT[_args[1]] --local roundsExpended = fac.callFireMissionMulti({_args[1],1,4,_tgtList}) local roundsExpended = 1 --trigger.action.outText("FOUND STUFF "..#_tgtList .. " " .. roundsExpended, 30) for i = 1, #_tgtList do if _tgtList[i]:isExist() then fac.callFireMission({_args[1],10,0,_tgtList[i]}) end end end function fac.msgDraw(_args) local _unit = _args[1] local recceSide = _args[2] local _facUnitName = _args[3] local recceMarkID = timer.getTime() * 1000 local _unitPos = _unit:getPoint() local _vel = _unit:getVelocity() local _spd = 0 if _vel ~=nil then _spd = math.sqrt(_vel.x^2+_vel.z^2) end --local unitPos = _unit:getPoint() local _lat, _lon = coord.LOtoLL(_unit:getPosition().p) local _latLngStr = mist.tostringLL(_lat, _lon, 3, false) local _latLngSecStr = mist.tostringLL(_lat, _lon, 3, true) local _mgrsString = mist.tostringMGRS(coord.LLtoMGRS(coord.LOtoLL(_unit:getPosition().p)), 5) trigger.action.outText("Trying to draw mark ".. curMark, 15) trigger.action.markToCoalition(recceMarkID,_unit:getTypeName() .." - DMS: " .. _latLngSecStr .." Altitude: ".. math.floor(_unitPos.y) .."m/" .. math.floor(_unitPos.y*3.28084) .."ft" .. "\nHeading: ".. math.floor(getHeading(_unit) * 180/math.pi) .. "\nSpeed: " .. math.floor(_spd*2) .. " MPH" .."\nSpotted by: " .. fac.getFacName(_facUnitName), _unitPos, recceSide, false,"") timer.scheduleFunction(removeSetMark,{recceMarkID},timer.getTime() + 180) --timer.scheduleFunction(awacs.removeSetMark,{facMarkID,_args[2]:getUnit(1):getName()},timer.getTime() + awacs.setAWACSscanRate [_args[3]]-.25) --awacs.trackID = AWACSMarkID +1 return end function fac.callFireMissionMulti(_args) local _facUnitName = _args[1] local _tgtList --trigger.action.outText("FOUND STUFF "..#_args[4], 15) local _facUnit = Unit.getByName(_facUnitName) if _args[4] == nil then _tgtList = fac.facManTGT[_args[1]] else _tgtList = _args[4] end local _artyRounds = _args[2] local _roundType = _args[3] local _groupId = fac.getGroupId(_facUnit) local _artyInRange = nil local _artyPos = {} local comboShoot = {} local comboTasker = {} local tp local _i if _tgtList == nil then trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10) trigger.action.outTextForGroup(_groupId,"No Valid Target, please create target list with manual scan",10) return nil end for _i = 1, #_tgtList do if _tgtList[_i]:isExist() then _artyInRange = fac.getArty(_tgtList[_i],_facUnit,_roundType) --if _artyInRange ~=nil then --_artyPos = _artyInRange:getUnit(1):getPoint() --else --return --end else trigger.action.outTextForGroup(_groupId,"Invalid target detected, please rescan for more current target list with manual scan",10) return end if _tgtList[_i] == nil or _artyInRange == nil then if _tgtList[_i] == nil and _artyInRange ~= nil then trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10) trigger.action.outTextForGroup(_groupId,"No Valid Target",10) return nil elseif _artyInRange == nil then trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10) trigger.action.outTextForGroup(_groupId,"No untasked active artillery/bomber in range of target",10) return nil else _artyPos = _artyInRange:getUnit(1):getPoint() end else tp = _tgtList[_i]:getPoint() local firepoint = {} firepoint.x = tp.x --+ _fireOffset.x firepoint.y = tp.z --+ _fireOffset.z --firepoint.radius = 10 firepoint.expend = "One" --firepoint.attackQty = 1 firepoint.attackQty = 1 firepoint.altitude = _artyPos.y firepoint.altitudeEnabled = true firepoint.weaponType = 268402702 --firepoint.expendQty = _artyRounds --firepoint.expendQtyEnabled = true local firemission = {id = 'Bombing', params = firepoint} if _artyInRange:getUnit(1):hasAttribute('Naval') then firepoint.expendQty = 1 firepoint.expendQtyEnabled = true firemission = {id = 'FireAtPoint', params = firepoint} end --_artyInRange:getController():pushTask(firemission) if (fac.artyGetGuidedAmmo(_artyInRange:getUnits())-_i) >= 0 then --trigger.action.outTextForGroup(_groupId,"Target processed " .. _tgtList[_i]:getTypeName(),10) table.insert (comboTasker,firemission) end -- timer.scheduleFunction(fac.launchMulti,{_artyInRange:getController(),firemission},timer.getTime()+ 45) end --tasks = { _i = end comboShoot = {id = 'ComboTask', params = {tasks = comboTasker}} _artyInRange:getController():setOption(1,1) _artyInRange:getController():pushTask(comboShoot) _artyInRange:getController():setOption(10,3221225470) --if fac.ArtyTasked[_artyInRange:getName()] == nil or fac.ArtyTasked[_artyInRange:getName()].tasked == 0 then --table.insert (fac.ArtyTasked, _artyInRange:getName()) --fac.ArtyTasked[_artyInRange:getName()] fac.ArtyTasked[_artyInRange:getName()]= {name = _artyInRange:getName(), tasked = #comboTasker,timeTasked = nil} --timer.scheduleFunction(fac.purgeArtList,{_artyInRange:getName()},timer.getTime()+ 45*#_tgtList) --end --timer.scheduleFunction(fac.clearTask,{_artyInRange:getController(),#_tgtList},timer.getTime()+ 20*#_tgtList) trigger.action.outTextForCoalition(_facUnit:getCoalition(),"Fire mission order sent, " .._artyInRange:getUnit(1):getTypeName() .. " ("..fac.artyGetGuidedAmmo(_artyInRange:getUnits())-#comboTasker .. " rounds remaining"..") firing ".._artyRounds.." rounds at " .. #comboTasker .. " target(s). Requestor: " .. fac.getFacName(_facUnitName) ,10) return fac.artyGetGuidedAmmo(_artyInRange:getUnits()) end function tablelength(T) local count = 0 for _ in pairs(T) do count = count + 1 end return count end function CrptBmbDesig:onEvent(e) local t ={} local pwdCheckList = {} local tgtHead local i local j --local str if e.id == 26 then if string.find(e.text, "CBRQT") or string.find(e.text, "TDRQT") then --trigger.action.outText(e.initiator:getName() .. " " .. e.groupID, 25) --local pwdCheckList =world.getMarkPanels() for i in string.gmatch(e.text, "%S+") do table.insert(t, i) end --trigger.action.outText(pwdCheckList[1].groupID..e.coalition, 25) if string.find(e.text, "CBRQT") then fac.carpetMapExecute({e.pos,t[1],e.coalition,"CARPET BOMB"}) world.removeEventHandler(CrptBmbDesig) trigger.action.removeMark(e.idx) else fac.carpetMapExecute({e.pos,t[1],e.coalition,"TALD"}) world.removeEventHandler(CrptBmbDesig) trigger.action.removeMark(e.idx) --trigger.action.removeMark(pwdCheckList[j].idx) -- for j =1, #pwdCheckList do -- if string.find(pwdCheckList[j].text,t[2]) and pwdCheckList[j].coalition ~=-1 then -- end end end end end function fac.carpetMapDesignate(_args) --local _unitR = fac.getFacUnit(_args[1]) --local _groupId = fac.getGroupId(_unitR) world.addEventHandler(CrptBmbDesig) --local pw = "Password is A"..timer.getTime() --trigger.action.markToGroup(timer.getTime()+_groupId,pw,_unitR:getPoint(),_groupId) end function RECCEDesig:onEvent(e) local t ={} local pwdCheckList = {} local tgtHead local i local j --local str if e.id == 26 then if string.find(e.text, "RECCE") then --trigger.action.outText(e.initiator:getName() .. " " .. e.groupID, 25) --local pwdCheckList =world.getMarkPanels() for i in string.gmatch(e.text, "%S+") do table.insert(t, i) end fac.RECCEMapExecute({e.pos,t[1],e.coalition,"TALD"}) world.removeEventHandler(RECCEDesig) trigger.action.removeMark(e.idx) end end end function fac.RECCEDesignate(_args) --local _unitR = fac.getFacUnit(_args[1]) --local _groupId = fac.getGroupId(_unitR) world.addEventHandler(RECCEDesig) --local pw = "Password is A"..timer.getTime() --trigger.action.markToGroup(timer.getTime()+_groupId,pw,_unitR:getPoint(),_groupId) end function fac.RECCEMapExecute(_args) local blueRECCEac = " " local redRECCEEac = " " local reccePont = _args[1] local side = _args[3] local avaliAB = {} local dist2RECCE = 1000000000 local RECCEmission = {} local _facUnitName = nil local selectRECCE = nil local selectRECCEgroup local selectRECCEpos for _, _facUnitName in pairs(fac.reccePilotNames) do --trigger.action.outText("Found " .. _facUnitName, 25) local recceAC = Unit.getByName(_facUnitName) if recceAC ~= nil then if recceAC:getPlayerName() == nil and fac.RECCETasked[_facUnitName] ~= 1 then --trigger.action.outText("Found " .. _facUnitName, 25) if side == recceAC:getCoalition() and recceAC:isExist() then local tempSelectRECCE = _facUnitName local tempSelectRECCEgroup = Unit.getByName(_facUnitName) :getGroup() local tempSelectRECCEpos = Unit.getByName(_facUnitName):getPoint() local tempdist = math.sqrt((tempSelectRECCEpos.x-reccePont.x)^2 + (tempSelectRECCEpos.z-reccePont.z)^2) --trigger.action.outText("Found " .. tempdist, 25) if dist2RECCE > tempdist then -- trigger.action.outText("Found " .. _facUnitName .." " ..tempdist.." " .. dist2RECCE, 25) selectRECCE = tempSelectRECCE selectRECCEgroup = tempSelectRECCEgroup selectRECCEpos = tempSelectRECCEpos dist2RECCE = tempdist end end end end end if selectRECCE ~= nil then local scriptSTR = "fac.recceDetect({"..'"' .. selectRECCE .. '"'.."})\nfac.RECCETasked["..'"'..selectRECCE..'"'.."] = 0\ntrigger.action.outTextForCoalition(" .. side ..","..'"'.."RECCE Misson Complete, " .. selectRECCE .." returning to holding orbit" .. '"'..",10)" local scriptSTR2 = "fac.RECCETasked["..'"'..selectRECCE..'"'.."] = 0\ntrigger.action.outTextForCoalition(" .. side ..","..'"'.. selectRECCE .." avaliable for retasking" .. '"'..",10)" --trigger.action.outText(scriptSTR, 25) --removebyKey(fac.RECCETasked,selectRECCE) RECCEmission = { id = 'Mission', params = { airborne = true, route = { points = { [1] = { ["x"] = selectRECCEpos.x, --bombIP.x + math.cos(ipAngle+_FH*math.pi/4)*radTurn, ["y"] = selectRECCEpos.z, --bombIP.y + math.sin(ipAngle+_FH*math.pi/4)*radTurn, ["type"] = "Turning Point", ["action"] = "Turning Point", ["alt"] = selectRECCEpos.y, ["speed"] = 544, --["task"] = {}, }, [2] = { ["x"] = reccePont.x, --bombIP.x + math.cos(ipAngle+_FH*math.pi/4)*radTurn, ["y"] = reccePont.z, --bombIP.y + math.sin(ipAngle+_FH*math.pi/4)*radTurn, ["type"] = "Turning Point", ["action"] = "Fly Over Point", ["alt"] = 20000, ["speed"] = 544, --["ETA"] = timer.getTime()+time2IP, ["ETA_locked"] = false, --["alt_type"] = ["task"] = { ["id"] = "ComboTask", ["params"] = { ["tasks"] = { --[1] = {}, [1] = { ["enabled"] = true, ["auto"] = false, ["id"] = "WrappedAction", ["number"] = 2, ["params"] = { ["action"] = { ["id"] = "Script", ["params"] = { ["command"] = scriptSTR, }, -- end of ["params"] }, -- end of ["action"] }, -- end of ["params"] }, -- end of [1] }, -- end of ["tasks"] }, -- end of ["params"] }, -- end of ["task"] }, [3] = { ["x"] = selectRECCEpos.x, --bombIP.x + math.cos(ipAngle+_FH*math.pi/4)*radTurn, ["y"] = selectRECCEpos.z, --bombIP.y + math.sin(ipAngle+_FH*math.pi/4)*radTurn, ["type"] = "Turning Point", ["action"] = "Turning Point", ["alt"] = selectRECCEpos.y, ["speed"] = 544, ["task"] = { ["id"] = "ComboTask", ["params"] = { ["tasks"] = { [1] = { ["enabled"] = true, ["auto"] = false, ["id"] = "Orbit", ["number"] = 1, ["params"] = { ["altitude"] = selectRECCEpos.y, ["pattern"] = "Circle", ["speed"] = 424.98611111111, ["speedEdited"] = true, }, -- end of ["params"] }, -- end of [1] [2] = { ["enabled"] = true, ["auto"] = false, ["id"] = "WrappedAction", ["number"] = 2, ["params"] = { ["action"] = { ["id"] = "Script", ["params"] = { ["command"] = scriptSTR, }, -- end of ["params"] }, -- end of ["action"] }, -- end of ["params"] }, -- end of [2] }, -- end of ["tasks"] }, -- end of ["params"] }, -- end of ["task"] }, } } } } local recceController = selectRECCEgroup:getController() recceController:setTask(RECCEmission) recceController:setOption(1,1) trigger.action.outTextForCoalition(_args[3], selectRECCE .. " a " .. Unit.getByName(selectRECCE):getTypeName() .. " has been dispatched to RECCE a Map Mark", 10) if contains(fac.RECCETasked,selectRECCE) == false then table.insert(fac.RECCETasked,selectRECCE) fac.RECCETasked[selectRECCE] = 1 else fac.RECCETasked[selectRECCE] = 1 end else trigger.action.outTextForCoalition(_args[3], "No AI RECCE Assets available", 10) end -- --RECCE spawner wip -- avaliAB = coalition.getAirbases(enum coalitionId ) -- for abCount = 1, #avaliAB do -- if Airbase.getCategory(avaliAB[abCount]) == 0 then -- -- --trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),Group.getByName(fireGroup):getUnit(1):getTypeName() .. " is winchester and RTB for rearm at " .. Airbase.getCallsign((avaliAB[abCount]),10) -- avaliAB[abCount].getPoint -- end -- end -- local group = { -- ["visible"] = false, -- ["taskSelected"] = true, -- --["groupId"] = HVA.tempGroupSpawnedcounter, -- ["hidden"] = false, -- ["units"] = {}, -- ["frequency"] = "", -- ["y"] = yofs, -- ["x"] = xofs, -- ["name"] = {}, -- ["start_time"] = 0, -- ["task"] = {}, -- ["route"] = { -- ["points"] = -- { -- [1] = -- { -- ["alt"] = rPos.y, -- ["type"] = "Turning Point", -- ["ETA"] = 0, -- ["alt_type"] = "RADIO", -- ["formation_template"] = "", -- ["y"] = yofs, -- ["x"] = xofs, -- ["ETA_locked"] = true, -- ["speed"] = _spd, -- ["action"] = "Cone", -- ["task"] = { -- ["id"] = "ComboTask", -- ["params"] = -- { -- ["tasks"] = -- { -- [1] ={}, -- [2] = -- { -- ["number"] = 2, -- ["auto"] = true, -- ["id"] = "Follow", -- ["enabled"] = true, -- ["params"] = -- { -- ["lastWptIndexFlagChangedManually"] = false, -- ["groupId"] = rId, -- ["lastWptIndex"] = 4, -- ["lastWptIndexFlag"] = false, -- ["pos"] = -- { -- ["y"] = math.random(0,200), -- ["x"] = 200, -- ["z"] = 200, -- }, -- end of ["pos"] -- }, -- }, -- }, -- end of ["tasks"] -- }, -- end of ["params"] -- }, -- end of ["task"], -- ["speed_locked"] = false, -- }, -- end of [1] -- } -- } -- } end function fac.carpetMapExecute(_args) local _enemyUnit = nil local _artyInRange = nil local _artyPos = {} local comboShoot = {} local previousTask = {} local comboTasker = {} local firemission = {} local firePointTask = {} local firePointWpt = {} local firepoint = {} local firepointFormTask ={} local firepointForm ={} local tpENV ={} local _i local bombIP ={} local ipTurnPt = {} local combatClimb = {} local combatTurn = {} local tp = {} local _k local comboTasker = {} --local tp = _args[4] local _i --trigger.action.outText(_args[1],_args[3], 25) local attackAz = 0 local directATTACK = true if _args[2] ~= "CBRQT" and _args[2] ~= "TDRQT" then --and type(_args[2]) ~= "string" and _args[2] > 360 --trigger.action.outText(_args[2], 25) local inAz = tonumber(_args[2]) if inAz ~= nil and inAz < 360 then attackAz = math.rad(inAz) directATTACK = false end else trigger.action.outTextForCoalition(_args[3],"Attack Heading not selected or is invalid, Defaulting to direct attack",10) end if _args[4] == "CARPET BOMB" then _artyInRange = fac.getBomber(_args[1],_args[3],5) else _artyInRange = fac.getBomber(_args[1],_args[3],3) end --if _enemyUnit == nil or _artyInRange == nil then -- if _enemyUnit == nil and _artyInRange ~= nil then -- trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10) -- trigger.action.outTextForGroup(_groupId,"No Valid Target",10) -- return if _artyInRange == nil then trigger.action.outTextForCoalition(_args[3],"Unable to process fire mission",10) trigger.action.outTextForCoalition(_args[3],"No untasked active bomber in range of target",10) return --else else _artyPos = _artyInRange:getUnit(1):getPoint() local ammoType = _artyInRange:getUnit(1):getAmmo() local weapStation = 1 if _args[4] == "TALD" then for _k = 1,#ammoType do --trigger.action.outText(payloadCheck[_k].desc.typeName,10) if ammoType[_k].desc.typeName == "weapons.missiles.ADM_141A" then weapStation = _k --table.insert(_foundArty,tempFound[_i]) --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " " .. payloadCheck[1].desc.guidance,10) --else --trigger.action.outText(Group.getByName(tempFound[_i]):getUnit(1):getTypeName() .. " unguided bombs",10) break end end end tp = _args[1] -- firePointWpt.x = tp.x + math.cos(getHeading(_facUnit)+math.pi)*5000 -- firePointWpt.y = tp.z + math.sin(getHeading(_facUnit)+math.pi)*5000 -- firePointWpt.type = "Turning Point" -- firePointWpt.action = "Turning Point" -- firePointWpt.alt = _artyPos.y firepoint.x = tp.x --+ _fireOffset.x firepoint.y = tp.z --+ _fireOffset.z firepoint.attackType = 'Carpet' firepoint.carpetLength = ammoType[weapStation].count*10 firepoint.expend = "All" firepoint.direction = attackAz + math.pi firepoint.directionEnabled = true firepoint.attackQty = 1 firepoint.groupAttack = true --firepoint.weaponType = 2147485694 if _args[4] == "TALD" then firepoint.weaponType = 8589934592 firepoint.altitude = 10000 firepoint.altitudeEnabled = false else firepoint.weaponType = 2147485694 firepoint.altitude = _artyPos.y firepoint.altitudeEnabled = true end --firepoint.expendQty = _artyRounds --firepoint.expendQtyEnabled = true --["params"] = TALDmission2 = {id = 'Bombing', params = { ["direction"] = firepoint.direction, ["attackQtyLimit"] = false, ["attackQty"] = 1, ["expend"] = "All", ["altitudeEdited"] = true, ["directionEnabled"] = false, ["groupAttack"] = true, ["altitude"] = firepoint.altitude, ["altitudeEnabled"] = true, ["y"] = firepoint.y, ["weaponType"] = firepoint.weaponType, ["x"] = firepoint.x, }, -- end of ["params"] } firePointTask = {id = 'CarpetBombing', params = firepoint} --TALDmission = {id = 'Bombing', params = firepoint} -- firePointWpt.task = firepointTask -- firepointForm.variantIndex = 2 -- firepointForm.formationIndex = 2 -- firepointForm.value = 131074 -- firePointFormTask = {id = 'Formation', params = firepointForm} -- previousTask = mist.getGroupRoute(_artyInRange:getName()) -- --table.insert (comboTasker,firepointFormTask) -- table.insert (comboTasker,firepointTask) -- --trigger.action.outText(mist.utils.tableShow(previousTask), 25) -- table.insert (comboTasker,previousTask) local _vel = _artyInRange:getUnit(1):getVelocity() _spd = math.sqrt(_vel.x^2+_vel.z^2) local atkSpd = _spd -- if _args[4] == "TALD" then -- atkSpd = 500 -- end local radTurn = (2*atkSpd)^2/(11.8*math.tan(25*math.pi/180)) radTurn = 20000 if _args[4] == "TALD" then radTurn = 64820 end local combatClimb = { ["alt"] = 2000, ["action"] = "Turning Point", ["alt_type"] = "BARO", ["speed"] = 220.97222222222, ["task"] = { ["id"] = "ComboTask", ["params"] = { ["tasks"] = { [1] = { ["enabled"] = true, ["auto"] = false, ["id"] = "Aerobatics", ["number"] = 1, ["params"] = { ["maneuversSequency"] = { [1] = { ["name"] = "CLIMB", ["params"] = { ["InitSpeed"] = { ["order"] = 3, ["value"] = 444, }, -- end of ["InitSpeed"] ["InitAltitude"] = { ["order"] = 2, ["value"] = 2000, }, -- end of ["InitAltitude"] ["StartImmediatly"] = { ["order"] = 5, ["value"] = 1, }, -- end of ["StartImmediatly"] ["RepeatQty"] = { ["min_v"] = 1, ["max_v"] = 10, ["value"] = 1, ["order"] = 1, }, -- end of ["RepeatQty"] ["UseSmoke"] = { ["order"] = 4, ["value"] = 0, }, -- end of ["UseSmoke"] ["Angle"] = { ["min_v"] = 15, ["max_v"] = 90, ["value"] = 45, ["step"] = 5, ["order"] = 6, }, -- end of ["Angle"] ["FinalAltitude"] = { ["order"] = 7, ["value"] = 10000, }, -- end of ["FinalAltitude"] }, -- end of ["params"] }, -- end of [1] }, -- end of ["maneuversSequency"] }, -- end of ["params"] }, -- end of [1] }, }, }, } local combatTurn = { ["enabled"] = true, ["auto"] = false, ["id"] = "Aerobatics", ["number"] = 2, ["params"] = { ["maneuversSequency"] = { [1] = { ["name"] = "TURN", ["params"] = { ["Ny_req"] = { ["order"] = 6, ["value"] = 2, }, -- end of ["Ny_req"] ["InitAltitude"] = { ["order"] = 2, ["value"] = 2000, }, -- end of ["InitAltitude"] ["StartImmediatly"] = { ["order"] = 5, ["value"] = 1, }, -- end of ["StartImmediatly"] ["UseSmoke"] = { ["order"] = 4, ["value"] = 0, }, -- end of ["UseSmoke"] ["SIDE"] = { ["order"] = 9, ["value"] = 0, }, -- end of ["SIDE"] ["InitSpeed"] = { ["order"] = 3, ["value"] = 795.49999999999, }, -- end of ["InitSpeed"] ["ROLL"] = { ["order"] = 7, ["value"] = 60, }, -- end of ["ROLL"] ["SECTOR"] = { ["order"] = 8, ["value"] = 90, }, -- end of ["SECTOR"] ["RepeatQty"] = { ["min_v"] = 1, ["max_v"] = 10, ["value"] = 1, ["order"] = 1, }, -- end of ["RepeatQty"] }, -- end of ["params"] }, -- end of [1] }, }, } bombIP.x = tp.x + math.cos(attackAz+math.pi)*radTurn*1 bombIP.z = tp.z + math.sin(attackAz+math.pi)*radTurn*1 local dx = -(_artyPos.x-bombIP.x) local dy = -(_artyPos.z-bombIP.z) local ipAngle = math.atan(dy/dx) --trigger.action.outText("IPANGLE = " .. (ipAngle)/math.pi*180 .."\n", 300) -- if ipAngle < 0 then -- ipAngle = ipAngle + 2*math.pi -- end local d2TGT = math.sqrt((_artyPos.x-tp.x)^2 + (_artyPos.z-tp.z)^2) local d2TP = math.sqrt((dx)^2 + (dy)^2) local time2TGT = d2TGT/411.6 local time2IP = d2TP/411.6 -- if d2TGT < d2TP then -- bombIP.x = tp.x + math.cos(attackAz)*radTurn*1 -- bombIP.z = tp.z + math.sin(attackAz)*radTurn*1 -- end local _FH = 1 if dy < 0 then -- dy = -1 90-270 if dx < 0 then --dy/dx = 1 180-270 --trigger.action.outText(_artyInRange:getName().." Firing SW:\n".. (ipAngle/math.pi)*180 .."\n", 300) --ipAngle= ipAngle + 2*math.pi -- math.pi/4 _FH = 0 else --trigger.action.outText(_artyInRange:getName().." Firing SE:\n".. (ipAngle/math.pi)*180 .."\n", 300) --ipAngle= ipAngle + math.pi --+ math.pi/4 _FH = -1 end elseif dy > 0 then --dy = 1 270-90 if dx < 0 then --dy/dx = -1 270-0 --trigger.action.outText(_artyInRange:getName().." Firing NW:\n".. (ipAngle/math.pi)*180 .."\n", 300) _FH = 0 --ipAngle= ipAngle + 2*math.pi -- math.pi/4 else --dy/dx = 1 0-90 --trigger.action.outText(_artyInRange:getName().." Firing NE:\n".. (ipAngle/math.pi)*180 .."\n", 300) --ipAngle= ipAngle -- + math.pi/4 _FH = 1 end end local taskedMission = {} if _args[4] == "TALD" then taskedMission = TALDmission2 else taskedMission = firePointTask end local IPoffset = {} IPoffset.x = bombIP.x + math.cos(ipAngle+math.pi*_FH)*d2TP/2 IPoffset.z = bombIP.z + math.sin(ipAngle+math.pi*_FH)*d2TP/2 if math.sqrt(dx^2+dy^2) < radTurn then IPoffset.x = bombIP.x IPoffset.z = bombIP.z end --_artyInRange local headingDeg = (ipAngle)/math.pi*180 if headingDeg >= 360 then headingDeg = headingDeg-360 end local scriptSTR = "trigger.action.outTextForCoalition(" .. _args[3] ..","..'"'.. _artyInRange:getUnit(1):getTypeName() .." is IP Inbound for " .._args[4] .. " attack" .. '"'..",10)" local ipSTR = {} ipstr ={ ["enabled"] = true, ["auto"] = false, ["id"] = "WrappedAction", ["number"] = 2, ["params"] = { ["action"] = { ["id"] = "Script", ["params"] = { ["command"] = scriptSTR, }, -- end of ["params"] }, -- end of ["action"] }, -- end of ["params"] } -- end of [1] table.insert(comboTasker,ipstr) --table.insert(comboTasker,combatClimb) table.insert(comboTasker,taskedMission) comboMission = {id = 'ComboTask', params = {tasks = comboTasker}} --trigger.action.outText(scriptSTR, 25) --trigger.action.outText(radTurn.."\n"..IPoffset.x .. " ".. IPoffset.z .."\n" ..bombIP.x .. " ".. bombIP.z .."\n".. headingDeg.."\n", 300) --trigger.action.markToCoalition(timer.getTime()+100,"TP ".. headingDeg .. "\nETA " .. time2IP, IPoffset,_args[3]) --trigger.action.markToCoalition(timer.getTime()+200,"IP".. headingDeg, bombIP,_args[3]) firemission = { id = 'Mission', params = { airborne = true, route = { points = {--firePointWpt--,previousTask [1] = { ["x"] = _artyPos.x, --bombIP.x + math.cos(ipAngle+_FH*math.pi/4)*radTurn, ["y"] = _artyPos.z, --bombIP.y + math.sin(ipAngle+_FH*math.pi/4)*radTurn, ["type"] = "Turning Point", ["action"] = "Turning Point", ["alt"] = firepoint.altitude, ["speed"] = atkSpd, --["task"] = {}, }, -- [2] = { -- ["x"] = IPoffset.x, --bombIP.x + math.cos(ipAngle+_FH*math.pi/4)*radTurn, -- ["y"] = IPoffset.z, --bombIP.y + math.sin(ipAngle+_FH*math.pi/4)*radTurn, -- ["type"] = "Turning Point", -- ["action"] = "Turning Point", -- ["alt"] = firepoint.altitude, -- ["speed"] = atkSpd, -- ["ETA"] = timer.getTime()+time2IP, -- ["ETA_locked"] = false, -- --["alt_type"] = -- ["task"] = {}, -- end of ["task"] -- }, -- [2] = { -- ["x"] = tp.x + math.cos(getHeading(_facUnit)+math.pi)*50*_spd*2, -- ["y"] = tp.z + math.sin(getHeading(_facUnit)+math.pi)*50*_spd*2, -- ["type"] = "Turning Point", -- ["action"] = "Turning Point", -- ["alt"] = _artyPos.y, -- --["speed"] = _artyInRange:getUnit(1):getVelocity(), -- --["task"] = {} -- }, [2] = { ["x"] = bombIP.x , ["y"] = bombIP.z, ["type"] = "Turning Point", ["action"] = "Fly Over Point", ["alt"] = firepoint.altitude, --["alt_type"] = ["speed"] = atkSpd, ["task"] = comboMission, ["ETA"] = timer.getTime() + time2IP*2, ["ETA_locked"] = false, }, [3] = { ["x"] = IPoffset.x, ["y"] = IPoffset.z, ["type"] = "Turning Point", ["action"] = "Turning Point", ["alt"] = firepoint.altitude, ["speed"] = atkSpd, --["alt_type"] = --["task"] = {} }, } } } } --_artyInRange:getController():pushTask(firemission) -- timer.scheduleFunction(fac.launchMulti,{_artyInRange:getController(),firemission},timer.getTime()+ 45) --end --tasks = { _i = --end --comboShoot = {id = 'ComboTask', params = {tasks = comboTasker}} --_artyInRange:getController():setOption(5,65539) --_artyInRange:getController():pushTask(firePointTask) _artyInRange:getController():setOption(1,1) if _args[4] == "TALD" then _artyInRange:getController():setOption(5,131074) if directATTACK == true then _artyInRange:getController():setTask(comboMission) else _artyInRange:getController():setTask(firemission) end else _artyInRange:getController():setOption(5,786435) if directATTACK == true then _artyInRange:getController():setTask(comboMission) else _artyInRange:getController():setTask(firemission) end end _artyInRange:getController():setOption(10,3221225470) if fac.ArtyTasked[_artyInRange:getName()] == nil or fac.ArtyTasked[_artyInRange:getName()].tasked == 0 then if fac.ArtyTasked[_artyInRange:getName()] == nil then table.insert (fac.ArtyTasked, _artyInRange:getName()) end --fac.ArtyTasked[_artyInRange:getName()] --fac.ArtyTasked[_artyInRange:getName()]= {name = _artyInRange:getName(), tasked = 1,timeTasked = nil} fac.ArtyTasked[_artyInRange:getName()]= {name = _artyInRange:getName(), tasked = ammoType[weapStation].count *#_artyInRange:getUnits() ,timeTasked = timer.getTime() ,tgt = nil} --timer.scheduleFunction(fac.purgeArtList,{_artyInRange:getName()},timer.getTime()+ 45*1) end --timer.scheduleFunction(fac.clearTask,{_artyInRange:getController(),#_tgtList},timer.getTime()+ 20*#_tgtList) trigger.action.outTextForCoalition(_args[3],"Fire mission order sent, " .._artyInRange:getUnit(1):getTypeName() .. "(".. ammoType[weapStation].count *#_artyInRange:getUnits() .." Rounds)".." will carpet bomb using ATK Az of ".. math.floor(attackAz/math.pi*180) .. " degrees on Map Mark" ,10) end end function fac.callFireMissionCarpet(_args) --local _facUnitName = _args[1] local _facUnit =_args[1] --local _tgtList = fac.facManTGT[_args[1]] local _artyRounds = _args[2] local _roundType = _args[3] local _groupId = _args[6] local _enemyUnit = nil local _artyInRange = nil local _artyPos = {} local comboShoot = {} local previousTask = {} local comboTasker = {} local firemission = {} local firePointTask = {} local firePointWpt = {} local firepoint = {} local firepointFormTask ={} local firepointForm ={} local tp = _args[4] local _i local attackHead = _args[5] if attackHead == nil or attackHead == "CBRQT" then trigger.action.outTextForGroup(_groupId,"No Heading defined, defaulting to 0 az",10) --trigger.action.outTextForGroup(_groupId,"No Valid Target, please create target list with manual scan",10) --return attackHead = 0 end --for _i = 1, #_tgtList do --if _tgtList[_i]:isExist() then --_enemyUnit = fac.getCurrentFacUnit(_facUnit, _facUnitName) _artyInRange = fac.getArty(tp,nil,_roundType,_args[7]) --if _artyInRange ~=nil then --_artyPos = _artyInRange:getUnit(1):getPoint() --else --return --end --else --trigger.action.outTextForGroup(_groupId,"Invalid target detected, please rescan for more current target list with manual scan",10) --return --end if _artyInRange == nil then trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10) trigger.action.outTextForGroup(_groupId,"No untasked active artillery/bomber in range of target",10) return --else else _artyPos = _artyInRange:getUnit(1):getPoint() tp = _enemyUnit:getPoint() firePointWpt.x = tp.x + math.cos(attackHead+math.pi)*5000 firePointWpt.y = tp.z + math.sin(attackHead+math.pi)*5000 firePointWpt.type = "Turning Point" firePointWpt.action = "Turning Point" firePointWpt.alt = _artyPos.y firepoint.x = tp.x --+ _fireOffset.x firepoint.y = tp.z --+ _fireOffset.z firepoint.attackType = 'Carpet' firepoint.carpetLength = 500 firepoint.expend = "All" --firepoint.direction = getHeading(_facUnit)--+math.pi firepoint.directionEnabled = true firepoint.attackQty = 1 firepoint.altitude = _artyPos.y firepoint.altitudeEnabled = true --firepoint.expendQty = _artyRounds --firepoint.expendQtyEnabled = true firepoint.groupAttack = true firePointTask = {id = 'CarpetBombing', params = firepoint} firePointWpt.task = firepointTask -- firepointForm.variantIndex = 2 -- firepointForm.formationIndex = 2 -- firepointForm.value = 131074 -- firePointFormTask = {id = 'Formation', params = firepointForm} previousTask = mist.getGroupRoute(_artyInRange:getName()) --table.insert (comboTasker,firepointFormTask) table.insert (comboTasker,firePointWpt) --trigger.action.outText(mist.utils.tableShow(previousTask), 25) table.insert (comboTasker,previousTask) --_artyInRange firemission = { id = 'Mission', params = { route = { points = {--firePointWpt--,previousTask [1] = { ["x"] = tp.x + math.cos(attackHead+math.pi)*20000, ["y"] = tp.z + math.sin(attackHead+math.pi)*20000, ["type"] = "Turning Point", ["action"] = "Turning Point", ["alt"] = _artyPos.y, ["task"] = firePointTask }, -- [2] = { -- ["x"] = tp.x + math.cos(getHeading(_facUnit)+math.pi)*5000, -- ["y"] = tp.z + math.sin(getHeading(_facUnit)+math.pi)*5000, -- ["type"] = "Turning Point", -- ["action"] = "Turning Point", -- ["alt"] = _artyPos.y, -- ["task"] = firePointTask -- } } } } } --_artyInRange:getController():pushTask(firemission) -- timer.scheduleFunction(fac.launchMulti,{_artyInRange:getController(),firemission},timer.getTime()+ 45) end --tasks = { _i = --end --comboShoot = {id = 'ComboTask', params = {tasks = comboTasker}} _artyInRange:getController():setOption(1,1) --_artyInRange:getController():pushTask(firePointTask) _artyInRange:getController():setOption(5,65539) _artyInRange:getController():setTask(firemission) _artyInRange:getController():setOption(10,3221225470) --if fac.ArtyTasked[_artyInRange:getName()] == nil or fac.ArtyTasked[_artyInRange:getName()].tasked > 0 then --table.insert (fac.ArtyTasked, _artyInRange:getName()) --fac.ArtyTasked[_artyInRange:getName()] fac.ArtyTasked[_artyInRange:getName()]= {name = _artyInRange:getName(), tasked = 1,timeTasked = nil} --timer.scheduleFunction(fac.purgeArtList,{_artyInRange:getName()},timer.getTime()+ 45*1) --end local ammoType = _artyInRange:getUnit(1):getAmmo() --timer.scheduleFunction(fac.clearTask,{_artyInRange:getController(),#_tgtList},timer.getTime()+ 20*#_tgtList) trigger.action.outTextForCoalition(_facUnit:getCoalition(),"Fire mission order sent, " .._artyInRange:getUnit(1):getTypeName() .. "(".. ammoType[1].count .." Rounds)".." will carpet bomb using ATK Az of ".. math.floor(attackHead/math.pi*180).. " degrees on target:" .. _enemyUnit:getTypeName() ,10) end function fac.callFireMissionCarpet2(_args) local _facUnitName = _args[1] local _facUnit = Unit.getByName(_facUnitName) local _tgtList = fac.facManTGT[_args[1]] local _artyRounds = _args[2] local _roundType = _args[3] local _groupId = fac.getGroupId(_facUnit) local _enemyUnit = nil local _artyInRange = nil local _artyPos = {} local comboShoot = {} local previousTask = {} local comboTasker = {} local firemission = {} local firePointTask = {} local firePointWpt = {} local firepoint = {} local firepointFormTask ={} local firepointForm ={} local tpENV ={} local _i local bombIP ={} local ipTurnPt = {} --if _tgtList == nil then --trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10) --trigger.action.outTextForGroup(_groupId,"No Valid Target, please create target list with manual scan",10) --return --end --for _i = 1, #_tgtList do --if _tgtList[_i]:isExist() then _enemyUnit = fac.getCurrentFacUnit(_facUnit, _facUnitName) _artyInRange = fac.getArty(_enemyUnit,_facUnit,_roundType) --if _artyInRange ~=nil then --_artyPos = _artyInRange:getUnit(1):getPoint() --else --return --end --else --trigger.action.outTextForGroup(_groupId,"Invalid target detected, please rescan for more current target list with manual scan",10) --return --end if _enemyUnit == nil or _artyInRange == nil then if _enemyUnit == nil and _artyInRange ~= nil then trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10) trigger.action.outTextForGroup(_groupId,"No Valid Target",10) return elseif _artyInRange == nil then trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10) trigger.action.outTextForGroup(_groupId,"No untasked active artillery/bomber in range of target",10) return --else end else _artyPos = _artyInRange:getUnit(1):getPoint() tp = _enemyUnit:getPoint() firePointWpt.x = tp.x + math.cos(getHeading(_facUnit)+math.pi)*5000 firePointWpt.y = tp.z + math.sin(getHeading(_facUnit)+math.pi)*5000 firePointWpt.type = "Turning Point" firePointWpt.action = "Turning Point" firePointWpt.alt = _artyPos.y firepoint.x = tp.x --+ _fireOffset.x firepoint.y = tp.z --+ _fireOffset.z firepoint.attackType = 'Carpet' firepoint.carpetLength = 1000 firepoint.expend = "All" --firepoint.direction = getHeading(_facUnit)--+math.pi --firepoint.directionEnabled = true firepoint.attackQty = 1 firepoint.altitude = _artyPos.y firepoint.altitudeEnabled = true --firepoint.expendQty = _artyRounds --firepoint.expendQtyEnabled = true firepoint.groupAttack = true firePointTask = {id = 'CarpetBombing', params = firepoint} firePointWpt.task = firepointTask -- firepointForm.variantIndex = 2 -- firepointForm.formationIndex = 2 -- firepointForm.value = 131074 -- firePointFormTask = {id = 'Formation', params = firepointForm} previousTask = mist.getGroupRoute(_artyInRange:getName()) --table.insert (comboTasker,firepointFormTask) table.insert (comboTasker,firepointTask) --trigger.action.outText(mist.utils.tableShow(previousTask), 25) table.insert (comboTasker,previousTask) local _vel = _artyInRange:getUnit(1):getVelocity() _spd = math.sqrt(_vel.x^2+_vel.z^2) local radTurn = (2*_spd)^2/(11.8*math.tan(25*math.pi/180)) bombIP.x = tp.x + math.cos(getHeading(_facUnit)+math.pi)*radTurn*1 bombIP.y = tp.z + math.sin(getHeading(_facUnit)+math.pi)*radTurn*1 local dx = -(_artyPos.x-bombIP.x) local dy = -(_artyPos.z-bombIP.y) local ipAngle = math.atan(dy/dx) local _FH = 1 if dy < 0 then -- dy = -1 90-270 if dx < 0 then --dy/dx = 1 180-270 --trigger.action.outText(_artyInRange:getName().." Firing SW:\n".. (_fireheading/math.pi)*180 .."\n", 300) ipAngle= ipAngle + 2*math.pi else --trigger.action.outText(_artyInRange:getName().." Firing SE:\n".. (_fireheading/math.pi)*180 .."\n", 300) ipAngle= ipAngle + math.pi end elseif dy > 0 then --dy = 1 270-90 if dx < 0 then --dy/dx = -1 270-0 --trigger.action.outText(_artyInRange:getName().." Firing NW:\n".. (_fireheading/math.pi)*180 .."\n", 300) ipAngle= ipAngle + 2*math.pi else --dy/dx = 1 0-90 --trigger.action.outText(_artyInRange:getName().." Firing NE:\n".. (_fireheading/math.pi)*180 .."\n", 300) ipAngle= ipAngle _FH = -1 end end local IPoffset = {} IPoffset.x = radTurn IPoffset.y = radTurn if math.sqrt(dx^2+dy^2) < radTurn then IPoffset.x = 1 IPoffset.y = 1 end --_artyInRange firemission = { id = 'Mission', params = { airborne = true, route = { points = {--firePointWpt--,previousTask [1] = { ["x"] = bombIP.x + math.cos(ipAngle)*radTurn, ["y"] = bombIP.y + math.sin(ipAngle)*radTurn, ["type"] = "Turning Point", ["action"] = "Turning Point", ["alt"] = _artyPos.y, ["speed"] = _artyInRange:getUnit(1):getVelocity(), --["alt_type"] = --["task"] = {} }, -- [2] = { -- ["x"] = tp.x + math.cos(getHeading(_facUnit)+math.pi)*50*_spd*2, -- ["y"] = tp.z + math.sin(getHeading(_facUnit)+math.pi)*50*_spd*2, -- ["type"] = "Turning Point", -- ["action"] = "Turning Point", -- ["alt"] = _artyPos.y, -- --["speed"] = _artyInRange:getUnit(1):getVelocity(), -- --["task"] = {} -- }, [2] = { ["x"] = tp.x + math.cos(getHeading(_facUnit)+math.pi)*radTurn*1, ["y"] = tp.z + math.sin(getHeading(_facUnit)+math.pi)*radTurn*1, ["type"] = "Turning Point", ["action"] = "Turning Point", ["alt"] = _artyPos.y, --["alt_type"] = ["speed"] = _artyInRange:getUnit(1):getVelocity(), ["task"] = firePointTask } } } } } --_artyInRange:getController():pushTask(firemission) -- timer.scheduleFunction(fac.launchMulti,{_artyInRange:getController(),firemission},timer.getTime()+ 45) end --tasks = { _i = --end --comboShoot = {id = 'ComboTask', params = {tasks = comboTasker}} _artyInRange:getController():setOption(1,1) _artyInRange:getController():setOption(5,65539) --_artyInRange:getController():pushTask(firePointTask) _artyInRange:getController():setTask(firemission) _artyInRange:getController():setOption(10,3221225470) --if fac.ArtyTasked[_artyInRange:getName()] == nil or fac.ArtyTasked[_artyInRange:getName()].tasked > 0 then --table.insert (fac.ArtyTasked, _artyInRange:getName()) --fac.ArtyTasked[_artyInRange:getName()] fac.ArtyTasked[_artyInRange:getName()]= {name = _artyInRange:getName(), tasked = 1,timeTasked = nil} --timer.scheduleFunction(fac.purgeArtList,{_artyInRange:getName()},timer.getTime()+ 45*1) --end local ammoType = _artyInRange:getUnit(1):getAmmo() --timer.scheduleFunction(fac.clearTask,{_artyInRange:getController(),#_tgtList},timer.getTime()+ 20*#_tgtList) trigger.action.outTextForCoalition(_facUnit:getCoalition(),"Fire mission order sent, " .._artyInRange:getUnit(1):getTypeName() .. "(".. ammoType[1].count .." Rounds)".." will carpet bomb using ATK Az of ".. math.floor(getHeading(_facUnit)/math.pi*180).. " degrees on target:" .. _enemyUnit:getTypeName() .. ". Requestor: " .. fac.getFacName(_facUnitName) ,10) end function fac.launchMulti(_args) _args[1]:pushTask(_args[2]) end function fac.taskedArty(_args) _args[1]:pushTask(_args[2]) end local facArtyFireDetect ={} function facArtyFireDetect:onEvent(e) if e.id == world.event.S_EVENT_SHOT then local fireGroup = Unit.getGroup(e.initiator):getName() local displayUnitName = e.initiator:getDesc() if fac.ArtyTasked[fireGroup] ~= nil and fac.ArtyTasked[fireGroup].tasked > 0 then fac.ArtyTasked[fireGroup].tasked = fac.ArtyTasked[fireGroup].tasked - 1 trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),displayUnitName.displayName .. " has commenced attack at designated target, tasked rounds remaining "..fac.ArtyTasked[fireGroup].tasked,0.5) if fac.ArtyTasked[fireGroup].tasked == 0 then --fac.ArtyTasked[fireGroup].tasked = false local leaderType = Group.getByName(fireGroup):getUnit(1):getDesc() trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(), leaderType.displayName .. " Task Group available for re-tasking ",20) end if Unit.getGroup(e.initiator):getCategory() > 1 and e.weapon:getCategory() == 0 then if fac.ArtyTasked[fireGroup].tgt:isExist() then local tgtPnt = fac.ArtyTasked[fireGroup].tgt:getPoint() local _tempDist = fac.getDistance(e.initiator:getPoint(), tgtPnt) timer.scheduleFunction(fac.explosions, {tgtPnt}, timer.getTime() + _tempDist/264) else Group.getByName(fireGroup):getController():popTask() fac.ArtyTasked[fireGroup].tasked = 0 trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),Group.getByName(fireGroup):getUnit(1):getTypeName() .. " Task Group tasked target destroyed, available for re-tasking ",20) end end elseif fac.ArtyTasked[fireGroup] ~= nil then fac.ArtyTasked[fireGroup].tasked = 0 if Unit.getGroup(e.initiator):getCategory() == 0 then --trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),Group.getByName(fireGroup):getUnit(1):getTypeName() .. " BOMBS AWAY!!! ",0.25) end end if fac.ArtyTasked[fireGroup] ~= nil and Unit.getGroup(e.initiator):getCategory() == 0 then --trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),Group.getByName(fireGroup):getUnit(1):getTypeName() .. " has ammo remaining " .. fac.artyGetAmmo(Unit.getGroup(e.initiator):getUnits()),10) if fac.artyGetAmmo(Unit.getGroup(e.initiator):getUnits()) == 0 then trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),displayUnitName.displayName .. " is winchester and RTB",10) -- local avaliAB = coalition.getAirbases(Group.getByName(fireGroup):getCoalition()) -- for abCount = 1, #avaliAB do -- if Airbase.getCategory(avaliAB[abCount]) == 0 then -- --trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),Group.getByName(fireGroup):getUnit(1):getTypeName() .. " is winchester and RTB for rearm at " .. Airbase.getCallsign((avaliAB[abCount]),10) -- local rearm = {} -- rearm = { -- id = 'Mission', -- params = { -- airborne = true, -- route = { -- points = {--firePointWpt--,previousTask -- [1] = { -- ["x"] = 0, -- ["y"] = 0, -- ["type"] = "LandingReFuAr", -- ["action"] = "LandingReFuAr", -- ["alt"] =0, -- ["speed"] = e.initiator:getUnit(1):getVelocity(), -- ["airdromeId"] = Airbase.getID(avaliAB[abCount]), -- ["timeReFuAr"] = 10, -- --["alt_type"] = -- --["task"] = {} -- }, -- } -- } -- }, -- } -- trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),Group.getByName(fireGroup):getUnit(1):getTypeName() .. " is winchester and RTB for rearm at " .. Airbase.getCallsign(avaliAB[abCount]),10) -- break -- end -- end -- Unit.getGroup(e.initiator):getController():pushTask(rearm) end end end end function fac.explosions(args) local tgtPnt = args[1] local explodePnt = {} explodePnt.x = tgtPnt.x + math.random(-15,15) explodePnt.z = tgtPnt.z + math.random(-15,15) explodePnt.y = tgtPnt.y trigger.action.explosion(explodePnt, 10) end world.addEventHandler(facArtyFireDetect) function fac.checkTask(_args) local _i local _j local _facUnitName = _args[1] local _facUnit = Unit.getByName(_facUnitName) local _facGroup = _facUnit:getGroup() local _groupId = fac.getGroupId(_facUnit) trigger.action.outTextForCoalition(_facGroup:getCoalition(), "Checking artillery/bomber units" ,10) local _enemyUnit = fac.getCurrentFacUnit(_facUnit, _facUnitName) local _artyInRange = fac.getArty(_enemyUnit,_facUnit,1) local artyList = fac.ArtyTasked local tp local _TGTdist = -1 --trigger.action.outTextForCoalition(_facGroup:getCoalition(), tablelength(fac.ArtyTasked),10) for _i, _j in pairs(fac.ArtyTasked) do if tablelength(fac.ArtyTasked) > 0 then local fireGroup = _i if _facGroup:getCoalition() == Group.getByName(fireGroup):getCoalition() and Group.getByName(fireGroup):getUnit(1):isActive() and Group.getByName(fireGroup):isExist() then local _artyPos = Group.getByName(fireGroup):getUnit(1):getPoint() if _enemyUnit ~= nil then tp = _enemyUnit:getPoint() _TGTdist = math.sqrt(((tp.z-_artyPos.z)^2)+((tp.x-_artyPos.x)^2)) end local ammoCount = fac.artyGetAmmo(Group.getByName(fireGroup):getUnits()) trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),Group.getByName(fireGroup):getUnit(1):getTypeName() .. " Tasked rounds remaining: "..fac.ArtyTasked[fireGroup].tasked .. " Current Ammo: " .. ammoCount .." " .. math.floor(_TGTdist) ,10) end else trigger.action.outTextForCoalition(_facGroup:getCoalition(), "No active artillery detected, build some artillery units with CTLD!!" ,10) end end end function fac.callFireMission(_args) local _facUnitName = _args[1] local _artyRounds = _args[2] local _roundType = _args[3] local _enemyUnit = nil local _artyInRange = nil local _facUnit = Unit.getByName(_facUnitName) local _groupId = fac.getGroupId(_facUnit) local _illumPoint = {} local tp local spotterName local msgTime = 10 if fac.getFacName(_facUnitName) == nil then spotterName = "AI Spotter" else spotterName = fac.getFacName(_facUnitName) end if _args[4] == nil then _enemyUnit = fac.getCurrentFacUnit(_facUnit, _facUnitName) else _enemyUnit = _args[4] end if _roundType < 4 then _artyInRange = fac.getArty(_enemyUnit,_facUnit,_roundType) else _artyInRange = fac.getBomber(_enemyUnit,_facUnit,_roundType) end if _enemyUnit == nil or _artyInRange == nil then if _enemyUnit == nil and _artyInRange ~= nil then if _roundType ~= 1 then if _roundType ~= -1 then trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10) trigger.action.outTextForGroup(_groupId,"No Valid Target",10) end else tp = fac.facOffsetMaker(_facUnit) _illumPoint.x = tp.x _illumPoint.y = tp.y + fac.illumHeight _illumPoint.z = tp.z trigger.action.illuminationBomb(_illumPoint,500) trigger.action.outTextForCoalition(_facUnit:getCoalition(),"Fire mission order sent, " .._artyInRange:getUnit(1):getTypeName() .. " Task Group is firing illumination rounds " .. fac.facOffsetDist .. " m from " ..spotterName,10) end elseif _artyInRange == nil then if _roundType ~= -1 then trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10) trigger.action.outTextForGroup(_groupId,"No untasked active artillery/bomber in range of target",10) end end else --if _enemyUnit:getCoalition() == 1 then if _roundType ~= 1 then if fac.ArtyTasked[_artyInRange:getName()] == nil or fac.ArtyTasked[_artyInRange:getName()].tasked == 0 then --table.insert (fac.ArtyTasked, _artyInRange:getName()) --fac.ArtyTasked[_artyInRange:getName()] fac.ArtyTasked[_artyInRange:getName()]= {name = _artyInRange:getName(), tasked = 0} if _artyInRange:getUnit(1):hasAttribute('Strategic bombers') or _artyInRange:getUnit(1):hasAttribute('Bombers') then --local firemission = {id = 'Bombing', params = firepoint} --timer.scheduleFunction(fac.purgeArtList,{_artyInRange:getName()},timer.getTime()+ 20) else --timer.scheduleFunction(fac.purgeArtList,{_artyInRange:getName()},timer.getTime()+ 600) end --timer.scheduleFunction(fac.clearTask,{_artyInRange:getController(),1},timer.getTime()+ 20*_artyRounds+180) end end --trigger.action.outText(table.getn(fac.redArty) .. "insert blu" ,10) -- else -- if _roundType ~= 1 then -- table.insert (fac.ArtyTasked, _artyInRange:getName()) -- timer.scheduleFunction(fac.purgeArtList,{_artyInRange:getName()},timer.getTime()+ 180) -- end -- --trigger.action.outText(table.getn(fac.redArty) .. "insert red" ,10) -- end local _artyPos = _artyInRange:getUnit(1):getPoint() local firepoint = {} tp = _enemyUnit:getPoint() local _fireOffset = {x = 0,y = 0,z =0} --local _fireOffset.y = 0 local dx = tp.x-_artyPos.x local dy = tp.z-_artyPos.z local fpNorthOffset = getNorthCorrection(tp) local _fireheading = math.atan(dy/dx) --correcting for coordinate space local _FH = 1 if dy < 0 then -- dy = -1 90-270 if dx < 0 then --dy/dx = 1 180-270 --trigger.action.outText(_artyInRange:getName().." Firing SW:\n".. (_fireheading/math.pi)*180 .."\n", 300) _fireheading= _fireheading + 2*math.pi else --trigger.action.outText(_artyInRange:getName().." Firing SE:\n".. (_fireheading/math.pi)*180 .."\n", 300) _fireheading= _fireheading + math.pi end elseif dy > 0 then --dy = 1 270-90 if dx < 0 then --dy/dx = -1 270-0 --trigger.action.outText(_artyInRange:getName().." Firing NW:\n".. (_fireheading/math.pi)*180 .."\n", 300) _fireheading= _fireheading + 2*math.pi else --dy/dx = 1 0-90 --trigger.action.outText(_artyInRange:getName().." Firing NE:\n".. (_fireheading/math.pi)*180 .."\n", 300) _fireheading= _fireheading _FH = -1 end end local headingDeg =(_fireheading)/math.pi*180 if headingDeg >= 360 then headingDeg = headingDeg-360 end --trigger.action.outText(_artyInRange:getName().."\ndY ".. dy .."\ndX ".. dx .."\ndy/dx" .. dy/dx .."\nrad ".. _fireheading/math.pi .."\ndeg " .. headingDeg,120) --_fireheading = _fireheading local _TGTdist = math.sqrt(((tp.z-_artyPos.z)^2)+((tp.x-_artyPos.x)^2)) local _TGThghtD = math.abs(tp.y-_artyPos.y) if _artyInRange:getUnit(1):getTypeName() == "2B11 mortar" then _fireOffset.x = math.cos(_fireheading)*(-(100+_TGThghtD/10))*_FH _fireOffset.z = math.sin(_fireheading)*(-(100+_TGThghtD/10))*_FH elseif _artyInRange:getUnit(1):hasAttribute('Strategic bombers') or _artyInRange:getUnit(1):hasAttribute('Bombers') then _artyRounds = 1 end firepoint.x = tp.x + _fireOffset.x firepoint.y = tp.z + _fireOffset.z --firepoint.radius = 10 local firemission = {} local ammoRemain = fac.artyGetAmmo(_artyInRange:getUnits()) if _artyInRange:getUnit(1):hasAttribute('Naval') then local tempAmmoRemain = {} tempAmmoRemain = fac.artyGetNavalGunAmmo(_artyInRange:getUnits()) ammoRemain = tempAmmoRemain[1] end if ammoRemain < _artyRounds then _artyRounds = ammoRemain end if _artyInRange:getUnit(1):hasAttribute('Strategic bombers') or _artyInRange:getUnit(1):hasAttribute('Bombers') then local bomberTasked = _artyInRange:getUnit(1) local payloadCheck = {} payloadCheck = bomberTasked:getAmmo() if payloadCheck[1].desc.guidance == nil or payloadCheck[1].desc.guidance == 7 then --trigger.action.outText(bomberTasked:getTypeName(),10) --trigger.action.outText(#payloadCheck,10) firepoint.expend = "Quarter" else --trigger.action.outText( payloadCheck[1].desc.guidance,120) firepoint.expend = "One" end firepoint.attackQty = 1 firepoint.altitude = _artyPos.y firepoint.altitudeEnabled = true firemission = {id = 'Bombing', params = firepoint} _artyInRange:getController():setOption(1,1) _artyInRange:getController():setOption(10,3221225470) elseif _artyInRange:getUnit(1):hasAttribute('MLRS') or (_artyInRange:getUnit(2) ~= nil and _artyInRange:getUnit(2):hasAttribute('MLRS')) then firepoint.expendQty = _artyRounds firepoint.expendQtyEnabled = true firepoint.weaponType = 30720 firemission = {id = 'FireAtPoint', params = firepoint} else firepoint.expendQty = _artyRounds firepoint.expendQtyEnabled = true firepoint.weaponType = 258503344128 firemission = {id = 'FireAtPoint', params = firepoint} end -- local firepoint2 ={} -- firepoint2.groupId = fac.getGroupId(_enemyUnit) -- firepoint2.expend = "Quarter" -- local firemission = {id = 'AttackGroup', params = firepoint2} if _roundType ~= 1 then --_artyInRange:getController():setOption(9,2) local artyController = _artyInRange:getController() --timer.scheduleFunction(fac.fireArty,{artyController,firemission},timer.getTime() + .5) artyController:pushTask(firemission) --_artyInRange:getController():setOption(9,0) --if _roundType ~= -1 then fac.ArtyTasked[_artyInRange:getName()]= {name = _artyInRange:getName(), tasked = _artyRounds ,timeTasked = timer.getTime() ,tgt = _enemyUnit, requestor = spotterName} --end --Controller.knowTarget(_artyInRange:getUnit(3):getController(),_enemyUnit) trigger.action.outTextForGroup(_artyInRange:getID(),"Az: "..math.floor(headingDeg).." Range: ".._TGTdist,30) --trigger.action.outTextForGroup(_groupId,"Az: "..math.floor(headingDeg).." Range: ".._TGTdist,60) --local ammoRemain = fac.artyGetAmmo(_artyInRange:getUnits()) local displayUnitName = _artyInRange:getUnit(1):getDesc() if _roundType == -1 then msgTime = 1 end trigger.action.outTextForCoalition(_facUnit:getCoalition(),"Fire mission order sent, " .. displayUnitName.displayName .. " Task Group(".. ammoRemain .. " rounds remaining"..") firing ".._artyRounds.." rounds at " .. _enemyUnit:getTypeName() .. ". Requestor: " .. spotterName ,msgTime) timer.scheduleFunction(fac.purgeArtList,{_artyInRange:getName(),_artyRounds}, timer.getTime() + 200) else _illumPoint.x = tp.x _illumPoint.y = tp.y + fac.illumHeight _illumPoint.z = tp.z trigger.action.illuminationBomb(_illumPoint,500) trigger.action.outTextForCoalition(_facUnit:getCoalition(),"Fire mission order sent, " .. displayUnitName.displayName .. "Task Group is firing illumination rounds at " .. _enemyUnit:getTypeName() .. ". Requestor: " .. spotterName,10) end end end function fac.fireArty(_args) _args[1]:pushTask(_args[2]) end function fac.artyAICall() --local atyDunitName --trigger.action.outText("Tasking AI to call ARTY", 10) fac.AITgted = {} local aiARTYmultiTgt = {} for _, atyDunitName in pairs(fac.artDirectNames) do --trigger.action.outText(atyDunitName.. " found", 10) local status, error = pcall(function() local _unitR = fac.getFacUnit(atyDunitName) if _unitR ~= nil then --trigger.action.outText(atyDunitName.. " calling ARTY", 10) local _groupIdR = fac.getGroupId(_unitR) if _groupIdR then --trigger.action.outText(atyDunitName.. " calling ARTY2", 10) aiARTYmultiTgt = fac.scanForTGTai({atyDunitName}) -- local i for i = 1, #aiARTYmultiTgt do if contains(fac.AITgted,aiARTYmultiTgt[i]:getName()) == false then table.insert(fac.AITgted, aiARTYmultiTgt[i]:getName()) if aiARTYmultiTgt[i]:isExist() then --trigger.action.outText(atyDunitName.. " calling ARTY on " .. aiARTYmultiTgt[i]:getName(), 10) fac.callFireMission({atyDunitName,10,-1,aiARTYmultiTgt[i]}) end end end end --[[else env.info(string.format("FAC DEBUG: unit nil %s",_facUnitName)) ]] end end) if (not status) then env.error(string.format("Error adding f10 to ARTY Spotter: %s", error), false) end end if ctld then local troopTypeIDX local transportIDX local onboardArtD = false for _i, transportIDX in pairs(ctld.inTransitTroops) do --trigger.action.outText(transportIDX.. " found", 10) --local onboardTroops = ctld.inTransitTroops[_i] --trigger.action.outText(transportIDX.troops.type .. " found", 10) if transportIDX.troops ~= nil then --trigger.action.outText(transportIDX.troops .. " found", 10) for _j, troopTypeIDX in pairs(transportIDX.troops.units) do --trigger.action.outText(troopTypeIDX.type .. "on" .. _i .. " found", 10) if contains(fac.artyDirectorTypes,troopTypeIDX.type) then onboardArtD = true break end end if onboardArtD == true then aiARTYmultiTgt = fac.scanForTGTai({_i}) -- local i for i = 1, #aiARTYmultiTgt do if contains(fac.AITgted,aiARTYmultiTgt[i]:getName()) == false then table.insert(fac.AITgted, aiARTYmultiTgt[i]:getName()) if aiARTYmultiTgt[i]:isExist() then --trigger.action.outText(atyDunitName.. " calling ARTY on " .. aiARTYmultiTgt[i]:getName(), 10) fac.callFireMission({_i,10,-1,aiARTYmultiTgt[i]}) end end end end end end end --fac.AITgted = {} timer.scheduleFunction(fac.artyAICall, nil, timer.getTime() + 30) end -- Scheduled functions (run cyclically) timer.scheduleFunction(fac.addFacF10MenuOptions, nil, timer.getTime() + 5.5) timer.scheduleFunction(fac.checkFacStatus, nil, timer.getTime() + 5.4) timer.scheduleFunction(fac.artyAICall, nil, timer.getTime() + 5)