mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 2.2.6
Reaper and Kiowa synch, sweeper
This commit is contained in:
parent
2b6491b978
commit
0aca69967c
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
|||||||
autoCSAR = {}
|
autoCSAR = {}
|
||||||
autoCSAR.version = "2.1.0"
|
autoCSAR.version = "2.2.0"
|
||||||
autoCSAR.requiredLibs = {
|
autoCSAR.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
"cfxZones", -- Zones, of course
|
"cfxZones", -- Zones, of course
|
||||||
@ -17,7 +17,26 @@ autoCSAR.trackedEjects = {} -- we start tracking on eject
|
|||||||
2.0.1 - fix for coalition change when ejected player changes coas or is forced to neutral
|
2.0.1 - fix for coalition change when ejected player changes coas or is forced to neutral
|
||||||
- GC
|
- GC
|
||||||
2.1.0 - persistence support
|
2.1.0 - persistence support
|
||||||
|
2.2.0 - new noExploit option in config
|
||||||
|
- no csar mission if pilot lands too close to airbase or farp
|
||||||
|
and noExploit is on
|
||||||
--]]--
|
--]]--
|
||||||
|
autoCSAR.forbidden = {} -- indexed by name, contains point
|
||||||
|
autoCSAR.killDist = 2100 -- meters from center of forbidden
|
||||||
|
|
||||||
|
function autoCSAR.collectForbiddenZones()
|
||||||
|
local allYourBase = world.getAirbases()
|
||||||
|
for idx, aBase in pairs(allYourBase) do
|
||||||
|
-- collect airbases and farps, ignore ships
|
||||||
|
local desc = aBase:getDesc()
|
||||||
|
local cat = desc.category
|
||||||
|
if cat == 0 or cat == 1 then
|
||||||
|
local name = aBase:getName()
|
||||||
|
local p = aBase:getPoint()
|
||||||
|
autoCSAR.forbidden[name] = p
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function autoCSAR.removeGuy(args)
|
function autoCSAR.removeGuy(args)
|
||||||
local theGuy = args.theGuy
|
local theGuy = args.theGuy
|
||||||
@ -53,6 +72,28 @@ function autoCSAR.createNewCSAR(theUnit, coa)
|
|||||||
if coa == 2 and not autoCSAR.blueCSAR then
|
if coa == 2 and not autoCSAR.blueCSAR then
|
||||||
return -- no blue rescue
|
return -- no blue rescue
|
||||||
end
|
end
|
||||||
|
-- noExploit burnup
|
||||||
|
if autoCSAR.noExploit then
|
||||||
|
local p = theUnit:getPoint()
|
||||||
|
local burned = false
|
||||||
|
for name, aPoint in pairs(autoCSAR.forbidden) do
|
||||||
|
local d = dcsCommon.distFlat(p, aPoint)
|
||||||
|
if d < autoCSAR.killDist then
|
||||||
|
if autoCSAR.verbose then
|
||||||
|
trigger.action.outText("+++aCSAR: BURNED ejection touchdown: too close to <" .. name .. ">", 30)
|
||||||
|
end
|
||||||
|
burned = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if burned then
|
||||||
|
trigger.action.outText("Pilot made it safely to ground, and was taken into custody immediately", 30)
|
||||||
|
-- try and remove the guy now
|
||||||
|
Unit.destroy(theUnit)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- end burnup code
|
||||||
|
|
||||||
-- for later expansion
|
-- for later expansion
|
||||||
local theGroup = theUnit:getGroup()
|
local theGroup = theUnit:getGroup()
|
||||||
@ -130,7 +171,6 @@ function autoCSAR:onEvent(event)
|
|||||||
|
|
||||||
if event.id == 6 then -- eject, start tracking, remember coa
|
if event.id == 6 then -- eject, start tracking, remember coa
|
||||||
local coa = event.initiator:getCoalition()
|
local coa = event.initiator:getCoalition()
|
||||||
|
|
||||||
-- see if pilot has ejector seat and prepare to connect one with the other
|
-- see if pilot has ejector seat and prepare to connect one with the other
|
||||||
local info = nil
|
local info = nil
|
||||||
if event.target and event.target:isExist() then
|
if event.target and event.target:isExist() then
|
||||||
@ -160,10 +200,7 @@ end
|
|||||||
function autoCSAR.readConfigZone()
|
function autoCSAR.readConfigZone()
|
||||||
local theZone = cfxZones.getZoneByName("autoCSARConfig")
|
local theZone = cfxZones.getZoneByName("autoCSARConfig")
|
||||||
if not theZone then
|
if not theZone then
|
||||||
theZone = cfxZones.createSimpleZone("autoCSARConfig")
|
theZone = cfxZones.createSimpleZone("autoCSARConfig")
|
||||||
if autoCSAR.verbose then
|
|
||||||
trigger.action.outText("+++aCSAR: NO config zone!", 30)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
autoCSAR.verbose = theZone.verbose
|
autoCSAR.verbose = theZone.verbose
|
||||||
autoCSAR.redCSAR = theZone:getBoolFromZoneProperty("red", true)
|
autoCSAR.redCSAR = theZone:getBoolFromZoneProperty("red", true)
|
||||||
@ -178,6 +215,9 @@ function autoCSAR.readConfigZone()
|
|||||||
|
|
||||||
autoCSAR.seaCSAR = theZone:getBoolFromZoneProperty("seaCSAR", true)
|
autoCSAR.seaCSAR = theZone:getBoolFromZoneProperty("seaCSAR", true)
|
||||||
|
|
||||||
|
autoCSAR.noExploit = theZone:getBoolFromZoneProperty("noExploit", false)
|
||||||
|
autoCSAR.killDist = theZone:getNumberFromZoneProperty("killDist", 2100)
|
||||||
|
|
||||||
if autoCSAR.verbose then
|
if autoCSAR.verbose then
|
||||||
trigger.action.outText("+++aCSAR: read config", 30)
|
trigger.action.outText("+++aCSAR: read config", 30)
|
||||||
end
|
end
|
||||||
@ -249,6 +289,9 @@ function autoCSAR.start()
|
|||||||
autoCSAR.loadData()
|
autoCSAR.loadData()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- collect forbidden zones if noExploit is active
|
||||||
|
autoCSAR.collectForbiddenZones()
|
||||||
|
|
||||||
-- start GC
|
-- start GC
|
||||||
timer.scheduleFunction(autoCSAR.GC, {}, timer.getTime() + 1)
|
timer.scheduleFunction(autoCSAR.GC, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
|
|||||||
@ -2189,4 +2189,6 @@ end
|
|||||||
|
|
||||||
nameTest - optional safety / debug feature that will name-test each unit that is about to be spawned for replacement. Maybe auto turn on when verbose is set?
|
nameTest - optional safety / debug feature that will name-test each unit that is about to be spawned for replacement. Maybe auto turn on when verbose is set?
|
||||||
make example where transport can be different plane types but have same name
|
make example where transport can be different plane types but have same name
|
||||||
|
|
||||||
|
support 'orders' to complete replace routes, and pass to groundCommander like spawner. only for ground troops
|
||||||
--]]--
|
--]]--
|
||||||
@ -4,7 +4,7 @@
|
|||||||
-- *** EXTENDS ZONES: 'pathing' attribute
|
-- *** EXTENDS ZONES: 'pathing' attribute
|
||||||
--
|
--
|
||||||
cfxCommander = {}
|
cfxCommander = {}
|
||||||
cfxCommander.version = "2.0.0"
|
cfxCommander.version = "2.0.1"
|
||||||
--[[-- VERSION HISTORY
|
--[[-- VERSION HISTORY
|
||||||
- 1.0.5 - createWPListForGroupToPointViaRoads: detect no road found
|
- 1.0.5 - createWPListForGroupToPointViaRoads: detect no road found
|
||||||
- 1.0.6 - build in more group checks in assign wp list
|
- 1.0.6 - build in more group checks in assign wp list
|
||||||
@ -35,6 +35,7 @@ cfxCommander.version = "2.0.0"
|
|||||||
- hardened performCommands()
|
- hardened performCommands()
|
||||||
- createWPListForGroupToPoint() supports moveFormation
|
- createWPListForGroupToPoint() supports moveFormation
|
||||||
- makeGroupGoTherePreferringRoads() supports moveFormation
|
- makeGroupGoTherePreferringRoads() supports moveFormation
|
||||||
|
- 2.0.1 - hardened createBasicWaypoint when no formation given (default to echelonR
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
cfxCommander.requiredLibs = {
|
cfxCommander.requiredLibs = {
|
||||||
@ -260,6 +261,8 @@ function cfxCommander.createBasicWaypoint(point, speed, formation)
|
|||||||
if not speed then speed = 6 end -- 6 m/s = 20 kph
|
if not speed then speed = 6 end -- 6 m/s = 20 kph
|
||||||
wp.speed = speed
|
wp.speed = speed
|
||||||
|
|
||||||
|
if not formation then formation = "EchelonR" end
|
||||||
|
|
||||||
if cfxCommander.forceOffRoad then
|
if cfxCommander.forceOffRoad then
|
||||||
formation = "Off Road"
|
formation = "Off Road"
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
reaper = {}
|
reaper = {}
|
||||||
reaper.version = "1.0.0"
|
reaper.version = "1.1.0"
|
||||||
reaper.requiredLibs = {
|
reaper.requiredLibs = {
|
||||||
"dcsCommon",
|
"dcsCommon",
|
||||||
"cfxZones",
|
"cfxZones",
|
||||||
@ -8,8 +8,21 @@ reaper.requiredLibs = {
|
|||||||
VERSION HISTORY
|
VERSION HISTORY
|
||||||
|
|
||||||
1.0.0 - Initial Version
|
1.0.0 - Initial Version
|
||||||
|
1.1.0 - Individual status
|
||||||
|
- cycle target method
|
||||||
|
- cycle? attribute
|
||||||
|
- restructured menus
|
||||||
|
- added cycle target
|
||||||
|
- single status reprots full group
|
||||||
|
- drones have AFAC task instead of Reconnaissance
|
||||||
|
- Setting enroute task for group once target spotted
|
||||||
|
- compatible with Kiowa's L2MUM
|
||||||
|
- (undocumented) freq attribute for drones (in MHz)
|
||||||
|
- completely rewrote scanning method (performance)
|
||||||
|
- added FAC task
|
||||||
|
- split task generation from wp generation
|
||||||
|
- updated reaper naming, uniqueNames attribute (undocumented)
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
reaper.zones = {}-- all zones
|
reaper.zones = {}-- all zones
|
||||||
@ -17,6 +30,12 @@ reaper.scanning = {} -- zones that are scanning (looking for tgt). by zone name
|
|||||||
reaper.tracking = {} -- zones that are tracking tgt. by zone name
|
reaper.tracking = {} -- zones that are tracking tgt. by zone name
|
||||||
reaper.scanInterval = 10 -- seconds
|
reaper.scanInterval = 10 -- seconds
|
||||||
reaper.trackInterval = 0.3 -- seconds
|
reaper.trackInterval = 0.3 -- seconds
|
||||||
|
reaper.uuidCnt = 0
|
||||||
|
|
||||||
|
function reaper.uuid(instring)
|
||||||
|
reaper.uuidCnt = reaper.uuidCnt + 1
|
||||||
|
return instring .. "-R" .. reaper.uuidCnt
|
||||||
|
end
|
||||||
|
|
||||||
-- reading reaper zones
|
-- reading reaper zones
|
||||||
function reaper.readReaperZone(theZone)
|
function reaper.readReaperZone(theZone)
|
||||||
@ -25,6 +44,7 @@ function reaper.readReaperZone(theZone)
|
|||||||
if theZone.myType == "MQ-9 Reaper" then
|
if theZone.myType == "MQ-9 Reaper" then
|
||||||
theZone.alt = 9500
|
theZone.alt = 9500
|
||||||
else theZone.alt = 7500 end theZone.alt = theZone:getNumberFromZoneProperty("alt", theZone.alt)
|
else theZone.alt = 7500 end theZone.alt = theZone:getNumberFromZoneProperty("alt", theZone.alt)
|
||||||
|
theZone.freq = theZone:getNumberFromZoneProperty("freq", 133) * 1000000 -- in MHz
|
||||||
theZone.coa = theZone:getCoalitionFromZoneProperty("coalition", 2)
|
theZone.coa = theZone:getCoalitionFromZoneProperty("coalition", 2)
|
||||||
if theZone.coa == 0 then
|
if theZone.coa == 0 then
|
||||||
trigger.action.outText("+++Reap: Zone <" .. theZone.name .. "> is of coalition NEUTRAL. Switched to BLUE", 30)
|
trigger.action.outText("+++Reap: Zone <" .. theZone.name .. "> is of coalition NEUTRAL. Switched to BLUE", 30)
|
||||||
@ -44,6 +64,7 @@ function reaper.readReaperZone(theZone)
|
|||||||
theZone.autoRespawn = theZone:getBoolFromZoneProperty("autoRespawn", false)
|
theZone.autoRespawn = theZone:getBoolFromZoneProperty("autoRespawn", false)
|
||||||
theZone.launchUI = theZone:getBoolFromZoneProperty("launchUI", true)
|
theZone.launchUI = theZone:getBoolFromZoneProperty("launchUI", true)
|
||||||
theZone.statusUI = theZone:getBoolFromZoneProperty("statusUI", true)
|
theZone.statusUI = theZone:getBoolFromZoneProperty("statusUI", true)
|
||||||
|
theZone.uniqueNames = theZone:getBoolFromZoneProperty("uniqueNames", true) -- undocumented, leave true
|
||||||
if theZone:hasProperty("launch?") then
|
if theZone:hasProperty("launch?") then
|
||||||
theZone.launch = theZone:getStringFromZoneProperty("launch?", "<none>")
|
theZone.launch = theZone:getStringFromZoneProperty("launch?", "<none>")
|
||||||
theZone.launchVal = theZone:getFlagValue(theZone.launch)
|
theZone.launchVal = theZone:getFlagValue(theZone.launch)
|
||||||
@ -51,7 +72,12 @@ function reaper.readReaperZone(theZone)
|
|||||||
if theZone:hasProperty("status?") then
|
if theZone:hasProperty("status?") then
|
||||||
theZone.status = theZone:getStringFromZoneProperty("status?", "<none>")
|
theZone.status = theZone:getStringFromZoneProperty("status?", "<none>")
|
||||||
theZone.statusVal = theZone:getFlagValue(theZone.status)
|
theZone.statusVal = theZone:getFlagValue(theZone.status)
|
||||||
|
end
|
||||||
|
if theZone:hasProperty("cycle?") then
|
||||||
|
theZone.cycle = theZone:getStringFromZoneProperty("cycle?", "<none>")
|
||||||
|
theZone.cycleVal = theZone:getFlagValue(theZone.cycle)
|
||||||
end
|
end
|
||||||
|
|
||||||
theZone.hasSpawned = false
|
theZone.hasSpawned = false
|
||||||
|
|
||||||
if theZone.onStart then
|
if theZone.onStart then
|
||||||
@ -61,10 +87,24 @@ end
|
|||||||
|
|
||||||
-- spawn a drone from a zone
|
-- spawn a drone from a zone
|
||||||
function reaper.spawnForZone(theZone, ack)
|
function reaper.spawnForZone(theZone, ack)
|
||||||
|
-- delete any group with the same name
|
||||||
|
if not theZone.uniqueNames then
|
||||||
|
local exister = Group.getByName(theZone.name)
|
||||||
|
if exister then Group.destroy(exister) end
|
||||||
|
end
|
||||||
|
|
||||||
-- create spawn data
|
-- create spawn data
|
||||||
local gdata = dcsCommon.createEmptyGroundGroupData (dcsCommon.uuid(theZone.name))
|
local rName
|
||||||
gdata.task = "Reconnaissance"
|
if theZone.uniqueNames then
|
||||||
|
rName = reaper.uuid(theZone.name)
|
||||||
|
else
|
||||||
|
rName = theZone.name
|
||||||
|
end
|
||||||
|
|
||||||
|
local gdata = dcsCommon.createEmptyGroundGroupData (rName) -- warning: non-unique unit names, will replace previous
|
||||||
|
gdata.task = "AFAC"
|
||||||
gdata.route = {}
|
gdata.route = {}
|
||||||
|
|
||||||
-- calculate left and right
|
-- calculate left and right
|
||||||
local p = theZone:getPoint()
|
local p = theZone:getPoint()
|
||||||
local left, right
|
local left, right
|
||||||
@ -78,23 +118,31 @@ function reaper.spawnForZone(theZone, ack)
|
|||||||
end
|
end
|
||||||
gdata.x = left.x
|
gdata.x = left.x
|
||||||
gdata.y = left.z
|
gdata.y = left.z
|
||||||
|
gdata.frequency = theZone.freq
|
||||||
|
|
||||||
-- build the unit data
|
-- build the unit data
|
||||||
local unit = {}
|
local unit = {}
|
||||||
unit.name = dcsCommon.uuid(theZone.name)
|
unit.name = rName -- same as group
|
||||||
unit.x = left.x
|
unit.x = left.x
|
||||||
unit.y = left.z
|
unit.y = left.z
|
||||||
unit.type = theZone.myType
|
unit.type = theZone.myType
|
||||||
unit.skill = "High"
|
unit.skill = "High"
|
||||||
if theZone.myType == "MQ-9 Reaper" then
|
if theZone.myType == "MQ-9 Reaper" then
|
||||||
unit.speed = 55
|
unit.speed = 55
|
||||||
-- unit.alt = 9500
|
|
||||||
else
|
else
|
||||||
-- unit.alt = 7500
|
|
||||||
unit.speed = 33
|
unit.speed = 33
|
||||||
end
|
end
|
||||||
unit.alt = theZone.alt
|
unit.alt = theZone.alt
|
||||||
|
|
||||||
|
if theZone.uniqueNames then
|
||||||
|
else
|
||||||
|
if theZone.reaperGID and theZone.reaperUID then -- also re-use groupID
|
||||||
|
gdata.groupId = theZone.reaperGID
|
||||||
|
unit.unitId = theZone.reaperUID
|
||||||
|
trigger.action.outText("re-using data from old <" .. theZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- add to group
|
-- add to group
|
||||||
gdata.units[1] = unit
|
gdata.units[1] = unit
|
||||||
|
|
||||||
@ -112,7 +160,8 @@ function reaper.spawnForZone(theZone, ack)
|
|||||||
trigger.action.outText("+++Reap: failed to spawn for zone <" .. theZone.name .. ">", 30)
|
trigger.action.outText("+++Reap: failed to spawn for zone <" .. theZone.name .. ">", 30)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
theZone.reaperGID = theGroup:getID()
|
||||||
|
theZone.reaperUID = theGroup:getUnit(1):getID()
|
||||||
if theZone.verbose or reaper.verbose then
|
if theZone.verbose or reaper.verbose then
|
||||||
trigger.action.outText("+++reap: Spawned <" .. theGroup:getName() .. "> reaper", 30)
|
trigger.action.outText("+++reap: Spawned <" .. theGroup:getName() .. "> reaper", 30)
|
||||||
end
|
end
|
||||||
@ -145,7 +194,75 @@ function reaper.cleanUp(theZone)
|
|||||||
theZone.theSpot = nil
|
theZone.theSpot = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function reaper.createInitialWP(p, alt, speed)
|
function reaper.createReaperTask(alt, speed, target, theZone)
|
||||||
|
local task = {
|
||||||
|
["id"] = "ComboTask",
|
||||||
|
["params"] = {
|
||||||
|
["tasks"] = {
|
||||||
|
[1] = {
|
||||||
|
["enabled"] = true,
|
||||||
|
["auto"] = true,
|
||||||
|
["id"] = "FAC",
|
||||||
|
["number"] = 1,
|
||||||
|
["params"] =
|
||||||
|
{}, -- end of ["params"]
|
||||||
|
}, -- end of [1]
|
||||||
|
|
||||||
|
[2] = {
|
||||||
|
["enabled"] = true,
|
||||||
|
["auto"] = true,
|
||||||
|
["id"] = "WrappedAction",
|
||||||
|
["number"] = 2,
|
||||||
|
["params"] = {
|
||||||
|
["action"] = {
|
||||||
|
["id"] = "EPLRS",
|
||||||
|
["params"] = {
|
||||||
|
["value"] = true,
|
||||||
|
["groupId"] = 1,
|
||||||
|
}, -- end of ["params"]
|
||||||
|
}, -- end of ["action"]
|
||||||
|
}, -- end of ["params"]
|
||||||
|
}, -- end of [2]
|
||||||
|
[3] = {
|
||||||
|
["enabled"] = true,
|
||||||
|
["auto"] = false,
|
||||||
|
["id"] = "Orbit",
|
||||||
|
["number"] = 3,
|
||||||
|
["params"] = {
|
||||||
|
["altitude"] = alt,
|
||||||
|
["pattern"] = "Race-Track",
|
||||||
|
["speed"] = speed,
|
||||||
|
}, -- end of ["params"]
|
||||||
|
}, -- end of [3]
|
||||||
|
}, -- end of ["tasks"]
|
||||||
|
}, -- end of ["params"]
|
||||||
|
} -- end of ["task"]
|
||||||
|
if theTarget and theZone then
|
||||||
|
-- local gID = theTarget:getGroup():getID()
|
||||||
|
local gID = theTarget:getID() -- NOTE: theTarget is a GROUP!!!!
|
||||||
|
local task4 = {
|
||||||
|
["enabled"] = true,
|
||||||
|
["auto"] = false,
|
||||||
|
["id"] = "FAC_AttackGroup",
|
||||||
|
["number"] = 4,
|
||||||
|
["params"] =
|
||||||
|
{
|
||||||
|
["number"] = 1,
|
||||||
|
["designation"] = "No",
|
||||||
|
["modulation"] = 0,
|
||||||
|
["groupId"] = gID,
|
||||||
|
-- ["callname"] = 1,
|
||||||
|
-- ["datalink"] = true,
|
||||||
|
["weaponType"] = 0, -- 9663676414,
|
||||||
|
["frequency"] = theZone.freq, -- 133000000,
|
||||||
|
}, -- end of ["params"]
|
||||||
|
} -- end of [4]
|
||||||
|
task.params.tasks[4] = task4
|
||||||
|
end
|
||||||
|
return task
|
||||||
|
end
|
||||||
|
|
||||||
|
function reaper.createInitialWP(p, alt, speed) -- warning: target must be a GROUP
|
||||||
local wp = {
|
local wp = {
|
||||||
["alt"] = alt,
|
["alt"] = alt,
|
||||||
["action"] = "Turning Point",
|
["action"] = "Turning Point",
|
||||||
@ -154,39 +271,7 @@ function reaper.createInitialWP(p, alt, speed)
|
|||||||
["addopt"] = {}, -- end of ["addopt"]
|
["addopt"] = {}, -- end of ["addopt"]
|
||||||
}, -- end of ["properties"]
|
}, -- end of ["properties"]
|
||||||
["speed"] = speed,
|
["speed"] = speed,
|
||||||
["task"] = {
|
["task"] = {}, -- will construct later
|
||||||
["id"] = "ComboTask",
|
|
||||||
["params"] = {
|
|
||||||
["tasks"] = {
|
|
||||||
[1] = {
|
|
||||||
["enabled"] = true,
|
|
||||||
["auto"] = true,
|
|
||||||
["id"] = "WrappedAction",
|
|
||||||
["number"] = 1,
|
|
||||||
["params"] = {
|
|
||||||
["action"] = {
|
|
||||||
["id"] = "EPLRS",
|
|
||||||
["params"] = {
|
|
||||||
["value"] = true,
|
|
||||||
["groupId"] = 1,
|
|
||||||
}, -- end of ["params"]
|
|
||||||
}, -- end of ["action"]
|
|
||||||
}, -- end of ["params"]
|
|
||||||
}, -- end of [1]
|
|
||||||
[2] = {
|
|
||||||
["enabled"] = true,
|
|
||||||
["auto"] = false,
|
|
||||||
["id"] = "Orbit",
|
|
||||||
["number"] = 2,
|
|
||||||
["params"] = {
|
|
||||||
["altitude"] = alt,
|
|
||||||
["pattern"] = "Race-Track",
|
|
||||||
["speed"] = speed,
|
|
||||||
}, -- end of ["params"]
|
|
||||||
}, -- end of [2]
|
|
||||||
}, -- end of ["tasks"]
|
|
||||||
}, -- end of ["params"]
|
|
||||||
}, -- end of ["task"]
|
|
||||||
["type"] = "Turning Point",
|
["type"] = "Turning Point",
|
||||||
["ETA"] = 0,
|
["ETA"] = 0,
|
||||||
["ETA_locked"] = true,
|
["ETA_locked"] = true,
|
||||||
@ -195,69 +280,84 @@ function reaper.createInitialWP(p, alt, speed)
|
|||||||
["speed_locked"] = true,
|
["speed_locked"] = true,
|
||||||
["formation_template"] = "",
|
["formation_template"] = "",
|
||||||
} -- end of wp
|
} -- end of wp
|
||||||
|
|
||||||
|
wp.task = reaper.createReaperTask(alt, speed) -- no zone, no target
|
||||||
return wp
|
return wp
|
||||||
end
|
end
|
||||||
|
|
||||||
-- scanning & tracking
|
function reaper.setTarget(theZone, theTarget, cycled)
|
||||||
-- scanning looks for vehicles to track, and exectues much less often
|
-- add a laser tracker to this unit
|
||||||
-- tracking tracks a single vehicle and places a pointer on it
|
local lp = theTarget:getPoint()
|
||||||
function reaper.findFirstEnemyUnitVisible(enemies, theZone)
|
local lat, lon, alt = coord.LOtoLL(lp)
|
||||||
local p = theZone.theUav:getPoint()
|
lat, lon = dcsCommon.latLon2Text(lat, lon)
|
||||||
-- we assume a flat altitude of 7000m
|
|
||||||
local visRange = theZone.alt * 1 -- based on tan(45) = 1 --> range = alt
|
local theSpot = Spot.createLaser(theZone.theUav, {0, 2, 0}, lp, theZone.code)
|
||||||
for idx, aGroup in pairs(enemies) do
|
if theZone.doSmoke then
|
||||||
local theUnits = aGroup:getUnits()
|
trigger.action.smoke(lp , theZone.smokeColor )
|
||||||
-- optimization: only scan the first vehicle in group if it's in range local theUnit = theUnits[1]
|
end
|
||||||
local theUnit = theUnits[1]
|
trigger.action.outTextForCoalition(theZone.coa, "Drone <" .. theZone.name .. "> is tracking a <" .. theTarget:getTypeName() .. "> at " .. lat .. " " .. lon .. ", code " .. theZone.code, 30)
|
||||||
if theUnit and Unit.isExist(theUnit) then
|
trigger.action.outSoundForCoalition(theZone.coa, reaper.actionSound)
|
||||||
up = theUnit:getPoint()
|
theZone.theTarget = theTarget
|
||||||
d = dcsCommon.distFlat(up, p)
|
if theZone.theSpot then
|
||||||
if d < visRange then
|
theZone.theSpot:destroy()
|
||||||
-- try each unit if it is visible from drone
|
end
|
||||||
for idy, aUnit in pairs(theUnits) do
|
theZone.theSpot = theSpot
|
||||||
local up = aUnit:getPoint()
|
-- put me in track mode
|
||||||
up.y = up.y + 2
|
reaper.tracking[theZone.name] = theZone
|
||||||
if land.isVisible(p, up) then return aUnit end
|
|
||||||
end
|
if cycled then return end -- cycling inside group, no new tasking
|
||||||
|
|
||||||
|
-- now make tracking the group the drone's task
|
||||||
|
local theGroup = theTarget:getGroup()
|
||||||
|
local theTask = reaper.createReaperTask(theZone.alt, theZone.speed, theGroup, theZone) -- create full FAC task with orbit and group engage
|
||||||
|
local theController = theZone.theUav:getController()
|
||||||
|
if not theController then
|
||||||
|
trigger.action.outText("+++Rpr: UAV has no controller, getting group")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
theController:setTask(theTask) -- replace with longer task
|
||||||
|
end
|
||||||
|
|
||||||
|
function reaper.selectFromDetectedTargets(visTargets, theZone)
|
||||||
|
-- use (permanent?) detectedTargetList
|
||||||
|
for idx, tData in pairs(visTargets) do
|
||||||
|
if tData then
|
||||||
|
local theTarget = tData.object
|
||||||
|
local nn = theTarget:getName()
|
||||||
|
if not nn or nn == "" then
|
||||||
|
trigger.action.outText("+++reaper: shortcut on startup", 30)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
if theTarget and theTarget.getGroup then -- it's not a group or static object
|
||||||
|
local d = theTarget:getDesc()
|
||||||
|
if d.category == 2 then
|
||||||
|
if theZone.verbose then
|
||||||
|
trigger.action.outText("+++reap: identified <" .. tData.object:getName() .. "> as target for <" .. theZone.name .. ">")
|
||||||
|
end
|
||||||
|
return tData.object
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function reaper.scan()
|
function reaper.scanALT() -- alternative, more efficient (?) method using unit's controller
|
||||||
-- how far can the drone see? we calculate with a 120 degree opening
|
timer.scheduleFunction(reaper.scanALT, {}, timer.getTime() + reaper.scanInterval)
|
||||||
-- camera lens, making half angle = 45 --> tan(45) = 1
|
local filtered = {}
|
||||||
-- so the radius of the visible circle on the ground is 1 * altidude
|
|
||||||
timer.scheduleFunction(reaper.scan, {}, timer.getTime() + reaper.scanInterval)
|
|
||||||
filtered = {}
|
|
||||||
local redEnemies = coalition.getGroups(2, 2) -- blue ground vehicles
|
|
||||||
local blueEnemeis = coalition.getGroups(1, 2) -- get ground vehicles
|
|
||||||
for name, theZone in pairs(reaper.scanning) do
|
for name, theZone in pairs(reaper.scanning) do
|
||||||
local enemies = redEnemies
|
local theUAV = theZone.theUav
|
||||||
if theZone.coa == 2 then enemies = blueEnemeis end
|
if Unit.isExist(theUAV) then
|
||||||
if Unit.isExist(theZone.theUav) then
|
-- get the controller
|
||||||
local theTarget = reaper.findFirstEnemyUnitVisible(enemies, theZone)
|
local theController = theUAV:getController()
|
||||||
|
local visTargets = theController:getDetectedTargets(1, 2)
|
||||||
|
local theTarget = reaper.selectFromDetectedTargets(visTargets, theZone)
|
||||||
if theTarget then
|
if theTarget then
|
||||||
-- add a laser tracker to this unit
|
-- add a laser tracker to this unit
|
||||||
local lp = theTarget:getPoint()
|
reaper.setTarget(theZone, theTarget)
|
||||||
local lat, lon, alt = coord.LOtoLL(lp)
|
|
||||||
lat, lon = dcsCommon.latLon2Text(lat, lon)
|
|
||||||
|
|
||||||
local theSpot = Spot.createLaser(theZone.theUav, {0, 2, 0}, lp, theZone.code)
|
|
||||||
if theZone.doSmoke then
|
|
||||||
trigger.action.smoke(lp , theZone.smokeColor )
|
|
||||||
end
|
|
||||||
trigger.action.outTextForCoalition(theZone.coa, "Drone <" .. theZone.name .. "> is tracking a <" .. theTarget:getTypeName() .. "> at " .. lat .. " " .. lon .. ", code " .. theZone.code, 30)
|
|
||||||
trigger.action.outSoundForCoalition(theZone.coa, reaper.actionSound)
|
|
||||||
theZone.theTarget = theTarget
|
|
||||||
if theZone.theSpot then
|
|
||||||
theZone.theSpot:destroy()
|
|
||||||
end
|
|
||||||
theZone.theSpot = theSpot
|
|
||||||
-- put me in track mode
|
|
||||||
reaper.tracking[name] = theZone
|
|
||||||
else
|
else
|
||||||
-- will scan again
|
-- will scan again next round
|
||||||
filtered[name] = theZone
|
filtered[name] = theZone
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
@ -276,6 +376,7 @@ function reaper.scan()
|
|||||||
reaper.scanning = filtered
|
reaper.scanning = filtered
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function reaper.track()
|
function reaper.track()
|
||||||
local filtered = {}
|
local filtered = {}
|
||||||
for name, theZone in pairs(reaper.tracking) do
|
for name, theZone in pairs(reaper.tracking) do
|
||||||
@ -310,27 +411,73 @@ function reaper.track()
|
|||||||
timer.scheduleFunction(reaper.track, {}, timer.getTime() + reaper.trackInterval)
|
timer.scheduleFunction(reaper.track, {}, timer.getTime() + reaper.trackInterval)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function reaper.cycleTarget(theZone)
|
||||||
|
local coa = theZone.coa
|
||||||
|
-- try and advance to the next target
|
||||||
|
if not theZone.theUav or not Unit.isExist(theZone.theUav) then
|
||||||
|
trigger.action.outTextForCoalition(coa, "Reaper <" .. theZone.name .. "> not on station, requries launch first", 30)
|
||||||
|
trigger.action.outSoundForCoalition(theZone.coa, reaper.actionSound)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not theZone.theSpot or
|
||||||
|
not theZone.theUav or
|
||||||
|
not theZone.theTarget then
|
||||||
|
trigger.action.outTextForCoalition(coa, "Reaper <" .. theZone.name .. "> is not tracking a target", 30)
|
||||||
|
trigger.action.outSoundForCoalition(theZone.coa, reaper.actionSound)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
--when we get here, the reaper is tracking a target. get it's group
|
||||||
|
local theUnit = theZone.theTarget
|
||||||
|
if not theUnit.getGroup then return end -- safety first
|
||||||
|
local theGroup = theUnit:getGroup()
|
||||||
|
local allTargets = theGroup:getUnits()
|
||||||
|
local filtered = {}
|
||||||
|
local i = 1
|
||||||
|
local tIndex = 1
|
||||||
|
-- filter and find the target with it's index
|
||||||
|
for idx, aTgt in pairs(allTargets) do
|
||||||
|
if Unit.isExist(aTgt) then
|
||||||
|
if theUnit == aTgt then
|
||||||
|
if theZone.verbose then
|
||||||
|
trigger.action.outText("+++ reaper <" .. theZone.target .. ">: target index found : <" .. i .. ">", 30)
|
||||||
|
end
|
||||||
|
tIndex = i
|
||||||
|
end
|
||||||
|
table.insert(filtered, aTgt)
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local num = #filtered
|
||||||
|
if num < 2 then
|
||||||
|
-- nothing to do, simply ack
|
||||||
|
trigger.action.outTextForCoalition(coa, "<" .. theZone.name .. ">: Only one target left.", 30)
|
||||||
|
trigger.action.outSoundForCoalition(theZone.coa, reaper.actionSound)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
-- increase tIndex
|
||||||
|
tIndex = tIndex + 1
|
||||||
|
if tIndex > #filtered then tIndex = 1 end
|
||||||
|
local newTarget = filtered[tIndex]
|
||||||
|
-- tell zone to target this new target
|
||||||
|
reaper.setTarget(theZone, newTarget, true) -- also outputs text and action sound, true = cycled
|
||||||
|
end
|
||||||
|
|
||||||
function reaper.update()
|
function reaper.update()
|
||||||
timer.scheduleFunction(reaper.update, {}, timer.getTime() + 1)
|
timer.scheduleFunction(reaper.update, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
-- go through all my zones, and respawn those that have no
|
-- go through all my zones, and respawn those that have no
|
||||||
-- uav but have autoRespawn active
|
-- uav but have autoRespawn active
|
||||||
|
|
||||||
for name, theZone in pairs(reaper.zones) do
|
for name, theZone in pairs(reaper.zones) do
|
||||||
if theZone.autoRespawn and not theZone.theUav and theZone.hasSpawned then
|
if theZone.autoRespawn and not theZone.theUav and theZone.hasSpawned then
|
||||||
-- auto-respawn needs to kick in
|
-- auto-respawn needs to kick in
|
||||||
reaper.scanning[name] = nil
|
reaper.scanning[name] = nil
|
||||||
reaper.tracking[name] = nil
|
reaper.tracking[name] = nil
|
||||||
if reaper.verbose or theZone.verbose then
|
|
||||||
trigger.action.outText("+++reap: respawning for <" .. name .. ">", 30)
|
|
||||||
end
|
|
||||||
reaper.spawnForZone(theZone)
|
reaper.spawnForZone(theZone)
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone.status and theZone:testZoneFlag(theZone.status, "change", "statusVal") then
|
if theZone.status and theZone:testZoneFlag(theZone.status, "change", "statusVal") then
|
||||||
if theZone.verbose then
|
|
||||||
trigger.action.outText("+++reap: Triggered status for zone <" .. name .. "> on <" .. theZone.status .. ">", 30)
|
|
||||||
end
|
|
||||||
reaper.doSingleDroneStatus(theZone)
|
reaper.doSingleDroneStatus(theZone)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -340,6 +487,10 @@ function reaper.update()
|
|||||||
args[2] = name -- = args[2]
|
args[2] = name -- = args[2]
|
||||||
reaper.doLaunch(args)
|
reaper.doLaunch(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if theZone.cycle and theZone:testZoneFlag(theZone.cycle, "change", "cycleVal") then
|
||||||
|
reaper.cycleTarget(theZone)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- now poll my (global) status flags
|
-- now poll my (global) status flags
|
||||||
@ -356,45 +507,48 @@ end
|
|||||||
--
|
--
|
||||||
function reaper.installFullUIForCoa(coa)
|
function reaper.installFullUIForCoa(coa)
|
||||||
-- install "Drone Control" as root for red and blue
|
-- install "Drone Control" as root for red and blue
|
||||||
|
|
||||||
local mainMenu = nil
|
local mainMenu = nil
|
||||||
if reaper.mainMenu then
|
if reaper.mainMenu then
|
||||||
mainMenu = radioMenu.getMainMenuFor(reaper.mainMenu) -- nilling both next params will return menus[0]
|
mainMenu = radioMenu.getMainMenuFor(reaper.mainMenu) -- nilling both next params will return menus[0]
|
||||||
end
|
end
|
||||||
|
|
||||||
local root = missionCommands.addSubMenuForCoalition(coa, reaper.menuName, mainMenu)
|
local root = missionCommands.addSubMenuForCoalition(coa, reaper.menuName, mainMenu)
|
||||||
-- now install submenus
|
-- now install submenus
|
||||||
local c1 = missionCommands.addCommandForCoalition(coa, "Drone Status", root, reaper.redirectDroneStatus, {coa,})
|
reaper.installDCForCoa(coa, root)
|
||||||
local r2 = missionCommands.addSubMenuForCoalition(coa, "Launch Drones", root)
|
|
||||||
reaper.installLaunchersForCoa(coa, r2)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function reaper.installLaunchersForCoa(coa, root)
|
function reaper.installDCForCoa(coa, root)
|
||||||
-- WARNING: we currently install commands, may overflow!
|
|
||||||
-- trigger.action.outText("enter launchers builder", 30)
|
|
||||||
local filtered = {}
|
local filtered = {}
|
||||||
for name, theZone in pairs(reaper.zones) do
|
for name, theZone in pairs(reaper.zones) do
|
||||||
if theZone.coa == coa and theZone.launchUI then
|
if theZone.coa == coa and (theZone.statusUI or theZone.launchUI) then
|
||||||
filtered[name] = theZone
|
filtered[name] = theZone
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local n = dcsCommon.getSizeOfTable(filtered)
|
local n = dcsCommon.getSizeOfTable(filtered)
|
||||||
if n > 10 then
|
if n > 10 then
|
||||||
trigger.action.outText("+++reap: WARNING too many (" .. n .. ") launchers for coa <" .. coa .. ">", 30)
|
trigger.action.outText("+++reap: WARNING too many (" .. n .. ") drones for coa <" .. coa .. ">", 30)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
for name, theZone in pairs(filtered) do
|
for name, theZone in pairs(filtered) do
|
||||||
-- trigger.action.outText("proccing " .. name, 30)
|
local mnu = theZone.name .. ": " .. theZone.myType
|
||||||
mnu = theZone.name .. ": " .. theZone.myType
|
-- install menu for this drone
|
||||||
if bank and reaper.useCost then
|
local r1 = missionCommands.addSubMenuForCoalition(coa, mnu, root)
|
||||||
-- requires bank module
|
-- install status and cycle target commands for this drone
|
||||||
mnu = mnu .. "(§" .. theZone.cost .. ")"
|
|
||||||
end
|
|
||||||
local args = {coa, name, }
|
local args = {coa, name, }
|
||||||
local r3 = missionCommands.addCommandForCoalition(coa, mnu, root, reaper.redirectLaunch, args)
|
if theZone.launchUI then
|
||||||
|
mnu = "Launch " .. theZone.myType
|
||||||
|
if bank and reaper.useCost then
|
||||||
|
-- requires bank module
|
||||||
|
mnu = mnu .. " (§" .. theZone.cost .. ")"
|
||||||
|
end
|
||||||
|
local r3 = missionCommands.addCommandForCoalition(coa, mnu, r1, reaper.redirectLaunch, args)
|
||||||
|
end
|
||||||
|
if theZone.statusUI then
|
||||||
|
local r2 = missionCommands.addCommandForCoalition(coa, "Status Update", r1, reaper.redirectSingleStatus, args)
|
||||||
|
end
|
||||||
|
local r2 = missionCommands.addCommandForCoalition(coa, "Cycle target", r1, reaper.redirectCycleTarget, args)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function reaper.redirectDroneStatus(args)
|
function reaper.redirectDroneStatus(args)
|
||||||
timer.scheduleFunction(reaper.doDroneStatus, args, timer.getTime() + 0.1)
|
timer.scheduleFunction(reaper.doDroneStatus, args, timer.getTime() + 0.1)
|
||||||
@ -404,6 +558,13 @@ function reaper.redirectLaunch(args)
|
|||||||
timer.scheduleFunction(reaper.doLaunch, args, timer.getTime() + 0.1)
|
timer.scheduleFunction(reaper.doLaunch, args, timer.getTime() + 0.1)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function reaper.redirectSingleStatus(args)
|
||||||
|
timer.scheduleFunction(reaper.doSingleStatusM, args, timer.getTime() + 0.1)
|
||||||
|
end
|
||||||
|
|
||||||
|
function reaper.redirectCycleTarget(args)
|
||||||
|
timer.scheduleFunction(reaper.doCylcleTarget, args, timer.getTime() + 0.1)
|
||||||
|
end
|
||||||
--
|
--
|
||||||
-- DML API for UI
|
-- DML API for UI
|
||||||
--
|
--
|
||||||
@ -483,14 +644,12 @@ function reaper.doDroneStatus(args)
|
|||||||
else
|
else
|
||||||
msg = msg .. "\n\n(All drones have launched)\n"
|
msg = msg .. "\n\n(All drones have launched)\n"
|
||||||
end
|
end
|
||||||
|
|
||||||
trigger.action.outTextForCoalition(coa, msg, 30)
|
trigger.action.outTextForCoalition(coa, msg, 30)
|
||||||
trigger.action.outSoundForCoalition(coa, reaper.actionSound)
|
trigger.action.outSoundForCoalition(coa, reaper.actionSound)
|
||||||
end
|
end
|
||||||
|
|
||||||
function reaper.doSingleDroneStatus(theZone)
|
function reaper.doSingleDroneStatus(theZone)
|
||||||
local coa = theZone.coa
|
local coa = theZone.coa
|
||||||
-- trigger.action.outText("enter SINGLE drone status for coa " .. coa, 30)
|
|
||||||
local msg = ""
|
local msg = ""
|
||||||
local name = theZone.name
|
local name = theZone.name
|
||||||
-- see if drone is tracking
|
-- see if drone is tracking
|
||||||
@ -503,9 +662,31 @@ function reaper.doSingleDroneStatus(theZone)
|
|||||||
lat, lon = dcsCommon.latLon2Text(lat, lon)
|
lat, lon = dcsCommon.latLon2Text(lat, lon)
|
||||||
local ut = theTarget:getTypeName()
|
local ut = theTarget:getTypeName()
|
||||||
msg = msg .. ut .. " at " .. lat .. ", " .. lon .. " code " .. theZone.code
|
msg = msg .. ut .. " at " .. lat .. ", " .. lon .. " code " .. theZone.code
|
||||||
|
|
||||||
|
-- now add full group intelligence
|
||||||
|
local collector = {}
|
||||||
|
local theGroup = theTarget:getGroup()
|
||||||
|
local allTargets = theGroup:getUnits()
|
||||||
|
for idx, aTgt in pairs(allTargets) do
|
||||||
|
if Unit.isExist(aTgt) then
|
||||||
|
local tn = aTgt:getTypeName()
|
||||||
|
if collector[tn] then collector[tn] = collector[tn] + 1
|
||||||
|
else collector[tn] = 1 end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
msg = msg .."\nGroup consists of: "
|
||||||
|
local i = 1
|
||||||
|
for name, count in pairs(collector) do
|
||||||
|
if i > 1 then msg = msg .. ", " end
|
||||||
|
msg = msg .. name
|
||||||
|
if count > 1 then msg = msg .. " (x" .. count .. ")" end
|
||||||
|
i = 2
|
||||||
|
end
|
||||||
|
msg = msg .. ".\n"
|
||||||
else
|
else
|
||||||
msg = msg .. "[signal failure, please try later]"
|
msg = msg .. "[signal failure, please try again later]"
|
||||||
end
|
end
|
||||||
|
|
||||||
trigger.action.outTextForCoalition(coa, msg, 30)
|
trigger.action.outTextForCoalition(coa, msg, 30)
|
||||||
trigger.action.outSoundForCoalition(coa, reaper.actionSound)
|
trigger.action.outSoundForCoalition(coa, reaper.actionSound)
|
||||||
return
|
return
|
||||||
@ -528,9 +709,25 @@ function reaper.doSingleDroneStatus(theZone)
|
|||||||
trigger.action.outSoundForCoalition(coa, reaper.actionSound)
|
trigger.action.outSoundForCoalition(coa, reaper.actionSound)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function reaper.doSingleStatusM(args)
|
||||||
|
local coa = args[1]
|
||||||
|
local name = args[2]
|
||||||
|
local theZone = reaper.zones[name]
|
||||||
|
if not theZone then end return
|
||||||
|
reaper.doSingleDroneStatus(theZone)
|
||||||
|
end
|
||||||
|
|
||||||
|
function reaper.doCylcleTarget(args)
|
||||||
|
local coa = args[1]
|
||||||
|
local name = args[2]
|
||||||
|
local theZone = reaper.zones[name]
|
||||||
|
if not theZone then end return
|
||||||
|
reaper.cycleTarget(theZone)
|
||||||
|
end
|
||||||
|
|
||||||
function reaper.doLaunch(args)
|
function reaper.doLaunch(args)
|
||||||
coa = args[1]
|
local coa = args[1]
|
||||||
name = args[2]
|
local name = args[2]
|
||||||
-- check if we can launch
|
-- check if we can launch
|
||||||
local theZone = reaper.zones[name]
|
local theZone = reaper.zones[name]
|
||||||
if not theZone then
|
if not theZone then
|
||||||
@ -581,7 +778,7 @@ function reaper.readConfigZone()
|
|||||||
end
|
end
|
||||||
reaper.name = "reaperConfig" -- zones comaptibility
|
reaper.name = "reaperConfig" -- zones comaptibility
|
||||||
reaper.actionSound = theZone:getStringFromZoneProperty("actionSound", "UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav")
|
reaper.actionSound = theZone:getStringFromZoneProperty("actionSound", "UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav")
|
||||||
reaper.UI = theZone:getBoolFromZoneProperty("UI", true)
|
reaper.hasUI = theZone:getBoolFromZoneProperty("UI", true)
|
||||||
reaper.menuName = theZone:getStringFromZoneProperty("menuName", "Drone Command")
|
reaper.menuName = theZone:getStringFromZoneProperty("menuName", "Drone Command")
|
||||||
reaper.useCost = theZone:getBoolFromZoneProperty("useCost", true)
|
reaper.useCost = theZone:getBoolFromZoneProperty("useCost", true)
|
||||||
if theZone:hasProperty("blueStatus?") then
|
if theZone:hasProperty("blueStatus?") then
|
||||||
@ -668,7 +865,7 @@ function reaper.start()
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- install UI if desired
|
-- install UI if desired
|
||||||
if reaper.UI then
|
if reaper.hasUI then
|
||||||
local coas = {1, 2}
|
local coas = {1, 2}
|
||||||
for idx, coa in pairs(coas) do
|
for idx, coa in pairs(coas) do
|
||||||
reaper.installFullUIForCoa(coa)
|
reaper.installFullUIForCoa(coa)
|
||||||
@ -689,9 +886,9 @@ function reaper.start()
|
|||||||
timer.scheduleFunction(reaper.update, {}, timer.getTime() + 1)
|
timer.scheduleFunction(reaper.update, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
-- schedule scan and track loops
|
-- schedule scan and track loops
|
||||||
timer.scheduleFunction(reaper.scan, {}, timer.getTime() + 1)
|
-- timer.scheduleFunction(reaper.scan, {}, timer.getTime() + 1)
|
||||||
|
timer.scheduleFunction(reaper.scanALT, {}, timer.getTime() + 1)
|
||||||
timer.scheduleFunction(reaper.track, {}, timer.getTime() + 1)
|
timer.scheduleFunction(reaper.track, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
trigger.action.outText("reaper v " .. reaper.version .. " running.", 30)
|
trigger.action.outText("reaper v " .. reaper.version .. " running.", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@ -702,7 +899,5 @@ end
|
|||||||
|
|
||||||
--[[--
|
--[[--
|
||||||
Idea: mobile launch vehicle, zone follows apc around. Can even be hauled along with hook
|
Idea: mobile launch vehicle, zone follows apc around. Can even be hauled along with hook
|
||||||
idea: prioritizing targets in a group
|
|
||||||
fix quad zone waypoints
|
|
||||||
filter targets for lasing by list?
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxReconMode = {}
|
cfxReconMode = {}
|
||||||
cfxReconMode.version = "2.2.1"
|
cfxReconMode.version = "2.2.2"
|
||||||
cfxReconMode.verbose = false -- set to true for debug info
|
cfxReconMode.verbose = false -- set to true for debug info
|
||||||
cfxReconMode.reconSound = "UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav" -- to be played when somethiong discovered
|
cfxReconMode.reconSound = "UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav" -- to be played when somethiong discovered
|
||||||
|
|
||||||
@ -22,38 +22,6 @@ cfxReconMode.name = "cfxReconMode" -- to be compatible with test flags
|
|||||||
|
|
||||||
--[[--
|
--[[--
|
||||||
VERSION HISTORY
|
VERSION HISTORY
|
||||||
1.0.0 - initial version
|
|
||||||
1.0.1 - removeScoutByName()
|
|
||||||
1.0.2 - garbage collection
|
|
||||||
1.1.0 - autoRecon - any aircraft taking off immediately
|
|
||||||
signs up, no message when signing up or closing down
|
|
||||||
standalone - copied common procs lerp, agl, dist, distflat
|
|
||||||
from dcsCommon
|
|
||||||
report numbers
|
|
||||||
verbose flag
|
|
||||||
1.2.0 - queued recons. One scout per second for more even
|
|
||||||
performance
|
|
||||||
removed gc since it's now integrated into
|
|
||||||
update queue
|
|
||||||
removeScout optimization when directly passing name
|
|
||||||
playerOnlyRecon for autoRecon
|
|
||||||
red, blue, grey side filtering on auto scout
|
|
||||||
1.2.1 - parametrized report sound
|
|
||||||
1.3.0 - added black list, prio list functionality
|
|
||||||
1.3.1 - callbacks now also push name, as group can be dead
|
|
||||||
- removed bug when removing dead groups from map
|
|
||||||
1.4.0 - import dcsCommon, cfxZones etc
|
|
||||||
- added lib check
|
|
||||||
- config zone
|
|
||||||
- prio+
|
|
||||||
- detect+
|
|
||||||
1.4.1 - invocation no longer happen twice for prio.
|
|
||||||
- recon sound
|
|
||||||
- read all flight groups at start to get rid of the
|
|
||||||
- late activation work-around
|
|
||||||
1.5.0 - removeWhenDestroyed()
|
|
||||||
- autoRemove()
|
|
||||||
- readConfigZone creates default config zone so we get correct defaulting
|
|
||||||
2.0.0 - DML integration prio+-->prio! detect+ --> detect!
|
2.0.0 - DML integration prio+-->prio! detect+ --> detect!
|
||||||
and method
|
and method
|
||||||
- changed access to prio and blacklist to hash
|
- changed access to prio and blacklist to hash
|
||||||
@ -90,24 +58,9 @@ VERSION HISTORY
|
|||||||
- new marksFadeAfter config attribute to control mark time
|
- new marksFadeAfter config attribute to control mark time
|
||||||
- dmlZones OOP upgrade
|
- dmlZones OOP upgrade
|
||||||
2.2.1 - fixed "cfxReconSMode" typo
|
2.2.1 - fixed "cfxReconSMode" typo
|
||||||
|
2.2.2 - added groupNames attribute
|
||||||
|
- clean-up
|
||||||
|
|
||||||
cfxReconMode is a script that allows units to perform reconnaissance
|
|
||||||
missions and, after detecting units, marks them on the map with
|
|
||||||
markers for their coalition and some text
|
|
||||||
Also, a callback is initiated for scouts as follows
|
|
||||||
signature: (reason, theSide, theSout, theGroup) with
|
|
||||||
reason a string
|
|
||||||
'detected' a group was detected
|
|
||||||
'removed' a mark for a group timed out
|
|
||||||
'priority' a member of prio group was detected
|
|
||||||
'start' a scout started scouting
|
|
||||||
'end' a scout stopped scouting
|
|
||||||
'dead' a scout has died and was removed from pool
|
|
||||||
theSide - side of the SCOUT that detected units
|
|
||||||
theScout - the scout that detected the group
|
|
||||||
theGroup - the group that is detected
|
|
||||||
theName - the group's name
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
cfxReconMode.detectionMinRange = 3000 -- meters at ground level
|
cfxReconMode.detectionMinRange = 3000 -- meters at ground level
|
||||||
@ -137,9 +90,6 @@ cfxReconMode.marksFadeAfter = 30*60 -- after detection, marks disappear after
|
|||||||
cfxReconMode.callbacks = {} -- sig: cb(reason, side, scout, group)
|
cfxReconMode.callbacks = {} -- sig: cb(reason, side, scout, group)
|
||||||
cfxReconMode.uuidCount = 0 -- for unique marks
|
cfxReconMode.uuidCount = 0 -- for unique marks
|
||||||
|
|
||||||
|
|
||||||
-- end standalone dcsCommon extract
|
|
||||||
|
|
||||||
function cfxReconMode.uuid()
|
function cfxReconMode.uuid()
|
||||||
cfxReconMode.uuidCount = cfxReconMode.uuidCount + 1
|
cfxReconMode.uuidCount = cfxReconMode.uuidCount + 1
|
||||||
return cfxReconMode.uuidCount
|
return cfxReconMode.uuidCount
|
||||||
@ -163,7 +113,6 @@ function cfxReconMode.addToPrioList(aGroup, dynamic)
|
|||||||
aGroup = aGroup:getName()
|
aGroup = aGroup:getName()
|
||||||
end
|
end
|
||||||
if type(aGroup) == "string" then
|
if type(aGroup) == "string" then
|
||||||
-- table.insert(cfxReconMode.prioList, aGroup)
|
|
||||||
cfxReconMode.prioList[aGroup] = aGroup
|
cfxReconMode.prioList[aGroup] = aGroup
|
||||||
cfxReconMode.dynamics[aGroup] = dynamic
|
cfxReconMode.dynamics[aGroup] = dynamic
|
||||||
end
|
end
|
||||||
@ -176,7 +125,6 @@ function cfxReconMode.addToBlackList(aGroup, dynamic)
|
|||||||
aGroup = aGroup:getName()
|
aGroup = aGroup:getName()
|
||||||
end
|
end
|
||||||
if type(aGroup) == "string" then
|
if type(aGroup) == "string" then
|
||||||
--table.insert(cfxReconMode.blackList, aGroup)
|
|
||||||
cfxReconMode.blackList[aGroup] = aGroup
|
cfxReconMode.blackList[aGroup] = aGroup
|
||||||
cfxReconMode.dynamics[aGroup] = dynamic
|
cfxReconMode.dynamics[aGroup] = dynamic
|
||||||
end
|
end
|
||||||
@ -230,15 +178,9 @@ function cfxReconMode.isStringInList(theString, theList)
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- addScout directly adds a scout unit. Use from external
|
|
||||||
-- to manually add a unit (e.g. via GUI when autoscout isExist
|
|
||||||
-- off, or to force a scout unit (e.g. when scouts for a side
|
|
||||||
-- are not allowed but you still want a unit from that side
|
|
||||||
-- to scout
|
|
||||||
-- since we use a queue for scouts, also always check the
|
-- since we use a queue for scouts, also always check the
|
||||||
-- processed queue before adding to make sure a scout isn't
|
-- processed queue before adding to make sure a scout isn't
|
||||||
-- entered multiple times
|
-- entered multiple times
|
||||||
|
|
||||||
function cfxReconMode.addScout(theUnit)
|
function cfxReconMode.addScout(theUnit)
|
||||||
if not theUnit then
|
if not theUnit then
|
||||||
trigger.action.outText("+++cfxRecon: WARNING - nil Unit on add", 30)
|
trigger.action.outText("+++cfxRecon: WARNING - nil Unit on add", 30)
|
||||||
@ -350,9 +292,9 @@ end
|
|||||||
|
|
||||||
function cfxReconMode.placeMarkForUnit(location, theSide, theGroup)
|
function cfxReconMode.placeMarkForUnit(location, theSide, theGroup)
|
||||||
local theID = cfxReconMode.uuid()
|
local theID = cfxReconMode.uuid()
|
||||||
local theDesc = "Contact: "..theGroup:getName()
|
local theDesc = "Contact"
|
||||||
|
if cfxReconMode.groupNames then theDesc = theDesc .. ": " ..theGroup:getName() end
|
||||||
if cfxReconMode.reportNumbers then
|
if cfxReconMode.reportNumbers then
|
||||||
-- theDesc = theDesc .. " (" .. theGroup:getSize() .. " units)"
|
|
||||||
theDesc = theDesc .. " - " .. cfxReconMode.getSit(theGroup) .. ", " .. cfxReconMode.getAction(theGroup) .. "."
|
theDesc = theDesc .. " - " .. cfxReconMode.getSit(theGroup) .. ", " .. cfxReconMode.getAction(theGroup) .. "."
|
||||||
end
|
end
|
||||||
trigger.action.markToCoalition(
|
trigger.action.markToCoalition(
|
||||||
@ -466,7 +408,9 @@ function cfxReconMode.getTimeData()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function cfxReconMode.generateSALT(theScout, theGroup)
|
function cfxReconMode.generateSALT(theScout, theGroup)
|
||||||
local msg = theScout:getName() .. " reports new ground contact " .. theGroup:getName() .. ":\n"
|
local msg = theScout:getName() .. " reports new ground contact"
|
||||||
|
if cfxReconMode.groupNames then msg = msg .. " " .. theGroup:getName() end
|
||||||
|
msg = msg .. ":\n"
|
||||||
-- SALT: S = Situation or number of units A = action they are doing L = Location T = Time
|
-- SALT: S = Situation or number of units A = action they are doing L = Location T = Time
|
||||||
msg = msg .. cfxReconMode.getSit(theGroup) .. ", "-- S
|
msg = msg .. cfxReconMode.getSit(theGroup) .. ", "-- S
|
||||||
msg = msg .. cfxReconMode.getAction(theGroup) .. ", " -- A
|
msg = msg .. cfxReconMode.getAction(theGroup) .. ", " -- A
|
||||||
@ -559,7 +503,6 @@ function cfxReconMode.detectedGroup(mySide, theScout, theGroup, theLoc)
|
|||||||
|
|
||||||
-- see if it was a prio target
|
-- see if it was a prio target
|
||||||
if inList then
|
if inList then
|
||||||
-- if cfxReconMode.announcer then
|
|
||||||
if cfxReconMode.verbose then
|
if cfxReconMode.verbose then
|
||||||
trigger.action.outText("+++rcn: Priority target spotted", 30)
|
trigger.action.outText("+++rcn: Priority target spotted", 30)
|
||||||
end
|
end
|
||||||
@ -1049,7 +992,7 @@ function cfxReconMode.readConfigZone()
|
|||||||
if theZone:hasProperty("imperialUnits") then
|
if theZone:hasProperty("imperialUnits") then
|
||||||
cfxReconMode.imperialUnits = theZone:getBoolFromZoneProperty( "imperialUnits", false)
|
cfxReconMode.imperialUnits = theZone:getBoolFromZoneProperty( "imperialUnits", false)
|
||||||
end
|
end
|
||||||
|
cfxReconMode.groupNames = theZone:getBoolFromZoneProperty( "groupNames", true)
|
||||||
cfxReconMode.theZone = theZone -- save this zone
|
cfxReconMode.theZone = theZone -- save this zone
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1200,9 +1143,6 @@ if not cfxReconMode.start() then
|
|||||||
cfxReconMode = nil
|
cfxReconMode = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- debug: wire up my own callback
|
|
||||||
-- cfxReconMode.addCallback(cfxReconMode.demoReconCB)
|
|
||||||
|
|
||||||
|
|
||||||
--[[--
|
--[[--
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,16 @@
|
|||||||
sweeper = {}
|
sweeper = {}
|
||||||
sweeper.version = "1.0.0"
|
sweeper.version = "1.0.1"
|
||||||
sweeper.requiredLibs = {
|
sweeper.requiredLibs = {
|
||||||
"dcsCommon",
|
"dcsCommon",
|
||||||
"cfxZones",
|
"cfxZones",
|
||||||
}
|
}
|
||||||
-- remove all units that are detected twice in a row in the same
|
-- remove all units that are detected twice in a row in the same
|
||||||
-- zone after a time interval. Used to remove deadlocked units.
|
-- zone after a time interval. Used to remove deadlocked units.
|
||||||
|
--[[--
|
||||||
|
VERSION HISTORY
|
||||||
|
1.0.1 - Initial version
|
||||||
|
|
||||||
|
--]]--
|
||||||
|
|
||||||
sweeper.zones = {}
|
sweeper.zones = {}
|
||||||
sweeper.interval = 5 * 60 -- 5 mins (max 10 mins) in zone will kill you
|
sweeper.interval = 5 * 60 -- 5 mins (max 10 mins) in zone will kill you
|
||||||
@ -18,7 +23,7 @@ end
|
|||||||
|
|
||||||
function sweeper.readSweeperZone(theZone)
|
function sweeper.readSweeperZone(theZone)
|
||||||
theZone.aircraft = theZone:getBoolFromZoneProperty("aircraft", true)
|
theZone.aircraft = theZone:getBoolFromZoneProperty("aircraft", true)
|
||||||
theZone.helos = theZone:getBoolFromZoneProperty("helos", false)
|
theZone.helos = theZone:getBoolFromZoneProperty("helos", true)
|
||||||
end
|
end
|
||||||
|
|
||||||
function sweeper.update()
|
function sweeper.update()
|
||||||
@ -102,6 +107,16 @@ function sweeper.update()
|
|||||||
sweeper.flights = newFlights
|
sweeper.flights = newFlights
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function sweeper.readConfig()
|
||||||
|
local theZone = cfxZones.getZoneByName("sweeperConfig")
|
||||||
|
if not theZone then
|
||||||
|
theZone = cfxZones.createSimpleZone("sweeperConfig")
|
||||||
|
end
|
||||||
|
sweeper.name = "sweeperConfig" -- zones comaptibility
|
||||||
|
sweeper.interval = theZone:getNumberFromZoneProperty("interval", 5 * 60)
|
||||||
|
sewwper.verbose = theZone.verbose
|
||||||
|
end
|
||||||
|
|
||||||
function sweeper.start()
|
function sweeper.start()
|
||||||
-- lib check
|
-- lib check
|
||||||
if not dcsCommon.libCheck then
|
if not dcsCommon.libCheck then
|
||||||
@ -111,7 +126,9 @@ function sweeper.start()
|
|||||||
if not dcsCommon.libCheck("cfx sweeper", sweeper.requiredLibs) then
|
if not dcsCommon.libCheck("cfx sweeper", sweeper.requiredLibs) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sweeper.readConfig()
|
||||||
|
|
||||||
-- process sweeper Zones
|
-- process sweeper Zones
|
||||||
local attrZones = cfxZones.getZonesWithAttributeNamed("sweeper")
|
local attrZones = cfxZones.getZonesWithAttributeNamed("sweeper")
|
||||||
for k, aZone in pairs(attrZones) do
|
for k, aZone in pairs(attrZones) do
|
||||||
@ -119,7 +136,7 @@ function sweeper.start()
|
|||||||
sweeper.addSweeperZone(aZone) -- add to list
|
sweeper.addSweeperZone(aZone) -- add to list
|
||||||
end
|
end
|
||||||
|
|
||||||
-- start update in 5 seconds
|
-- start update in (interval)
|
||||||
timer.scheduleFunction(sweeper.update, {}, timer.getTime() + sweeper.interval)
|
timer.scheduleFunction(sweeper.update, {}, timer.getTime() + sweeper.interval)
|
||||||
|
|
||||||
-- say hi
|
-- say hi
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
williePete = {}
|
williePete = {}
|
||||||
williePete.version = "2.0.3"
|
williePete.version = "2.0.4"
|
||||||
williePete.ups = 10 -- we update at 10 fps, so accuracy of a
|
williePete.ups = 10 -- we update at 10 fps, so accuracy of a
|
||||||
-- missile moving at Mach 2 is within 33 meters,
|
-- missile moving at Mach 2 is within 33 meters,
|
||||||
-- with interpolation even at 3 meters
|
-- with interpolation even at 3 meters
|
||||||
@ -20,6 +20,7 @@ williePete.requiredLibs = {
|
|||||||
2.0.1 - added Harrier's FFAR M156 WP
|
2.0.1 - added Harrier's FFAR M156 WP
|
||||||
2.0.2 - hardened playerUpdate()
|
2.0.2 - hardened playerUpdate()
|
||||||
2.0.3 - further hardened playerUpdate()
|
2.0.3 - further hardened playerUpdate()
|
||||||
|
2.0.4 - support for the Kiowa's Hydra M259
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
williePete.willies = {}
|
williePete.willies = {}
|
||||||
@ -31,7 +32,8 @@ williePete.blastedObjects = {} -- used when we detonate something
|
|||||||
|
|
||||||
-- recognizes WP munitions. May require regular update when new
|
-- recognizes WP munitions. May require regular update when new
|
||||||
-- models come out.
|
-- models come out.
|
||||||
williePete.smokeWeapons = {"HYDRA_70_M274","HYDRA_70_MK61","HYDRA_70_MK1","HYDRA_70_WTU1B","HYDRA_70_M156","HYDRA_70_M158","BDU_45B","BDU_33","BDU_45","BDU_45LGB","BDU_50HD","BDU_50LD","BDU_50LGB","C_8CM", "SNEB_TYPE254_H1_GREEN", "SNEB_TYPE254_H1_RED", "SNEB_TYPE254_H1_YELLOW", "FFAR M156 WP"}
|
williePete.smokeWeapons = {"HYDRA_70_M274","HYDRA_70_MK61","HYDRA_70_MK1","HYDRA_70_WTU1B","HYDRA_70_M156","HYDRA_70_M158","BDU_45B","BDU_33","BDU_45","BDU_45LGB","BDU_50HD","BDU_50LD","BDU_50LGB","C_8CM", "SNEB_TYPE254_H1_GREEN", "SNEB_TYPE254_H1_RED", "SNEB_TYPE254_H1_YELLOW", "FFAR M156 WP",
|
||||||
|
"HYDRA_70_M259"}
|
||||||
|
|
||||||
function williePete.addWillie(theWillie)
|
function williePete.addWillie(theWillie)
|
||||||
table.insert(williePete.willies, theWillie)
|
table.insert(williePete.willies, theWillie)
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user