Version 1.3.4

New Tacan Zone module
This commit is contained in:
Christian Franz 2023-07-06 13:18:45 +02:00
parent 3f0de87b07
commit a231673292
7 changed files with 647 additions and 17 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
cfxZones = {}
cfxZones.version = "3.1.2"
cfxZones.version = "3.1.3"
-- cf/x zone management module
-- reads dcs zones and makes them accessible and mutable
@ -132,6 +132,11 @@ cfxZones.version = "3.1.2"
- 3.1.1 - getRGBAVectorFromZoneProperty now supports #RRGGBBAA and #RRGGBB format
- owner for all, default 0
- 3.1.2 - getAllZoneProperties has numbersOnly option
- 3.1.3 - new numberArrayFromString()
- new declutterZone()
- new getZoneVolume()
- offsetZone also updates zone bounds when moving zones
- corrected bug in calculateZoneBounds()
--]]--
cfxZones.verbose = false
@ -340,7 +345,8 @@ function cfxZones.calculateZoneBounds(theZone)
if (vertex.x < ll.x) then ll.x = vertex.x; ul.x = vertex.x end
if (vertex.x > lr.x) then lr.x = vertex.x; ur.x = vertex.x end
if (vertex.z < ul.z) then ul.z = vertex.z; ur.z = vertex.z end
if (vertex.z > ll.z) then ll.z = vertex.z; lr.z = vertex.z end
--if (vertex.z > ll.z) then ll.z = vertex.z; lr.z = vertex.z end
if (vertex.z > ur.z) then ur.z = vertex.z; ul.z = vertex.z end
local dp = dcsCommon.dist(theZone.point, vertex)
if dp > pRad then pRad = dp end -- find largst distance to vertex
end
@ -351,6 +357,7 @@ function cfxZones.calculateZoneBounds(theZone)
bounds.lr = lr
bounds.ul = ul
bounds.ur = ur
-- we may need to ascertain why we need ul, ur, ll, lr instead of just ll and ur
-- store pRad
theZone.pRad = pRad -- not sure we'll ever need that, but at least we have it
-- trigger.action.outText("+++Zones: poly zone <" .. theZone.name .. "> has pRad = " .. pRad, 30) -- remember to remove me
@ -804,6 +811,66 @@ function cfxZones.getZonesWithAttributeNamed(attributeName, testZones)
return attributZones
end
--
-- zone volume management
--
function cfxZones.getZoneVolume(theZone)
if not theZone then return nil end
if (theZone.isCircle) then
-- create a sphere volume
local p = cfxZones.getPoint(theZone)
p.y = land.getHeight({x = p.x, y = p.z})
local r = theZone.radius
if r < 10 then r = 10 end
local vol = {
id = world.VolumeType.SPHERE,
params = {
point = p,
radius = r
}
}
return vol
elseif (theZone.isPoly) then
--trigger.action.outText("zne: isPointInside: " .. theZone.name .. " is Polyzone!", 30)
-- build the box volume, using the zone's bounds ll and ur points
local lowerLeft = {}
-- we build x = westerm y = southern, Z = alt
local alt = land.getHeight({x=theZone.bounds.ll.x, y = theZone.bounds.ll.z}) - 10
lowerLeft.x = theZone.bounds.ll.x
lowerLeft.z = theZone.bounds.ll.z
lowerLeft.y = alt -- we go lower
local upperRight = {}
alt = land.getHeight({x=theZone.bounds.ur.x, y = theZone.bounds.ur.z}) + 10
upperRight.x = theZone.bounds.ur.x
upperRight.z = theZone.bounds.ur.z
upperRight.y = alt -- we go higher
-- construct volume
local vol = {
id = world.VolumeType.BOX,
params = {
min = lowerLeft,
max = upperRight
}
}
return vol
else
trigger.action.outText("zne: unknown zone type for <" .. theZone.name .. ">", 30)
end
end
function cfxZones.declutterZone(theZone)
if not theZone then return end
local theVol = cfxZones.getZoneVolume(theZone)
if theZone.verbose then
dcsCommon.dumpVar2Str("vol", theVol)
end
world.removeJunk(theVol)
end
--
-- units / groups in zone
--
@ -924,6 +991,18 @@ function cfxZones.offsetZone(theZone, dx, dz)
theZone.poly[v].x = theZone.poly[v].x + dx
theZone.poly[v].z = theZone.poly[v].z + dz
end
-- update zone bounds
theZone.bounds.ll.x = theZone.bounds.ll.x + dx
theZone.bounds.lr.x = theZone.bounds.lr.x + dx
theZone.bounds.ul.x = theZone.bounds.ul.x + dx
theZone.bounds.ur.x = theZone.bounds.ur.x + dx
theZone.bounds.ll.z = theZone.bounds.ll.z + dz
theZone.bounds.lr.z = theZone.bounds.lr.z + dz
theZone.bounds.ul.z = theZone.bounds.ul.z + dz
theZone.bounds.ur.z = theZone.bounds.ur.z + dz
end
function cfxZones.moveZoneTo(theZone, x, z)
@ -1886,7 +1965,58 @@ function cfxZones.testZoneFlag(theZone, theFlagName, theMethod, latchName)
return testResult, currVal
end
function cfxZones.numberArrayFromString(inString, default)
if not default then default = 0 end
if string.len(inString) < 1 then
trigger.action.outText("+++zne: empty numbers", 30)
return {default, }
end
if cfxZones.verbose then
trigger.action.outText("+++zne: processing <" .. inString .. ">", 30)
end
local flags = {}
local rawElements = dcsCommon.splitString(inString, ",")
-- go over all elements
for idx, anElement in pairs(rawElements) do
anElement = dcsCommon.trim(anElement)
if dcsCommon.stringStartsWithDigit(anElement) and dcsCommon.containsString(anElement, "-") then
-- interpret this as a range
local theRange = dcsCommon.splitString(anElement, "-")
local lowerBound = theRange[1]
lowerBound = tonumber(lowerBound)
local upperBound = theRange[2]
upperBound = tonumber(upperBound)
if lowerBound and upperBound then
-- swap if wrong order
if lowerBound > upperBound then
local temp = upperBound
upperBound = lowerBound
lowerBound = temp
end
-- now add add numbers to flags
for f=lowerBound, upperBound do
table.insert(flags, tostring(f))
end
else
-- bounds illegal
trigger.action.outText("+++zne: ignored range <" .. anElement .. "> (range)", 30)
end
else
-- single number
f = dcsCommon.trim(anElement)
f = tonumber(f)
if f then
table.insert(flags, f)
end
end
end
if #flags < 1 then flags = {default, } end
if cfxZones.verbose then
trigger.action.outText("+++zne: <" .. #flags .. "> flags total", 30)
end
return flags
end
function cfxZones.flagArrayFromString(inString)
-- original code from RND flag

View File

@ -1,5 +1,5 @@
cloneZones = {}
cloneZones.version = "1.7.1"
cloneZones.version = "1.7.3"
cloneZones.verbose = false
cloneZones.requiredLibs = {
"dcsCommon", -- always
@ -94,6 +94,8 @@ cloneZones.respawnOnGroupID = true
1.7.1 - useDelicates handOff for delicates
- forcedRespawn passes zone instead of verbose
1.7.2 - onPerimeter attribute
1.7.3 - declutter option
--]]--
@ -256,6 +258,9 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
end
end
-- declutter
theZone.declutter = cfxZones.getBoolFromZoneProperty(theZone, "declutter", false)
-- watchflags
theZone.cloneTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
@ -1543,6 +1548,14 @@ function cloneZones.spawnWithCloner(theZone)
cloneZones.invokeCallbacks(theZone, "wiped", {})
end
-- declutter?
if theZone.declutter then
cfxZones.declutterZone(theZone)
if theZone.verbose then
trigger.action.outText("+++clnZ: cloner <" .. theZone.name .. "> declutter complete.", 30)
end
end
local theClones, theStatics = cloneZones.spawnWithTemplateForZone(templateZone, theZone)
-- reset hasClones so we know our spawns are full and we can
-- detect complete destruction

View File

@ -1,5 +1,5 @@
dcsCommon = {}
dcsCommon.version = "2.8.9"
dcsCommon.version = "2.8.10"
--[[-- VERSION HISTORY
2.2.6 - compassPositionOfARelativeToB
- clockPositionOfARelativeToB
@ -156,6 +156,13 @@ dcsCommon.version = "2.8.9"
2.8.9 - vAdd supports xy and xyz
- vSub supports xy and xyz
- vMultScalar supports xy and xyz
2.8.10 - tacan2freq now integrated with module (blush)
- array2string cosmetic default
- vMultScalar corrected bug in accessing b.z
- new randomLetter()
- new getPlayerUnit()
- new getMapName()
- new getMagDeclForPoint()
--]]--
@ -2236,13 +2243,14 @@ end
end
function dcsCommon.array2string(inArray, deli)
if not deli then deli = "," end
if not deli then deli = ", " end
if type(inArray) ~= "table" then return "<err in array2string: not an array>" end
local s = ""
local count = 0
for idx, ele in pairs(inArray) do
if count > 0 then s = s .. deli .. " " end
s = s .. ele
count = count + 1
end
return s
end
@ -2475,6 +2483,7 @@ end
end
function dcsCommon.dumpVar2Str(key, value, prefix, inrecursion)
-- dumps to screen, not string
if not inrecursion then
-- output a marker to find in the log / screen
trigger.action.outText("*** dcsCommon vardump START",30)
@ -2599,7 +2608,7 @@ end
end
-- based on buzzer1977's idea, channel is number, eg in 74X, channel is 74, mode is "X"
function tacan2freq(channel, mode)
function dcsCommon.tacan2freq(channel, mode)
if not mode then mode = "X" end
if not channel then channel = 1 end
if type(mode) ~= "string" then mode = "X" end
@ -2712,7 +2721,7 @@ function dcsCommon.vMultScalar(a, f)
if not f then f = 0 end
r.x = a.x * f
r.y = a.y * f
if a.z and b.z then
if a.z then
r.z = a.z * f
end
return r
@ -2812,15 +2821,6 @@ function dcsCommon.isTroopCarrier(theUnit, carriers)
return dcsCommon.isTroopCarrierType(uType, carriers)
end
function dcsCommon.isPlayerUnit(theUnit)
-- new patch. simply check if getPlayerName returns something
if not theUnit then return false end
if not Unit.isExist(theUnit) then return end
if not theUnit.getPlayerName then return false end -- map/static object
local pName = theUnit:getPlayerName()
if pName then return true end
return false
end
function dcsCommon.getAllExistingPlayerUnitsRaw()
local apu = {}
@ -3360,6 +3360,14 @@ function dcsCommon.spellString(inString)
return res
end
dcsCommon.letters = {"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", }
function dcsCommon.randomLetter(lowercase)
local theLetter = dcsCommon.pickRandom(dcsCommon.letters)
if lowercase then theLetter = string.lower(theLetter) end
return theLetter
end
--
-- RGBA from hex
--
@ -3401,6 +3409,55 @@ function dcsCommon.playerName2Coalition(playerName)
return 0
end
function dcsCommon.isPlayerUnit(theUnit)
-- new patch. simply check if getPlayerName returns something
if not theUnit then return false end
if not Unit.isExist(theUnit) then return end
if not theUnit.getPlayerName then return false end -- map/static object
local pName = theUnit:getPlayerName()
if pName then return true end
return false
end
function dcsCommon.getPlayerUnit(name)
for coa = 1, 2 do
local players = coalition.getPlayers(coa)
for idx, theUnit in pairs(players) do
if theUnit:getPlayerName() == name then return theUnit end
end
end
return nil
end
--
-- theater and theater-related stuff
--
function dcsCommon.getMapName()
return env.mission.theatre
end
dcsCommon.magDecls = {Caucasus = 6.5,
MarianaIslands = 1,
Nevada = 12,
PersianGulf = 2,
Syria = 4,
Normandy = -12 -- 1944, -1 in 2016
-- SinaiMap still missing
-- Falklands still missing, big differences
}
function dcsCommon.getMagDeclForPoint(point)
-- WARNING! Approximations only, map-wide, not adjusted for year nor location!
-- serves as a stub for the day when DCS provides correct info
local map = dcsCommon.getMapName()
local decl = dcsCommon.magDecls[map]
if not decl then
trigger.action.outText("+++dcsC: unknown map <" .. map .. ">, using dclenation 0", 30)
decl = 0
end
return decl
end
--
-- iterators
--

430
modules/tacan.lua Normal file
View File

@ -0,0 +1,430 @@
tacan = {}
tacan.version = "1.0.0"
--[[--
Version History
1.0.0 - initial version
--]]--
tacan.verbose = false
tacan.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
}
tacan.tacanZones = {}
function tacan.createTacanZone(theZone)
theZone.onStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", true)
local channels = cfxZones.getStringFromZoneProperty(theZone, "channel", "1")
theZone.channels = cfxZones.numberArrayFromString(channels, 1)
if theZone.verbose or tacan.verbose then
trigger.action.outText("+++tcn: new tacan <" .. theZone.name .. "> for channels [" .. dcsCommon.array2string(theZone.channels, ", ") .. "]", 30)
end
local mode = cfxZones.getStringFromZoneProperty(theZone, "mode", "X")
mode = string.upper(mode)
theZone.modes = cfxZones.flagArrayFromString(mode)
if theZone.verbose or tacan.verbose then
trigger.action.outText("+++tcn: modes [" .. dcsCommon.array2string(theZone.modes, ", ") .. "]", 30)
end
theZone.coa = cfxZones.getCoalitionFromZoneProperty(theZone, "tacan", 0)
theZone.heading = cfxZones.getNumberFromZoneProperty(theZone, "heading", 0)
theZone.heading = theZone.heading * 0.0174533 -- convert to rads
local callsign = cfxZones.getStringFromZoneProperty(theZone, "callsign", "TXN")
callsign = string.upper(callsign)
theZone.callsigns = cfxZones.flagArrayFromString(callsign)
if theZone.verbose or tacan.verbose then
trigger.action.outText("+++tcn: callsigns [" .. dcsCommon.array2string(theZone.callsigns) .. "]", 30)
end
theZone.rndLoc = cfxZones.getBoolFromZoneProperty(theZone, "rndLoc", false)
-- theZone.method = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
theZone.triggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
if cfxZones.hasProperty(theZone, "deploy?") then
theZone.deployFlag = cfxZones.getStringFromZoneProperty(theZone, "deploy?", "<none>")
theZone.lastDeployFlagValue = cfxZones.getFlagValue(theZone.deployFlag, theZone)
end
if (not theZone.deployFlag) and (not theZone.onStart) then
trigger.action.outText("+++tacan: WARNING: tacan zone <> is late activation and has no activation flag, will never activate.", 30)
end
theZone.spawnedTACANS = {} -- for GC and List
theZone.preWipe = cfxZones.getBoolFromZoneProperty(theZone, "preWipe", true)
if cfxZones.hasProperty(theZone, "destroy?") then
theZone.destroyFlag = cfxZones.getStringFromZoneProperty(theZone, "destroy?", "<none>")
theZone.lastDestroyFlagValue = cfxZones.getFlagValue(theZone.destroyFlag, theZone)
end
if cfxZones.hasProperty(theZone, "c#") then
theZone.channelOut = cfxZones.getStringFromZoneProperty(theZone, "C#", "<none>")
end
theZone.announcer = cfxZones.getBoolFromZoneProperty(theZone, "announcer", false)
-- interface to groupTracker
if cfxZones.hasProperty(theZone, "trackWith:") then
theZone.trackWith = cfxZones.getStringFromZoneProperty(theZone, "trackWith:", "<None>")
end
-- see if we need to deploy now
if theZone.onStart then
tacan.TacanFromZone(theZone, true) -- true = silent
end
end
-- hand off to tracker
-- from cloneZones
function tacan.handoffTracking(theGroup, theZone)
if not groupTracker then
trigger.action.outText("+++tacan: <" .. theZone.name .. "> attribute 'trackWith:' requires groupTracker module", 30)
return
end
local trackerName = theZone.trackWith
-- now assemble a list of all trackers
if tacan.verbose or theZone.verbose then
trigger.action.outText("+++tacan: tacan tracked with: " .. trackerName, 30)
end
local trackerNames = {}
if dcsCommon.containsString(trackerName, ',') then
trackerNames = dcsCommon.splitString(trackerName, ',')
else
table.insert(trackerNames, trackerName)
end
for idx, aTrk in pairs(trackerNames) do
local theName = dcsCommon.trim(aTrk)
if theName == "*" then theName = theZone.name end
local theTracker = groupTracker.getTrackerByName(theName)
if not theTracker then
trigger.action.outText("+++tacan: <" .. theZone.name .. ">: cannot find tracker named <".. theName .. ">", 30)
else
groupTracker.addGroupToTracker(theGroup, theTracker)
if tacan.verbose or theZone.verbose then
trigger.action.outText("+++tacan: added " .. theGroup:getName() .. " to tracker " .. theName, 30)
end
end
end
end
-- create a tacan
function tacan.createTacanInZone(theZone, channel, mode, callsign)
local point = cfxZones.getPoint(theZone)
local name = theZone.name
local heading = theZone.heading
local unitID = dcsCommon.numberUUID()
if theZone.rndLoc then
point = cfxZones.createRandomPointInZone(theZone)
end
local data = tacan.buildTacanData(name, channel, mode, callsign, point, unitID, heading)
if theZone.verbose or tacan.verbose then
trigger.action.outText("+++tcn: new TACAN for <" .. theZone.name .. ">: ch<" .. channel .. ">, mode <" .. mode .. ">, call <" .. callsign .. ">", 30)
end
data.thePoint = point -- save location
--local s = dcsCommon.dumpVar2Str("data", data)
local coa = theZone.coa -- neutral
local cty = dcsCommon.getACountryForCoalition(coa)
local theCopy = dcsCommon.clone(data)
local theGroup = coalition.addGroup(cty, Group.Category.GROUND, data)
-- handoff for tracking
if theZone.trackWith then
tacan.handoffTracking(theGroup, theZone)
end
-- add to my spawns for GC to watch over
local t = {}
t.activeMode = mode
t.activeCallsign = callsign
t.activeChan = channel
t.theGroup = theGroup
t.theData = theCopy
table.insert(theZone.spawnedTACANS, t)
-- run a GC cycle
tacan.GC(true)
return theGroup, theCopy
end
function tacan.TacanFromZone(theZone, silent)
local channel = tonumber(dcsCommon.pickRandom(theZone.channels))
local mode = dcsCommon.pickRandom(theZone.modes)
local callsign = dcsCommon.pickRandom(theZone.callsigns)
if theZone.preWipe and theZone.activeTacan then
Group.destroy(theZone.activeTacan)
theZone.activeTacan = nil
end
local theGroup, data = tacan.createTacanInZone(theZone, channel, mode, callsign)
theZone.activeTacan = theGroup
theZone.activeChan = channel
if theZone.channelOut then
trigger.action.setUserFlag(theZone.channelOut, channel)
end
theZone.activeMode = mode
theZone.activeCallsign = callsign
theZone.activeName = data.name
if theGroup then
if theZone.verbose or tacan.verbose then
trigger.action.outText("+++tcn: created tacan <" .. data.name ..">", 30)
end
end
if (not silent) and theZone.announcer then
local str = "NOTAM: Deployed new TACAN " .. theZone.name .. " <" .. callsign .. ">, channel " .. channel .. mode .. ", active now"
if theZone.coa == 0 then
trigger.action.outText(str, 30)
else
trigger.action.outTextForCoalition(theZone.coa, str, 30)
end
end
end
function tacan.destroyTacan(theZone, announce)
if theZone.activeTacan then
Group.destroy(theZone.activeTacan) -- only destroys last allocated
theZone.activeTacan = nil
if announce then
local coa = theZone.coa
local str = "NOTAM: TACAN " .. theZone.name .. " <" .. theZone.activeCallsign .. "> deactivated"
if coa == 0 then
trigger.action.outText(str, 30)
else
trigger.action.outTextForCoalition(coa, str, 30)
end
end
end
if theZone.channelOut then
trigger.action.setUserFlag(theZone.channelOut, 0)
end
end
-- create a TACAN group for the requested TACAN
function tacan.buildTacanData(name, channel, mode, callsign, point, unitID, heading) -- point = (xyz)!
if not heading then heading = 0 end
if not mode then mode = "X" end
mode = string.upper(mode)
local x = point.x
local y = point.z
local alt = land.getHeight({x = x, y = y})
local g = {} -- group
g.name = name .. dcsCommon.numberUUID()
g.x = x
g.y = y
g.tasks = {}
g.task = "Ground Nothing"
local r = {} -- group.route
g.route = r
local p = {} -- group.route.points
r.points = p --
local p1 = {} -- group.route.points[1]
p[1] = p1
p1.alt = alt + 3
p1.x = x
p1.y = y
local t = {} -- group.route.points[1].task
p1.task = t
t.id = "ComboTask"
local params = {} -- group.route.points[1].task.params
t.params = params
local tasks = {} -- group.route.points[1].task.params.tasks
params.tasks = tasks
local t1 = {} -- group.route.points[1].task.params.tasks[1]
tasks[1] = t1
t1.enabled = true
t1.auto = false
t1.id = "WrappedAction"
t1.number = 1
local pm = {} -- group.route.points[1].task.params.tasks[1].params
t1.params = pm
local a = {} -- group.route.points[1].task.params.tasks[1].params.action
pm.action = a
a.id = "ActivateBeacon"
local ps = {} -- group.route.points[1].task.params.tasks[1].params.action.params
a.params = ps
ps.type = 4
ps.AA = false
ps.unitID = unitID
ps.modeChannel = mode
ps.channel = channel
ps.system = 18 -- mysterious
ps.callsign = callsign
ps.bearing = true
ps.frequency = dcsCommon.tacan2freq(channel, mode)
if tacan.verbose then
trigger.action.outText("tacan channel <" .. channel .. "> = freq <" .. ps.frequency .. ">", 30)
end
-- now build unit
local u = {}
g.units = u
local u1 = {}
u[1] = u1
u1.skill = "High"
u1.type = "TACAN_beacon"
u1.x = x
u1.y = y
u1.name = "u_" .. g.name
u1.unitId = unitID
return g -- return data block
end
--
-- Update
--
function tacan.update()
timer.scheduleFunction(tacan.update, {}, timer.getTime() + 1)
for tName, theZone in pairs(tacan.tacanZones) do
-- was start called?
if cfxZones.testZoneFlag(theZone, theZone.deployFlag, theZone.triggerMethod, "lastDeployFlagValue") then
-- we want to deploy and start the tacan.
-- first test if one is still up and running
if theZone.activeTacan and theZone.preWipe then
tacan.destroyTacan(theZone, false)
end
tacan.TacanFromZone(theZone)
end
if cfxZones.testZoneFlag(theZone, theZone.destroyFlag, theZone.triggerMethod, "lastDestroyFlagValue") then
tacan.destroyTacan(theZone, theZone.announcer)
end
end
end
function tacan.GC(singleCall)
if singleCall then
if tacan.verbose then
trigger.action.outText("+++tacan: single-pass GC invoked", 30)
end
else
timer.scheduleFunction(tacan.update, nil, timer.getTime() + 60)
end
for tName, theZone in pairs(tacan.tacanZones) do
local filteredTACANS = {}
for idx, theActive in pairs(theZone.spawnedTACANS) do
-- check if this tacan still exists
local name = theActive.theData.name -- group name
local theGroup = Group.getByName(name)
if theGroup and Group.isExist(theGroup) then
table.insert(filteredTACANS, theActive)
else
if tacan.verbose then
trigger.action.outText("+++tacan: filtered <" .. name .. ">: no longer exist", 30)
end
end
end
theZone.spawnedTACANS = filteredTACANS
end
end
--
-- comms: List TACAN radio command
--
function tacan.installComms()
tacan.redC = missionCommands.addCommandForCoalition(1, "Available TACAN stations", nil, tacan.listTacan, 1)
tacan.blueC = missionCommands.addCommandForCoalition(2, "Available TACAN stations", nil, tacan.listTacan, 2)
end
function tacan.listTacan(side)
timer.scheduleFunction(tacan.doListTacan, side, timer.getTime() + 0.1)
end
function tacan.doListTacan(args)
tacan.GC(true) -- force GC, once.
-- collect all neutral and same (as in args)-side tacans
local theTs = {}
for name, theZone in pairs(tacan.tacanZones) do
if theZone.coa == 0 or theZone.coa == args then
for idx, aTacan in pairs(theZone.spawnedTACANS) do
table.insert(theTs, aTacan)
end
end
end
if #theTs < 1 then
trigger.action.outTextForCoalition(args, "No active TACAN.", 30)
return
end
local msg = "\nActive TACAN:"
for idx, aTacan in pairs(theTs) do
msg = msg .. "\n - " .. aTacan.activeCallsign .. ": " .. aTacan.activeChan .. aTacan.activeMode
end
msg = msg .. "\n"
trigger.action.outTextForCoalition(args, msg, 30)
end
--
-- Start up: config etc
--
function tacan.readConfigZone()
local theZone = cfxZones.getZoneByName("tacanConfig")
if not theZone then theZone = cfxZones.createSimpleZone("tacanConfig") end
tacan.verbose = theZone.verbose
tacan.list = cfxZones.getBoolFromZoneProperty(theZone, "list", false)
if cfxZones.hasProperty(theZone, "GUI") then
tacan.list = cfxZones.getBoolFromZoneProperty(theZone, "GUI", false)
end
if tacan.verbose then
trigger.action.outText("+++tcn: read config", 30)
end
end
function tacan.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("cfx Tacan requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx TACAN",
tacan.requiredLibs) then
return false
end
-- read config
tacan.readConfigZone()
-- set comms
if tacan.list then tacan.installComms() end
-- collect tacan zones
local tZones = cfxZones.zonesWithProperty("tacan")
for k, aZone in pairs(tZones) do
tacan.createTacanZone(aZone)
tacan.tacanZones[aZone.name] = aZone
end
-- start update
tacan.update()
-- start GC
tacan.GC()
-- say Hi!
trigger.action.outText("cfx Tacan v" .. tacan.version .. " started.",30)
end
tacan.start()
--[[--
Ideas
- moving tacan, as in ndb
--]]--

Binary file not shown.