mirror of
https://github.com/iTracerFacer/DCS_MissionDev.git
synced 2025-12-03 04:14:46 +00:00
2767 lines
106 KiB
Lua
2767 lines
106 KiB
Lua
--[[
|
|
DCS FAC v2.1.0
|
|
-------
|
|
|
|
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
|
|
]]
|
|
|
|
|
|
|
|
local facPlayerSpawn ={}
|
|
fac = {} -- do not modify this line
|
|
|
|
function contains(t, e)
|
|
for i = 1,#t do
|
|
if t[i] == e then return true end
|
|
end
|
|
return false
|
|
end
|
|
|
|
fac.facACTypes ={
|
|
"SA342L",
|
|
--"TF-51",
|
|
--"Hawk",
|
|
}
|
|
|
|
fac.artyDirectorTypes = {
|
|
"Soldier M249",
|
|
|
|
}
|
|
-- ***************** 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,
|
|
}
|
|
|
|
fac.artDirectNames = {
|
|
"testSpotter"
|
|
}
|
|
|
|
--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.outTextForGroup(gid,"Artillery Spotter has been deployed", 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
|
|
},
|
|
["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.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)
|
|
trigger.action.markToCoalition(tgtMarkID,_enemyUnit:getTypeName().. " - 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 " .. _enemyUnit:getTypeName() .. '. 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, 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
|
|
|
|
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() 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.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 <No Smart Munition> (Anti-Material)", _artyPath , fac.callFireMission, { _facUnitName,10,3})
|
|
|
|
local _cMissilePath = missionCommands.addSubMenuForGroup(_groupId, "Air 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 (Turn your aircraft to desired attack azimuth), Dumb bombs only", _cMissilePath , fac.callFireMissionCarpet, { _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() })
|
|
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
|
|
if _Aunit:hasAttribute('Artillery') or _Aunit:hasAttribute('MLRS') or _Aunit:hasAttribute('Strategic bombers') or _Aunit:hasAttribute('Bombers') 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())]
|
|
if _unitDB ~= nil and _unitDB.groupId then
|
|
return _unitDB.groupId
|
|
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.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
|
|
local _checkArty = fac.isArty(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') 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)
|
|
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
|
|
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.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)
|
|
if fac.ArtyTasked[_args[1]].timeTasked == _args[2] then
|
|
fac.ArtyTasked[_args[1]].tasked = 0
|
|
fac.ArtyTasked[_args[1]].tgt = nil
|
|
fac.ArtyTasked[_args[1]].timeTasked = nil
|
|
trigger.action.outTextForCoalition(Group.getByName(_args[1]):getCoalition(),Group.getByName(_args[1]):getUnit(1):getTypeName() .. " available for re-tasking ",10)
|
|
--return element
|
|
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.expendQty = _artyRounds
|
|
--firepoint.expendQtyEnabled = true
|
|
local firemission = {id = 'Bombing', params = firepoint}
|
|
--_artyInRange:getController():pushTask(firemission)
|
|
|
|
if (fac.artyGetAmmo(_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.artyGetAmmo(_artyInRange:getUnits())-#comboTasker .. " rounds remaining"..") firing ".._artyRounds.." rounds at " .. #comboTasker .. " target(s). Requestor: " .. fac.getFacName(_facUnitName) ,10)
|
|
return fac.artyGetAmmo(_artyInRange:getUnits())
|
|
end
|
|
|
|
function tablelength(T)
|
|
local count = 0
|
|
for _ in pairs(T) do count = count + 1 end
|
|
return count
|
|
end
|
|
|
|
function fac.callFireMissionCarpet(_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 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
|
|
--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 = 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
|
|
previousTask = mist.getGroupRoute(_artyInRange:getName())
|
|
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(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
|
|
}
|
|
-- [2] = {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
--_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():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()
|
|
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(),Group.getByName(fireGroup):getUnit(1):getTypeName() .. " has commenced firing at designated target, tasked rounds remaining "..fac.ArtyTasked[fireGroup].tasked,0.5)
|
|
if fac.ArtyTasked[fireGroup].tasked == 0 then
|
|
--fac.ArtyTasked[fireGroup].tasked = false
|
|
trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),Group.getByName(fireGroup):getUnit(1):getTypeName() .. " available for re-tasking ",20)
|
|
end
|
|
if Unit.getGroup(e.initiator):getCategory() > 1 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() .. " 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() == 1 then
|
|
trigger.action.outTextForCoalition(Group.getByName(fireGroup):getCoalition(),Group.getByName(fireGroup):getUnit(1):getTypeName() .. " BOMBS AWAY!!! ",0.25)
|
|
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
|
|
|
|
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
|
|
|
|
_artyInRange = fac.getArty(_enemyUnit,_facUnit,_roundType)
|
|
|
|
if _enemyUnit == nil or _artyInRange == nil then
|
|
if _enemyUnit == nil and _artyInRange ~= nil then
|
|
if _roundType ~= 1 then
|
|
trigger.action.outTextForGroup(_groupId,"Unable to process fire mission",10)
|
|
trigger.action.outTextForGroup(_groupId,"No Valid Target",10)
|
|
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() .. " firing illumination rounds " .. fac.facOffsetDist .. " m from " ..spotterName,10)
|
|
end
|
|
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)
|
|
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 = {}
|
|
|
|
|
|
|
|
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)
|
|
else
|
|
firepoint.expendQty = _artyRounds
|
|
firepoint.expendQtyEnabled = true
|
|
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():pushTask(firemission)
|
|
fac.ArtyTasked[_artyInRange:getName()]= {name = _artyInRange:getName(), tasked = _artyRounds ,timeTasked = timer.getTime() ,tgt = _enemyUnit}
|
|
--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)
|
|
trigger.action.outTextForCoalition(_facUnit:getCoalition(),"Fire mission order sent, " .._artyInRange:getUnit(1):getTypeName() .. " ("..fac.artyGetAmmo(_artyInRange:getUnits()) .. " rounds remaining"..") firing ".._artyRounds.." rounds at " .. _enemyUnit:getTypeName() .. ". Requestor: " .. spotterName ,10)
|
|
timer.scheduleFunction(fac.purgeArtList,{_artyInRange:getName(),timeTasked}, timer.getTime() + 600)
|
|
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, " .._artyInRange:getUnit(1):getTypeName() .. " firing illumination rounds at " .. _enemyUnit:getTypeName() .. ". Requestor: " .. spotterName,10)
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
function fac.artyAICall()
|
|
--local atyDunitName
|
|
--trigger.action.outText("Tasking AI to call ARTY", 10)
|
|
for _, atyDunitName in pairs(fac.artDirectNames) do
|
|
|
|
local status, error = pcall(function()
|
|
|
|
local _unitR = fac.getFacUnit(atyDunitName)
|
|
|
|
if _unitR ~= nil then
|
|
|
|
local _groupIdR = fac.getGroupId(_unitR)
|
|
|
|
if _groupIdR then
|
|
--trigger.action.outText(atyDunitName.. " calling ARTY", 10)
|
|
local aiARTYTgt = fac.findFacNearestVisibleEnemy(Unit.getByName(atyDunitName))
|
|
if contains(fac.AITgted,aiARTYTgt:getName()) == false then
|
|
table.insert(fac.AITgted, aiARTYTgt:getName())
|
|
fac.callFireMission({atyDunitName,10,2,aiARTYTgt})
|
|
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
|
|
fac.AITgted = {}
|
|
timer.scheduleFunction(fac.artyAICall, nil, timer.getTime() + 300)
|
|
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)
|