Version 0.998

xFlags
Radio Trigger
messenger simplification
bang! constants
This commit is contained in:
Christian Franz 2022-04-14 14:37:11 +02:00
parent 2b97597e83
commit 284063b829
18 changed files with 630 additions and 1845 deletions

Binary file not shown.

Binary file not shown.

View File

@ -62,8 +62,6 @@ cfxGroundTroops.deployedTroops = {}
-- 1.7.5 - some troop.group hardening with isExist() -- 1.7.5 - some troop.group hardening with isExist()
-- an entry into the deployed troop has the following attributes -- an entry into the deployed troop has the following attributes
-- - group - the group -- - group - the group
-- - orders: "guard" - will guard the spot and look for enemies in range -- - orders: "guard" - will guard the spot and look for enemies in range

View File

@ -1,5 +1,5 @@
cfxSSBClient = {} cfxSSBClient = {}
cfxSSBClient.version = "2.0.2" cfxSSBClient.version = "2.0.3"
cfxSSBClient.verbose = false cfxSSBClient.verbose = false
cfxSSBClient.singleUse = false -- set to true to block crashed planes cfxSSBClient.singleUse = false -- set to true to block crashed planes
-- NOTE: singleUse (true) requires SSB to disable immediate respawn after kick -- NOTE: singleUse (true) requires SSB to disable immediate respawn after kick
@ -38,6 +38,8 @@ Version History
2.0.1 - stricter verbosity: moved more comments to verbose only 2.0.1 - stricter verbosity: moved more comments to verbose only
2.0.2 - health check code (initial) 2.0.2 - health check code (initial)
- added verbosity - added verbosity
2.0.3 - getPlayerName nil-trap on cloned player planes guard
in onEvent
WHAT IT IS WHAT IT IS
SSB Client is a small script that forms the client-side counterpart to SSB Client is a small script that forms the client-side counterpart to
@ -268,7 +270,12 @@ function cfxSSBClient:onEvent(event)
local theUnit = event.initiator -- we know this exists local theUnit = event.initiator -- we know this exists
local uName = theUnit:getName() local uName = theUnit:getName()
if not uName then return end if not uName then return end
-- player entered unit -- player entered unit?
-- check if this is cloned impostor
if not theUnit.getPlayerName then
trigger.action.outText("+++SSBC: non-player client " .. uName .. " detected, ignoring.", 30)
return
end
local playerName = theUnit:getPlayerName() local playerName = theUnit:getPlayerName()
if not playerName then if not playerName then
return -- NPC plane return -- NPC plane

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,15 @@ changer.changers = {}
Version History Version History
1.0.0 - Initial version 1.0.0 - Initial version
Transmogrify an incoming signal to an output signal
- not
- bool
- value
- rnd
- count (? multiple signals, better done with xFlags)
- min, max minmax 2,3, cap,
--]]-- --]]--
function changer.addChanger(theZone) function changer.addChanger(theZone)
@ -31,50 +40,70 @@ end
-- --
-- read zone -- read zone
-- --
function wiper.createWiperWithZone(theZone) function changer.createChangerWithZone(theZone)
theZone.triggerWiperFlag = cfxZones.getStringFromZoneProperty(theZone, "wipe?", "*<none>") theZone.triggerChangerFlag = cfxZones.getStringFromZoneProperty(theZone, "change?", "*<none>")
-- if theZone.triggerChangerFlag then
theZone.lastTriggerChangeValue = cfxZones.getFlagValue(theZone.triggerChangerFlag, theZone)
-- end
-- triggerWiperMethod -- triggerChangerMethod
theZone.triggerWiperMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change") theZone.triggerChangerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
if cfxZones.hasProperty(theZone, "triggerWiperMethod") then if cfxZones.hasProperty(theZone, "triggerChangerMethod") then
theZone.triggerWiperMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerWiperMethod", "change") theZone.triggerChangerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerChangerMethod", "change")
end end
if theZone.triggerWiperFlag then theZone.inEval = cfxZones.getBoolFromZoneProperty(theZone, "inEval", true) -- yes/no to pre-process, default is yes
theZone.lastTriggerWiperValue = cfxZones.getFlagValue(theZone.triggerWiperFlag, theZone)
theZone.changeTo = cfxZones.getStringFromZoneProperty(theZone, "to", "val") -- val, not, bool
theZone.changeTo = string.lower(theZone.changeTo)
theZone.changeTo = dcsCommon.trim(theZone.changeTo)
theZone.changeOut = cfxZones.getStringFromZoneProperty(theZone, "out!", "*none")
if cfxZones.hasProperty(theZone, "changeOut!") then
theZone.changeOut = cfxZones.getStringFromZoneProperty(theZone, "changeOut!", "*none")
end end
local theCat = cfxZones.getStringFromZoneProperty(theZone, "category", "static") if changer.verbose or theZone.verbose then
if cfxZones.hasProperty(theZone, "wipeCategory") then trigger.action.outText("+++chgr: new changer zone <".. theZone.name ..">", 30)
theCat = cfxZones.getStringFromZoneProperty(theZone, "wipeCategory", "static")
end
if cfxZones.hasProperty(theZone, "wipeCat") then
theCat = cfxZones.getStringFromZoneProperty(theZone, "wipeCat", "static")
end end
theZone.wipeCategory = dcsCommon.string2ObjectCat(theCat)
if cfxZones.hasProperty(theZone, "wipeNamed") then
theZone.wipeNamed = cfxZones.getStringFromZoneProperty(theZone, "wipeNamed", "<no name given>")
if dcsCommon.stringEndsWith(theZone.wipeNamed, "*") then
theZone.wipeNamedBeginsWith = true
theZone.wipeNamed = dcsCommon.removeEnding(theZone.wipeNamed, "*")
end
end
theZone.wipeInventory = cfxZones.getBoolFromZoneProperty(theZone, "wipeInventory", false)
if wiper.verbose or theZone.verbose then
trigger.action.outText("+++wpr: new wiper zone <".. theZone.name ..">", 30)
end
end end
-- --
-- MAIN ACTION -- MAIN ACTION
-- --
function changer.isTriggered(theZone) function changer.process(theZone)
-- read the line
local inVal = cfxZones.getFlagValue(theZone.triggerChangerFlag, theZone)
currVal = inVal
if theZone.inEval then
currVal = cfxZones.evalFlagMethodImmediate(currVal, theZone.triggerChangerMethod, theZone)
end
if type(currVal) == "boolean" then
if currVal then currVal = 1 else currVal = 0 end
end
local res = currVal
local op = theZone.changeTo
-- process and write outflag
if op == "bool" then
if currVal == 0 then res = 0 else res = 1 end
elseif
op == "not" then
if currVal == 0 then res = 1 else res = 0 end
end
-- all others drop through
-- write out
cfxZones.setFlagValueMult(theZone.changeOut, res, theZone)
if changer.verbose or theZone.verbose then
trigger.action.outText("+++chgr: changed <" .. inVal .. "> via op=(" .. op .. ") to <" .. res .. "> for <" .. theZone.name .. ">", 10)
end
-- remember last value in case we need it
theZone.lastTriggerChangeValue = currVal -- we should never need to use this, but leave it in for now. note we save currVal, not res...
end end
@ -87,8 +116,7 @@ function changer.update()
timer.scheduleFunction(changer.update, {}, timer.getTime() + 1/changer.ups) timer.scheduleFunction(changer.update, {}, timer.getTime() + 1/changer.ups)
for idx, aZone in pairs(changer.changers) do for idx, aZone in pairs(changer.changers) do
changer.process(aZone)
end end
end end
@ -114,35 +142,35 @@ function changer.readConfigZone()
end end
end end
function wiper.start() function changer.start()
-- lib check -- lib check
if not dcsCommon.libCheck then if not dcsCommon.libCheck then
trigger.action.outText("cfx Wiper requires dcsCommon", 30) trigger.action.outText("cfx changer requires dcsCommon", 30)
return false return false
end end
if not dcsCommon.libCheck("cfx Wiper", wiper.requiredLibs) then if not dcsCommon.libCheck("cfx changer", changer.requiredLibs) then
return false return false
end end
-- read config -- read config
wiper.readConfigZone() changer.readConfigZone()
-- process cloner Zones -- process cloner Zones
local attrZones = cfxZones.getZonesWithAttributeNamed("wipe?") local attrZones = cfxZones.getZonesWithAttributeNamed("change?")
for k, aZone in pairs(attrZones) do for k, aZone in pairs(attrZones) do
wiper.createWiperWithZone(aZone) -- process attributes changer.createChangerWithZone(aZone) -- process attributes
wiper.addWiper(aZone) -- add to list changer.addChanger(aZone) -- add to list
end end
-- start update -- start update
wiper.update() changer.update()
trigger.action.outText("cfx Wiper v" .. wiper.version .. " started.", 30) trigger.action.outText("cfx Changer v" .. changer.version .. " started.", 30)
return true return true
end end
-- let's go! -- let's go!
if not wiper.start() then if not changer.start() then
trigger.action.outText("cfx Wiper aborted: missing libraries", 30) trigger.action.outText("cfx changer aborted: missing libraries", 30)
wiper = nil changer = nil
end end

View File

@ -69,6 +69,7 @@ dcsCommon.version = "2.5.9"
2.5.7 - point2text(p) 2.5.7 - point2text(p)
2.5.8 - string2GroupCat() 2.5.8 - string2GroupCat()
2.5.9 - string2ObjectCat() 2.5.9 - string2ObjectCat()
2.6.0 - unified uuid, removed uuIdent
--]]-- --]]--
@ -78,6 +79,7 @@ dcsCommon.version = "2.5.9"
dcsCommon.verbose = false -- set to true to see debug messages. Lots of them dcsCommon.verbose = false -- set to true to see debug messages. Lots of them
dcsCommon.uuidStr = "uuid-" dcsCommon.uuidStr = "uuid-"
dcsCommon.simpleUUID = 76543 -- a number to start. as good as any
-- globals -- globals
dcsCommon.cbID = 0 -- callback id for simple callback scheduling dcsCommon.cbID = 0 -- callback id for simple callback scheduling
@ -1896,16 +1898,16 @@ dcsCommon.version = "2.5.9"
end end
dcsCommon.simpleUUID = 76543 -- a number to start. as good as any
function dcsCommon.numberUUID() function dcsCommon.numberUUID()
dcsCommon.simpleUUID = dcsCommon.simpleUUID + 1 dcsCommon.simpleUUID = dcsCommon.simpleUUID + 1
return dcsCommon.simpleUUID return dcsCommon.simpleUUID
end end
function dcsCommon.uuid(prefix) function dcsCommon.uuid(prefix)
dcsCommon.uuIdent = dcsCommon.uuIdent + 1 --dcsCommon.uuIdent = dcsCommon.uuIdent + 1
if not prefix then prefix = dcsCommon.uuidStr end if not prefix then prefix = dcsCommon.uuidStr end
return prefix .. "-" .. dcsCommon.uuIdent return prefix .. "-" .. dcsCommon.numberUUID() -- dcsCommon.uuIdent
end end
function dcsCommon.event2text(id) function dcsCommon.event2text(id)
@ -2194,7 +2196,7 @@ end
-- init any variables the lib requires internally -- init any variables the lib requires internally
function dcsCommon.init() function dcsCommon.init()
cbID = 0 cbID = 0
dcsCommon.uuIdent = 0 --dcsCommon.uuIdent = 0
if (dcsCommon.verbose) or true then if (dcsCommon.verbose) or true then
trigger.action.outText("dcsCommon v" .. dcsCommon.version .. " loaded", 10) trigger.action.outText("dcsCommon v" .. dcsCommon.version .. " loaded", 10)
end end

View File

@ -1,5 +1,5 @@
groupTracker = {} groupTracker = {}
groupTracker.version = "1.1.0" groupTracker.version = "1.1.1"
groupTracker.verbose = false groupTracker.verbose = false
groupTracker.ups = 1 groupTracker.ups = 1
groupTracker.requiredLibs = { groupTracker.requiredLibs = {
@ -14,6 +14,7 @@ groupTracker.trackers = {}
1.1.0 - filtering added 1.1.0 - filtering added
- array support for trackers - array support for trackers
- array support for trackers - array support for trackers
1.1.1 - corrected clone zone reference bug
--]]-- --]]--
@ -199,7 +200,7 @@ function groupTracker.trackGroupsInZone(theZone)
else else
for idy, aGroup in pairs(theGroups) do for idy, aGroup in pairs(theGroups) do
groupTracker.addGroupToTracker(aGroup, theTracker) groupTracker.addGroupToTracker(aGroup, theTracker)
if cloneZones.verbose or theZone.verbose then if groupTracker.verbose or theZone.verbose then
trigger.action.outText("+++gTrk-TW: added " .. theGroup:getName() .. " to tracker " .. theName, 30) trigger.action.outText("+++gTrk-TW: added " .. theGroup:getName() .. " to tracker " .. theName, 30)
end end
end end

View File

@ -1,5 +1,5 @@
messenger = {} messenger = {}
messenger.version = "1.2.1" messenger.version = "1.3.0"
messenger.verbose = false messenger.verbose = false
messenger.requiredLibs = { messenger.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -20,6 +20,7 @@ messenger.messengers = {}
- messageOff? - messageOff?
1.2.0 - msgTriggerMethod (original Watchflag integration) 1.2.0 - msgTriggerMethod (original Watchflag integration)
1.2.1 - qoL: <n> = newline, <z> = zone name, <v> = value 1.2.1 - qoL: <n> = newline, <z> = zone name, <v> = value
1.3.0 - messenger? saves messageOut? attribute
--]]-- --]]--
function messenger.addMessenger(theZone) function messenger.addMessenger(theZone)
@ -56,6 +57,7 @@ end
function messenger.createMessengerWithZone(theZone) function messenger.createMessengerWithZone(theZone)
-- start val - a range -- start val - a range
local aMessage = cfxZones.getStringFromZoneProperty(theZone, "message", "") local aMessage = cfxZones.getStringFromZoneProperty(theZone, "message", "")
theZone.message = messenger.preProcMessage(aMessage, theZone) theZone.message = messenger.preProcMessage(aMessage, theZone)
@ -76,11 +78,14 @@ function messenger.createMessengerWithZone(theZone)
theZone.msgTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "msgTriggerMethod", "change") theZone.msgTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "msgTriggerMethod", "change")
end end
-- trigger flag f? in? messageOut? -- trigger flag f? in? messageOut?, add messenger?
if cfxZones.hasProperty(theZone, "f?") then if cfxZones.hasProperty(theZone, "f?") then
theZone.triggerMessagerFlag = cfxZones.getStringFromZoneProperty(theZone, "f?", "none") theZone.triggerMessagerFlag = cfxZones.getStringFromZoneProperty(theZone, "f?", "none")
-- may want to add deprecated note later
end end
-- can also use in? for counting. we always use triggerMessagerFlag -- can also use in? for counting. we always use triggerMessagerFlag
if cfxZones.hasProperty(theZone, "in?") then if cfxZones.hasProperty(theZone, "in?") then
theZone.triggerMessagerFlag = cfxZones.getStringFromZoneProperty(theZone, "in?", "none") theZone.triggerMessagerFlag = cfxZones.getStringFromZoneProperty(theZone, "in?", "none")
@ -90,9 +95,17 @@ function messenger.createMessengerWithZone(theZone)
theZone.triggerMessagerFlag = cfxZones.getStringFromZoneProperty(theZone, "messageOut?", "none") theZone.triggerMessagerFlag = cfxZones.getStringFromZoneProperty(theZone, "messageOut?", "none")
end end
if theZone.triggerMessagerFlag then -- try default only if no other is set
theZone.lastMessageTriggerValue = cfxZones.getFlagValue(theZone.triggerMessagerFlag, theZone)-- trigger.misc.getUserFlag(theZone.triggerMessagerFlag) -- save last value if not theZone.triggerMessagerFlag then
if not cfxZones.hasProperty(theZone, "messenger?") then
trigger.action.outText("*** Note: messenger in <" .. theZone.name .. "> can't be triggered", 30)
end end
theZone.triggerMessagerFlag = cfxZones.getStringFromZoneProperty(theZone, "messenger?", "none")
end
-- if theZone.triggerMessagerFlag then
theZone.lastMessageTriggerValue = cfxZones.getFlagValue(theZone.triggerMessagerFlag, theZone)-- save last value
-- end
theZone.messageOff = false theZone.messageOff = false
if cfxZones.hasProperty(theZone, "messageOff?") then if cfxZones.hasProperty(theZone, "messageOff?") then
@ -238,13 +251,21 @@ function messenger.start()
-- read config -- read config
messenger.readConfigZone() messenger.readConfigZone()
-- process cloner Zones -- process messenger Zones
-- old style
local attrZones = cfxZones.getZonesWithAttributeNamed("messenger") local attrZones = cfxZones.getZonesWithAttributeNamed("messenger")
for k, aZone in pairs(attrZones) do for k, aZone in pairs(attrZones) do
messenger.createMessengerWithZone(aZone) -- process attributes messenger.createMessengerWithZone(aZone) -- process attributes
messenger.addMessenger(aZone) -- add to list messenger.addMessenger(aZone) -- add to list
end end
-- new style that saves messageOut? flag by reading flags
attrZones = cfxZones.getZonesWithAttributeNamed("messenger?")
for k, aZone in pairs(attrZones) do
messenger.createMessengerWithZone(aZone) -- process attributes
messenger.addMessenger(aZone) -- add to list
end
-- start update -- start update
messenger.update() messenger.update()

127
modules/module template.lua Normal file
View File

@ -0,0 +1,127 @@
tmpl = {}
tmpl.version = "0.0.0"
tmpl.verbose = false
tmpl.ups = 1
tmpl.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
}
tmpl.tmpls = {}
--[[--
Version History
--]]--
function tmpl.addTmpl(theZone)
table.insert(tmpl.tmpls, theZone)
end
function tmpl.getTmplByName(aName)
for idx, aZone in pairs(tmpl.tmpls) do
if aName == aZone.name then return aZone end
end
if tmpl.verbose then
trigger.action.outText("+++tmpl: no tmpl with name <" .. aName ..">", 30)
end
return nil
end
--
-- read zone
--
function tmpl.createTmplWithZone(theZone)
-- read main trigger
theZone.triggerTmplFlag = cfxZones.getStringFromZoneProperty(theZone, "tmpl?", "*<none>")
theZone.lastTriggerTmplValue = cfxZones.getFlagValue(theZone.triggerTmplFlag, theZone)
-- TriggerMethod: common and specific synonym
theZone.tmplTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
if cfxZones.hasProperty(theZone, "tmplTriggerMethod") then
theZone.tmplTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "tmplTriggerMethod", "change")
end
if tmpl.verbose or theZone.verbose then
trigger.action.outText("+++tmpl: new tmpl zone <".. theZone.name ..">", 30)
end
end
--
-- MAIN ACTION
--
function tmpl.process(theZone)
end
--
-- Update
--
function tmpl.update()
-- call me in a second to poll triggers
timer.scheduleFunction(tmpl.update, {}, timer.getTime() + 1/tmpl.ups)
for idx, aZone in pairs(tmpl.tmpls) do
-- see if we are triggered
if cfxZones.testZoneFlag(aZone, aZone.triggerTmplFlag, aZone.tmplTriggerMethod, "lastTriggerTmplValue") then
if tmpl.verbose or theZone.verbose then
trigger.action.outText("+++tmpl: triggered on main? for <".. aZone.name ..">", 30)
end
tmpl.process(aZone)
end
end
end
--
-- Config & Start
--
function tmpl.readConfigZone()
local theZone = cfxZones.getZoneByName("tmplConfig")
if not theZone then
if tmpl.verbose then
trigger.action.outText("+++tmpl: NO config zone!", 30)
end
return
end
tmpl.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
if tmpl.verbose then
trigger.action.outText("+++tmpl: read config", 30)
end
end
function tmpl.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("cfx tmpl requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx tmpl", tmpl.requiredLibs) then
return false
end
-- read config
tmpl.readConfigZone()
-- process tmpl Zones
-- old style
local attrZones = cfxZones.getZonesWithAttributeNamed("tmpl")
for k, aZone in pairs(attrZones) do
tmpl.createTmplWithZone(aZone) -- process attributes
tmpl.addTmpl(aZone) -- add to list
end
-- start update
tmpl.update()
trigger.action.outText("cfx tmpl v" .. tmpl.version .. " started.", 30)
return true
end
-- let's go!
if not tmpl.start() then
trigger.action.outText("cfx tmpl aborted: missing libraries", 30)
tmpl = nil
end

147
modules/radioTrigger.lua Normal file
View File

@ -0,0 +1,147 @@
radioTrigger = {}
radioTrigger.version = "1.0.0"
radioTrigger.verbose = false
radioTrigger.ups = 1
radioTrigger.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
}
radioTrigger.radioTriggers = {}
--[[--
Version History
1.0.0 - initial version
--]]--
function radioTrigger.addRadioTrigger(theZone)
table.insert(radioTrigger.radioTriggers, theZone)
end
function radioTrigger.getRadioTriggerByName(aName)
for idx, aZone in pairs(radioTrigger.radioTriggers) do
if aName == aZone.name then return aZone end
end
if radioTrigger.verbose then
trigger.action.outText("+++radioTrigger: no radioTrigger with name <" .. aName ..">", 30)
end
return nil
end
--
-- read zone
--
function radioTrigger.createRadioTriggerWithZone(theZone)
-- read main trigger
theZone.triggerRadioFlag = cfxZones.getStringFromZoneProperty(theZone, "radio?", "*<none>")
theZone.lastRadioTriggerValue = cfxZones.getFlagValue(theZone.triggerRadioFlag, theZone)
-- TriggerMethod: common and specific synonym
theZone.radioTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
if cfxZones.hasProperty(theZone, "radioTriggerMethod") then
theZone.radioTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "radioTriggerMethod", "change")
end
-- out method
theZone.rtMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
if cfxZones.hasProperty(theZone, "rtMethod") then
theZone.rtMethod = cfxZones.getStringFromZoneProperty(theZone, "rtMethod", "inc")
end
-- out flag
theZone.rtOutFlag = cfxZones.getStringFromZoneProperty(theZone, "out!", "*<none>")
if cfxZones.hasProperty(theZone, "rtOut!") then
theZone.rtOutFlag = cfxZones.getStringFromZoneProperty(theZone, "rtOut!", "*<none>")
end
if radioTrigger.verbose or theZone.verbose then
trigger.action.outText("+++rTrg: new radioTrigger zone <".. theZone.name ..">", 30)
end
end
--
-- MAIN ACTION
--
function radioTrigger.process(theZone)
-- we are triggered, simply poll the out flag
cfxZones.pollFlag(theZone.rtOutFlag, theZone.rtMethod, theZone)
end
--
-- Update
--
function radioTrigger.update()
-- call me in a second to poll triggers
timer.scheduleFunction(radioTrigger.update, {}, timer.getTime() + 1/radioTrigger.ups)
for idx, aZone in pairs(radioTrigger.radioTriggers) do
-- see if we are triggered
local origSave = aZone.lastRadioTriggerValue
if cfxZones.testZoneFlag(aZone, aZone.triggerRadioFlag, aZone.radioTriggerMethod, "lastRadioTriggerValue") then
if radioTrigger.verbose or aZone.verbose then
trigger.action.outText("+++rTrg: triggered on radio? for <".. aZone.name ..">", 30)
end
radioTrigger.process(aZone)
-- now RESET both trigger and last trigger
-- so radio can be used again
cfxZones.setFlagValue(aZone.triggerRadioFlag, origSave, aZone)
aZone.lastRadioTriggerValue = origSave
end
end
end
--
-- Config & Start
--
function radioTrigger.readConfigZone()
local theZone = cfxZones.getZoneByName("radioTriggerConfig")
if not theZone then
if radioTrigger.verbose then
trigger.action.outText("+++radioTrigger: NO config zone!", 30)
end
return
end
radioTrigger.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
if radioTrigger.verbose then
trigger.action.outText("+++radioTrigger: read config", 30)
end
end
function radioTrigger.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("cfx radioTrigger requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx radioTrigger", radioTrigger.requiredLibs) then
return false
end
-- read config
radioTrigger.readConfigZone()
-- process radioTrigger Zones
-- old style
local attrZones = cfxZones.getZonesWithAttributeNamed("radio?")
for k, aZone in pairs(attrZones) do
radioTrigger.createRadioTriggerWithZone(aZone) -- process attributes
radioTrigger.addRadioTrigger(aZone) -- add to list
end
-- start update
radioTrigger.update()
trigger.action.outText("cfx radioTrigger v" .. radioTrigger.version .. " started.", 30)
return true
end
-- let's go!
if not radioTrigger.start() then
trigger.action.outText("cfx radioTrigger aborted: missing libraries", 30)
radioTrigger = nil
end

View File

@ -1,5 +1,5 @@
xFlags = {} xFlags = {}
xFlags.version = "1.2.0" xFlags.version = "1.2.1"
xFlags.verbose = false xFlags.verbose = false
xFlags.ups = 1 -- overwritten in get config when configZone is present xFlags.ups = 1 -- overwritten in get config when configZone is present
xFlags.requiredLibs = { xFlags.requiredLibs = {
@ -15,6 +15,13 @@ xFlags.requiredLibs = {
1.1.0 - Watchflags harmonization 1.1.0 - Watchflags harmonization
1.2.0 - xDirect flag, 1.2.0 - xDirect flag,
- direct array support - direct array support
1.2.1 - verbosity changes
- "most" operator
- "half or more" operator
- fixed reset
- xSuccess optimizations
- inc, dec, quoted flags
- matchNum can carry flag
--]]-- --]]--
xFlags.xFlagZones = {} xFlags.xFlagZones = {}
@ -25,7 +32,7 @@ end
-- --
-- create xFlag -- create xFlag
-- --
function xFlags.reset() function xFlags.reset(theZone)
for i = 1, #theZone.flagNames do for i = 1, #theZone.flagNames do
-- since the checksum is order dependent, -- since the checksum is order dependent,
-- we must preserve the order of the array -- we must preserve the order of the array
@ -33,7 +40,9 @@ function xFlags.reset()
theZone.startFlagValues[i] = cfxZones.getFlagValue(flagName, theZone) theZone.startFlagValues[i] = cfxZones.getFlagValue(flagName, theZone)
theZone.flagResults[i] = false theZone.flagResults[i] = false
theZone.flagChecksum = theZone.flagChecksum .. "0" theZone.flagChecksum = theZone.flagChecksum .. "0"
trigger.action.outText("+++xF: flag " .. flagName, 30) if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xF: zone <" .. theZone.name .. "> flag " .. flagName, 30)
end
end end
theZone.xHasFired = false theZone.xHasFired = false
end end
@ -59,16 +68,23 @@ function xFlags.createXFlagsWithZone(theZone)
theZone.startFlagValues[i] = cfxZones.getFlagValue(flagName, theZone) theZone.startFlagValues[i] = cfxZones.getFlagValue(flagName, theZone)
theZone.flagResults[i] = false theZone.flagResults[i] = false
theZone.flagChecksum = theZone.flagChecksum .. "0" theZone.flagChecksum = theZone.flagChecksum .. "0"
trigger.action.outText("+++xF: flag " .. flagName, 30) if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xFlag: <" .. theZone.name .. "> monitors flag " .. flagName, 30)
end
end end
theZone.xHasFired = false theZone.xHasFired = false
if cfxZones.hasProperty(theZone, "xSuccess!") then
theZone.xSuccess = cfxZones.getStringFromZoneProperty(theZone, "xSuccess!", "<none>") theZone.xSuccess = cfxZones.getStringFromZoneProperty(theZone, "xSuccess!", "<none>")
end
if cfxZones.hasProperty(theZone, "out!") then if cfxZones.hasProperty(theZone, "out!") then
theZone.xSuccess = cfxZones.getStringFromZoneProperty(theZone, "out!", "*<none>") theZone.xSuccess = cfxZones.getStringFromZoneProperty(theZone, "out!", "*<none>")
end end
if not theZone.xSuccess then
theZone.xSuccess = "*<none>"
end
if cfxZones.hasProperty(theZone, "xChange!") then if cfxZones.hasProperty(theZone, "xChange!") then
theZone.xChange = cfxZones.getStringFromZoneProperty(theZone, "xChange!", "*<none>") theZone.xChange = cfxZones.getStringFromZoneProperty(theZone, "xChange!", "*<none>")
end end
@ -80,12 +96,10 @@ function xFlags.createXFlagsWithZone(theZone)
theZone.inspect = string.lower(theZone.inspect) theZone.inspect = string.lower(theZone.inspect)
theZone.inspect = dcsCommon.trim(theZone.inspect) theZone.inspect = dcsCommon.trim(theZone.inspect)
theZone.matchNum = cfxZones.getNumberFromZoneProperty(theZone, "#hits", 0) theZone.matchNum = cfxZones.getStringFromZoneProperty(theZone, "#hits", "1")
theZone.xTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "xFlagMethod", "change") -- (<>=[number or reference flag], off, on, yes, no, true, false, change
theZone.xTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "xTriggerMethod", "change") -- (<>=[number or reference flag], off, on, yes, no, true, false, change
if cfxZones.hasProperty(theZone, "xTrigger") then
theZone.xTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "xTrigger", "change")
end
theZone.xTriggerMethod = string.lower(theZone.xTriggerMethod) theZone.xTriggerMethod = string.lower(theZone.xTriggerMethod)
theZone.xTriggerMethod = dcsCommon.trim(theZone.xTriggerMethod) theZone.xTriggerMethod = dcsCommon.trim(theZone.xTriggerMethod)
@ -102,8 +116,31 @@ function xFlags.createXFlagsWithZone(theZone)
theZone.xOneShot = cfxZones.getBoolFromZoneProperty(theZone, "oneShot", true) theZone.xOneShot = cfxZones.getBoolFromZoneProperty(theZone, "oneShot", true)
end
function xFlags.evaluateNumOrFlag(theAttribute, theZone)
-- on entry, theAttribute contains a string
-- if it's a number, we return that, if it's a
-- string, we see if it's a quoted flag or
-- direct flag. in any way, we fetch and return
-- that flag's value
local aNum = tonumber(theAttribute)
if aNum then return aNum end
local remainder = dcsCommon.trim(theAttribute)
local esc = string.sub(remainder, 1, 1)
local last = string.sub(remainder, -1)
if esc == "(" and last == ")" and string.len(remainder) > 2 then
remainder = string.sub(remainder, 2, -2)
remainder = dcsCommon.trim(remainder)
end
if esc == "\"" and last == "\"" and string.len(remainder) > 2 then
remainder = string.sub(remainder, 2, -2)
remainder = dcsCommon.trim(remainder)
end
rNum = cfxZones.getFlagValue(remainder, theZone)
end end
function xFlags.evaluateFlags(theZone) function xFlags.evaluateFlags(theZone)
@ -122,10 +159,34 @@ function xFlags.evaluateFlags(theZone)
local checkSum = "" local checkSum = ""
local firstChar = string.sub(op, 1, 1) local firstChar = string.sub(op, 1, 1)
local remainder = string.sub(op, 2) local remainder = string.sub(op, 2)
remainder = dcsCommon.trim(remainder) -- remove all leading and trailing spaces
local rNum = tonumber(remainder) local rNum = tonumber(remainder)
if not rNum then if not rNum then
-- interpret remainder as flag name -- interpret remainder as flag name
-- so we can say >*killMax -- so we can say >*killMax or "22" with 22 a flag name
-- we use remainder as name for flag
-- PROCESS ESCAPE SEQUENCES
local esc = string.sub(remainder, 1, 1)
local last = string.sub(remainder, -1)
if esc == "@" then
remainder = string.sub(remainder, 2)
remainder = dcsCommon.trim(remainder)
end
if esc == "(" and last == ")" and string.len(remainder) > 2 then
-- note: iisues with startswith("(") ???
remainder = string.sub(remainder, 2, -2)
remainder = dcsCommon.trim(remainder)
end
if esc == "\"" and last == "\"" and string.len(remainder) > 2 then
remainder = string.sub(remainder, 2, -2)
remainder = dcsCommon.trim(remainder)
end
if cfxZones.verbose then
trigger.action.outText("+++zne: accessing flag <" .. remainder .. ">", 30)
end
rNum = cfxZones.getFlagValue(remainder, theZone) rNum = cfxZones.getFlagValue(remainder, theZone)
end end
@ -142,14 +203,14 @@ function xFlags.evaluateFlags(theZone)
else else
checkSum = checkSum .. "0" checkSum = checkSum .. "0"
end end
elseif op == "on" or op == "yes" or op == "true" then elseif op == "on" or op == "yes" or op == "true" or op == "1" then
if currVals[i] ~= 0 then if currVals[i] ~= 0 then
hits = hits + 1 hits = hits + 1
checkSum = checkSum .. "X" checkSum = checkSum .. "X"
else else
checkSum = checkSum .. "0" checkSum = checkSum .. "0"
end end
elseif op == "off" or op == "no" or op == "false" elseif op == "off" or op == "no" or op == "false" or op == "0"
then then
if currVals[i] == 0 then if currVals[i] == 0 then
hits = hits + 1 hits = hits + 1
@ -158,6 +219,22 @@ function xFlags.evaluateFlags(theZone)
checkSum = checkSum .. "0" checkSum = checkSum .. "0"
end end
elseif op == "inc" or op == "+1" then
if currVals[i] == theZone.startFlagValues[i] + 1 then
hits = hits + 1
checkSum = checkSum .. "X"
else
checkSum = checkSum .. "0"
end
elseif op == "dec" or op == "-1" then
if currVals[i] == theZone.startFlagValues[i] - 1 then
hits = hits + 1
checkSum = checkSum .. "X"
else
checkSum = checkSum .. "0"
end
elseif firstChar == "<" and rNum then elseif firstChar == "<" and rNum then
if currVals[i] < rNum then if currVals[i] < rNum then
hits = hits + 1 hits = hits + 1
@ -183,7 +260,7 @@ function xFlags.evaluateFlags(theZone)
end end
else else
trigger.action.outText("+++xF: unknown xTriggerMethod: <" .. op .. ">", 30) trigger.action.outText("+++xF: unknown xFlagMethod: <" .. op .. ">", 30)
return 0, "" return 0, ""
end end
if xFlags.verbose and lastHits ~= hits then if xFlags.verbose and lastHits ~= hits then
@ -197,6 +274,8 @@ function xFlags.evaluateZone(theZone)
-- short circuit if we are done -- short circuit if we are done
if theZone.xHasFired and theZone.xOneShot then return end if theZone.xHasFired and theZone.xOneShot then return end
-- calculate matchNum
local matchNum = xFlags.evaluateNumOrFlag(theZone.matchNum, theZone) -- convert or fetch
local hits, checkSum = xFlags.evaluateFlags(theZone) local hits, checkSum = xFlags.evaluateFlags(theZone)
-- depending on inspect see what the outcome is -- depending on inspect see what the outcome is
@ -207,21 +286,28 @@ function xFlags.evaluateZone(theZone)
evalResult = true evalResult = true
elseif (op == "and" or op == "all") and hits == #theZone.flagNames then elseif (op == "and" or op == "all") and hits == #theZone.flagNames then
evalResult = true evalResult = true
elseif (op == "morethan" or op == "more than") and hits > theZone.matchNum then elseif (op == "morethan" or op == "more than") and hits > matchNum then
evalResult = true evalResult = true
elseif (op == "atleast" or op == "at least") and hits >= theZone.matchNum then elseif (op == "atleast" or op == "at least") and hits >= matchNum then
evalResult = true evalResult = true
elseif op == "exactly" and hits == theZone.matchNum then elseif op == "exactly" and hits == matchNum then
evalResult = true evalResult = true
elseif (op == "none" or op == "nor") and hits == 0 then elseif (op == "none" or op == "nor") and hits == 0 then
evalResult = true evalResult = true
elseif (op == "not all" or op == "notall" or op == "nand") and hits < #theZone.flagNames then elseif (op == "not all" or op == "notall" or op == "nand") and hits < #theZone.flagNames then
evalResult = true evalResult = true
elseif (op == "most") and hits > (#theZone.flagNames / 2) then
evalResult = true
elseif (op == "half" or op == "at least half" or op == "half or more") and hits >= (#theZone.flagNames / 2) then
-- warning: 'half' means really 'at least half"
evalResult = true
end end
-- add "most" to more than 50% of flagnum
-- now check if changed and if result true -- now check if changed and if result true
if checkSum ~= theZone.flagChecksum then if checkSum ~= theZone.flagChecksum then
if xFlags.verbose then if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xFlag: change detected for " .. theZone.name .. ": " .. theZone.flagChecksum .. "-->" ..checkSum, 30) trigger.action.outText("+++xFlag: change detected for " .. theZone.name .. ": " .. theZone.flagChecksum .. "-->" ..checkSum, 30)
end end
@ -232,6 +318,10 @@ function xFlags.evaluateZone(theZone)
end end
end end
theZone.flagChecksum = checkSum theZone.flagChecksum = checkSum
else
if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xFlag: no change, checksum is |" .. checkSum .. "| for <" .. theZone.name .. ">", 10)
end
end end
-- now directly set the value of evalResult (0 = false, 1 = true) -- now directly set the value of evalResult (0 = false, 1 = true)
@ -246,8 +336,8 @@ function xFlags.evaluateZone(theZone)
-- now see if we bang the output according to method -- now see if we bang the output according to method
if evalResult then if evalResult then
if xFlags.verbose then if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xFlag: success bang! on " .. theZone.xSuccess .. " for " .. theZone.name, 30) trigger.action.outText("+++xFlag: success bang! on <" .. theZone.xSuccess .. "> for <" .. theZone.name .. ">", 30)
end end
cfxZones.pollFlag(theZone.xSuccess, theZone.xMethod, theZone) cfxZones.pollFlag(theZone.xSuccess, theZone.xMethod, theZone)
theZone.xHasFired = true theZone.xHasFired = true
@ -269,8 +359,8 @@ function xFlags.update()
local currVal = cfxZones.getFlagValue(theZone.xReset, theZone) local currVal = cfxZones.getFlagValue(theZone.xReset, theZone)
if currVal ~= theZone.xLastReset then if currVal ~= theZone.xLastReset then
theZone.xLastReset = currVal theZone.xLastReset = currVal
if xFlags.verbose then if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xF: reset command for " .. theZone.name, 30) trigger.action.outText("+++xFlag: reset command for " .. theZone.name, 30)
end end
xFlags.reset(theZone) xFlags.reset(theZone)
end end
@ -285,7 +375,7 @@ function xFlags.readConfigZone()
local theZone = cfxZones.getZoneByName("xFlagsConfig") local theZone = cfxZones.getZoneByName("xFlagsConfig")
if not theZone then if not theZone then
if xFlags.verbose then if xFlags.verbose then
trigger.action.outText("***xFlg: NO config zone!", 30) trigger.action.outText("***xFlag: NO config zone!", 30)
end end
return return
end end
@ -343,3 +433,8 @@ if not xFlags.start() then
trigger.action.outText("cf/x xFlags aborted: missing libraries", 30) trigger.action.outText("cf/x xFlags aborted: missing libraries", 30)
xFlags = nil xFlags = nil
end end
--[[--
Additional features:
- make #hits compatible to flags and numbers
--]]--

Binary file not shown.

Binary file not shown.