Version 0.992

unitZone
xFlags (preview)
follow me
island defender
This commit is contained in:
Christian Franz 2022-03-10 18:17:33 +01:00
parent a1f5ca8567
commit a35087c234
13 changed files with 751 additions and 19 deletions

Binary file not shown.

Binary file not shown.

View File

@ -202,6 +202,10 @@ function rndFlags.fire(theZone)
local theFlag = table.remove(availableFlags,theFlagIndex)
--rndFlags.pollFlag(theFlag, theZone.rndMethod)
if rndFlags.verbose then
trigger.action.outText("+++RND: polling " .. theFlag .. " with " .. theZone.rndMethod, 30)
end
cfxZones.pollFlag(theFlag, theZone.rndMethod, theZone)
end
@ -309,3 +313,4 @@ if not rndFlags.start() then
rndFlags = nil
end
-- TODO: move flags to RND!, rename RND to RND!, deprecate flags!

View File

@ -1,5 +1,5 @@
cfxSSBClient = {}
cfxSSBClient.version = "2.0.0"
cfxSSBClient.version = "2.0.2"
cfxSSBClient.verbose = false
cfxSSBClient.singleUse = false -- set to true to block crashed planes
-- NOTE: singleUse (true) requires SSB to disable immediate respawn after kick
@ -36,6 +36,7 @@ Version History
- reUseAfter option for single-use
- dcsCommon, cfxZones import
2.0.1 - stricter verbosity: moved more comments to verbose only
2.0.2 - health check code
WHAT IT IS
SSB Client is a small script that forms the client-side counterpart to
@ -232,7 +233,20 @@ function cfxSSBClient.openSlotForCrashedGroupNamed(gName)
end
end
function cfxSSBClient:onEvent(event)
function cfxSSBClient:onEvent(event)
if event.id == 21 then -- S_EVENT_PLAYER_LEAVE_UNIT
trigger.action.outText("+++SSB: Player leave unit", 30)
local theUnit = event.initiator
if not theUnit then
trigger.action.outText("+++SSB: No unit left, abort", 30)
return
end
local curH = theUnit:getLife()
local maxH = theUnit:getLife0()
trigger.action.outText("+++SSB: Health check: " .. curH .. " of " .. maxH, 30)
return
end
if event.id == 10 then -- S_EVENT_BASE_CAPTURED
if cfxSSBClient.verbose then
trigger.action.outText("+++SSB: CAPTURE EVENT -- RESETTING SLOTS", 30)

View File

@ -6,7 +6,7 @@
--
cfxZones = {}
cfxZones.version = "2.5.7"
cfxZones.version = "2.5.8"
--[[-- VERSION HISTORY
- 2.2.4 - getCoalitionFromZoneProperty
- getStringFromZoneProperty
@ -55,6 +55,8 @@ cfxZones.version = "2.5.7"
- randomDelayFromPositiveRange
- isMEFlag
- 2.5.7 - pollFlag supports dml flags
- 2.5.8 - flagArrayFromString
- getFlagNumber invokes tonumber() before returning result
--]]--
cfxZones.verbose = false
@ -117,7 +119,7 @@ function cfxZones.readFromDCS(clearfirst)
return;
end
-- we only retrive the data we need. At this point it is name, location and radius
-- we only retrieve the data we need. At this point it is name, location and radius
-- and put this in our own little structure. we also convert to all upper case name for index
-- and assume that the name may also carry meaning, e.g. 'LZ:' defines a landing zone
-- so we can quickly create other sets from this
@ -1149,30 +1151,85 @@ function cfxZones.getFlagValue(theFlag, theZone)
if type(theFlag) == "number" then
-- straight get, ME flag
return trigger.misc.getUserFlag(theFlag)
return tonumber(trigger.misc.getUserFlag(theFlag))
end
-- we assume it's a string now
theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces
local nFlag = tonumber(theFlag)
if nFlag then
return trigger.misc.getUserFlag(theFlag)
return tonumber(trigger.misc.getUserFlag(theFlag))
end
-- now do wildcard processing. we have alphanumeric
if dcsCommon.stringStartsWith(theFlag, "*") then
theFlag = zoneName .. theFlag
end
return trigger.misc.getUserFlag(theFlag)
return tonumber(trigger.misc.getUserFlag(theFlag))
end
function cfxZones.isMEFlag(inFlag)
-- do NOT use me
trigger.action.outText("+++zne: warning: deprecated isMEFlag", 30)
return true
-- returns true if inFlag is a pure positive number
-- inFlag = dcsCommon.trim(inFlag)
-- return dcsCommon.stringIsPositiveNumber(inFlag)
end
function cfxZones.flagArrayFromString(inString)
-- original code from RND flag
if string.len(inString) < 1 then
trigger.action.outText("+++zne: empty flags", 30)
return {}
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
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) -- DML flag upgrade: accept strings tonumber(anElement)
if f then
table.insert(flags, f)
else
trigger.action.outText("+++zne: ignored element <" .. anElement .. "> (single)", 30)
end
end
end
if cfxZones.verbose then
trigger.action.outText("+++zne: <" .. #flags .. "> flags total", 30)
end
return flags
end
--
-- PROPERTY PROCESSING
--

View File

@ -20,6 +20,7 @@ countDown.requiredLibs = {
1.2.0 - DML Flags
- counterOut!
- ups config
1.2.1 - disableCounter?
--]]--
@ -120,6 +121,13 @@ function countDown.createCountDownWithZone(theZone)
if cfxZones.hasProperty(theZone, "counterOut!") then
theZone.counterOut = cfxZones.getStringFromZoneProperty(theZone, "counterOut!", "<none>")
end
-- disableFlag
theZone.counterDisabled = false
if cfxZones.hasProperty(theZone, "disableCounter?") then
theZone.disableCounterFlag = cfxZones.getStringFromZoneProperty(theZone, "disableCounter?", "<none>")
theZone.disableCounterFlagVal = cfxZones.getFlagValue(theZone.disableCounterFlag, theZone)
end
end
--
@ -195,7 +203,7 @@ function countDown.update()
for idx, aZone in pairs(countDown.counters) do
-- make sure to re-start before reading time limit
if aZone.triggerCountFlag then
if aZone.triggerCountFlag and not aZone.counterDisabled then
local currTriggerVal = cfxZones.getFlagValue(aZone.triggerCountFlag, aZone) -- trigger.misc.getUserFlag(aZone.triggerCountFlag)
if currTriggerVal ~= aZone.lastCountTriggerValue
then
@ -206,6 +214,16 @@ function countDown.update()
aZone.lastCountTriggerValue = cfxZones.getFlagValue(aZone.triggerCountFlag, aZone) -- trigger.misc.getUserFlag(aZone.triggerCountFlag) -- save last value
end
end
if aZone.disableCounterFlag then
local currVal = cfxZones.getFlagValue(aZone.disableCounterFlag, aZone)
if currVal ~= aZone.disableCounterFlagVal then
if countDown.verbose then
trigger.action.outText("+++cntD: disabling counter " .. aZone.name, 30)
end
aZone.counterDisabled = true
end
end
end
end

View File

@ -19,6 +19,7 @@ csarManager.version = "2.0.3"
- 2.0.2 - use parametric csarManager.hoverAlt
- use hoverDuration
- 2.0.3 - corrected bug in hoverDuration
- 2.0.4 - guard in createCSARMission for cfxCommander
--]]--
-- modules that need to be loaded BEFORE I run
@ -28,6 +29,7 @@ csarManager.requiredLibs = {
"cfxPlayer", -- player monitoring and group monitoring
"nameStats", -- generic data module for weight
"cargoSuper",
-- "cfxCommander", -- needed if you want to hand-create CSAR missions
}
-- *** DOES NOT EXTEND ZONES *** BUT USES OWN STRUCT
@ -131,6 +133,11 @@ csarManager.csarCompleteCB = {}
-- CREATING A CSAR
--
function csarManager.createDownedPilot(theMission)
if not cfxCommander then
trigger.action.outText("+++CSAR: can't create mission, module cfxCommander is missing.", 30)
return
end
local aLocation = {}
local aHeading = 0 -- in rads
local newTargetZone = theMission.zone

View File

@ -1,5 +1,5 @@
dcsCommon = {}
dcsCommon.version = "2.5.5"
dcsCommon.version = "2.5.6"
--[[-- VERSION HISTORY
2.2.6 - compassPositionOfARelativeToB
- clockPositionOfARelativeToB
@ -65,6 +65,7 @@ dcsCommon.version = "2.5.5"
2.5.5 - stringStartsWithDigit()
- stringStartsWithLetter()
- stringIsPositiveNumber()
2.5.6 - corrected stringEndsWith() bug with str
--]]--
@ -1740,7 +1741,7 @@ dcsCommon.version = "2.5.5"
end
function dcsCommon.stringEndsWith(theString, theEnding)
return theEnding == "" or str:sub(-#theEnding) == theEnding
return theEnding == "" or theString:sub(-#theEnding) == theEnding
end
function dcsCommon.removeEnding(theString, theEnding)

View File

@ -1,5 +1,5 @@
messenger = {}
messenger.version = "1.1.0"
messenger.version = "1.1.1"
messenger.verbose = false
messenger.requiredLibs = {
"dcsCommon", -- always
@ -15,7 +15,9 @@ messenger.messengers = {}
- clearScreen option
- inValue?
- message preprocessor
1.1.1 - firewalled coalition to msgCoalition
- messageOn?
- messageOff?
--]]--
function messenger.addMessenger(theZone)
@ -36,7 +38,7 @@ end
--
-- read attributes
--
function messenger.createMessengerDownWithZone(theZone)
function messenger.createMessengerWithZone(theZone)
-- start val - a range
theZone.message = cfxZones.getStringFromZoneProperty(theZone, "message", "")
@ -68,9 +70,24 @@ function messenger.createMessengerDownWithZone(theZone)
if theZone.triggerMessagerFlag then
theZone.lastMessageTriggerValue = cfxZones.getFlagValue(theZone.triggerMessagerFlag, theZone)-- trigger.misc.getUserFlag(theZone.triggerMessagerFlag) -- save last value
end
theZone.messageOff = false
if cfxZones.hasProperty(theZone, "messageOff?") then
theZone.messageOffFlag = cfxZones.getStringFromZoneProperty(theZone, "messageOff?", "*none")
theZone.lastMessageOff = cfxZones.getFlagValue(theZone.messageOffFlag, theZone)
end
if cfxZones.hasProperty(theZone, "messageOn?") then
theZone.messageOnFlag = cfxZones.getStringFromZoneProperty(theZone, "messageOn?", "*none")
theZone.lastMessageOn = cfxZones.getFlagValue(theZone.messageOnFlag, theZone)
end
if cfxZones.hasProperty(theZone, "coalition") then
theZone.coalition = cfxZones.getCoalitionFromZoneProperty(theZone, "coalition", 0)
theZone.msgCoalition = cfxZones.getCoalitionFromZoneProperty(theZone, "coalition", 0)
end
if cfxZones.hasProperty(theZone, "msgCoalition") then
theZone.msgCoalition = cfxZones.getCoalitionFromZoneProperty(theZone, "msgCoalition", 0)
end
-- flag whose value can be read
@ -78,6 +95,9 @@ function messenger.createMessengerDownWithZone(theZone)
theZone.messageValue = cfxZones.getStringFromZoneProperty(theZone, "messageValue?", "<none>")
end
if messenger.verbose then
trigger.action.outText("+++Msg: new zone <".. theZone.name .."> will say <".. theZone.message .. ">", 30)
end
end
--
@ -105,15 +125,25 @@ end
function messenger.isTriggered(theZone)
-- this module has triggered
if theZone.messageOff then
if messenger.verbose then
trigger.action.outFlag("msg: message for <".. theZone.name .."> is OFF",30)
end
return
end
local fileName = "l10n/DEFAULT/" .. theZone.soundFile
local msg = messenger.getMessage(theZone)
if messenger.verbose then
trigger.action.outText("+++Msg: <".. theZone.name .."> will say <".. msg .. ">", 30)
end
if theZone.spaceBefore then msg = "\n"..msg end
if theZone.spaceAfter then msg = msg .. "\n" end
if theZone.coalition then
trigger.action.outTextForCoalition(theZone.coalition, msg, theZone.duration, theZone.clearScreen)
trigger.action.outSoundForCoalition(theZone.coalition, fileName)
if theZone.msgCoalition then
trigger.action.outTextForCoalition(theZone.msgCoalition, msg, theZone.duration, theZone.clearScreen)
trigger.action.outSoundForCoalition(theZone.msgCoalition, fileName)
else
-- out to all
trigger.action.outText(msg, theZone.duration, theZone.clearScreen)
@ -132,12 +162,34 @@ function messenger.update()
if currTriggerVal ~= aZone.lastMessageTriggerValue
then
if messenger.verbose then
trigger.action.outText("+++msgr: triggered on in?", 30)
trigger.action.outText("+++msgr: triggered on in? for <".. aZone.name ..">", 30)
end
messenger.isTriggered(aZone)
aZone.lastMessageTriggerValue = cfxZones.getFlagValue(aZone.triggerMessagerFlag, aZone) -- trigger.misc.getUserFlag(aZone.triggerMessagerFlag) -- save last value
end
end
if aZone.messageOffFlag then
local currVal = cfxZones.getFlagValue(aZone.messageOffFlag, aZone)
if currVal ~= aZone.lastMessageOff then
aZone.messageOff = true
aZone.lastMessageOff = currVal
if messenger.verbose then
trigger.action.outText("+++msg: messenger <" .. aZone.name .. "> turned ***OFF***", 30)
end
end
end
if aZone.messageOnFlag then
local currVal = cfxZones.getFlagValue(aZone.messageOnFlag, aZone)
if currVal ~= aZone.lastMessageOn then
aZone.messageOff = false
aZone.lastMessageOn = currVal
if messenger.verbose then
trigger.action.outText("+++msg: messenger <" .. aZone.name .. "> turned ON", 30)
end
end
end
end
end
@ -176,7 +228,7 @@ function messenger.start()
-- process cloner Zones
local attrZones = cfxZones.getZonesWithAttributeNamed("messenger")
for k, aZone in pairs(attrZones) do
messenger.createMessengerDownWithZone(aZone) -- process attributes
messenger.createMessengerWithZone(aZone) -- process attributes
messenger.addMessenger(aZone) -- add to list
end

272
modules/unitZone.lua Normal file
View File

@ -0,0 +1,272 @@
unitZone={}
unitZone.version = "1.0.0"
unitZone.verbose = false
unitZone.ups = 1
unitZone.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
}
unitZone.unitZones = {}
function unitZone.addUnitZone(theZone)
table.insert(unitZone.unitZones, theZone)
end
function unitZone.getUnitZoneByName(aName)
for idx, aZone in pairs(unitZone.unitZones) do
if aName == aZone.name then return aZone end
end
if unitZone.verbose then
trigger.action.outText("+++uZne: no unitZone with name <" .. aName ..">", 30)
end
return nil
end
function unitZone.string2cat(filterString)
if not filterString then return 2 end -- default ground
filterString = filterString:lower()
filterString = dcsCommon.trim(filterString)
local catNum = tonumber(filterString)
if catNum then
if catNum < 0 then catNum = 0 end
if catNum > 4 then catNum = 4 end
return catNum
end
catNum = 2 -- ground default
if dcsCommon.stringStartsWith(filterString, "grou") then catNum = 2 end
if dcsCommon.stringStartsWith(filterString, "air") then catNum = 0 end
if dcsCommon.stringStartsWith(filterString, "hel") then catNum = 1 end
if dcsCommon.stringStartsWith(filterString, "shi") then catNum = 3 end
if dcsCommon.stringStartsWith(filterString, "trai") then catNum = 4 end
return catNum
end
function unitZone.createUnitZone(theZone)
-- start val - a range
theZone.lookFor = cfxZones.getStringFromZoneProperty(theZone, "lookFor", "cfx no unit supplied")
if dcsCommon.stringEndsWith(theZone.lookFor, "*") then
theZone.lookForBeginsWith = true
theZone.lookFor = dcsCommon.removeEnding(theZone.lookFor, "*")
end
theZone.matching = cfxZones.getStringFromZoneProperty(theZone, "matching", "group") -- group, player [, name, type]
theZone.matching = dcsCommon.trim(theZone.matching:lower())
if theZone.matching == "groups" then theZone.matching = "group" end -- some simplification
if theZone.matching == "players" then theZone.matching = "player" end -- some simplification
-- coalition
theZone.uzCoalition = cfxZones.getCoalitionFromZoneProperty(theZone, "coalition", 0) -- 0 = all
if cfxZones.hasProperty(theZone, "uzCoalition") then
cfxZones.uzCoalition = cfxZones.getCoalitionFromZoneProperty(theZone, "uzCoalition", 0)
end
theZone.enterZone = cfxZones.getStringFromZoneProperty(theZone, "enterZone!", "<none>")
theZone.exitZone = cfxZones.getStringFromZoneProperty(theZone, "exitZone!", "<none>")
theZone.changeZone = cfxZones.getStringFromZoneProperty(theZone, "changeZone!", "<none>")
if cfxZones.hasProperty(theZone, "filterFor") then
local filterString = cfxZones.getStringFromZoneProperty(theZone, "filterFor", "1") -- ground
theZone.filterFor = unitZone.string2cat(filterString)
if unitZone.verbose then
trigger.action.outText("+++uZne: filtering " .. theZone.filterFor .. " in " .. theZone.name, 30)
end
end
-- now get initial zone status ?
theZone.lastStatus = unitZone.checkZoneStatus(theZone)
if unitZone.verbose then
trigger.action.outText("+++uZne: processsed unit zone " .. theZone.name, 30)
end
end
--
-- process zone
--
function unitZone.collectGroups(theZone)
local collector = {}
if theZone.matching == "player" then
-- collect all players matching coalition
if theZone.uzCoalition == 1 or theZone.uzCoalition == 0 then
local allPlayers = coalition.getPlayers(1)
for idx, pUnit in pairs(allPlayers) do
table.insert(collector, pUnit)
end
end
if theZone.uzCoalition == 2 or theZone.uzCoalition == 0 then
local allPlayers = coalition.getPlayers(2)
for idx, pUnit in pairs(allPlayers) do
table.insert(collector, pUnit)
end
end
elseif theZone.matching == "group" then
if theZone.uzCoalition == 1 or theZone.uzCoalition == 0 then
local allGroups = coalition.getGroups(1, theZone.filterFor)
for idx, pUnit in pairs(allGroups) do
table.insert(collector, pUnit)
end
end
if theZone.uzCoalition == 2 or theZone.uzCoalition == 0 then
local allGroups = coalition.getGroups(2, theZone.filterFor)
for idx, pUnit in pairs(allGroups) do
table.insert(collector, pUnit)
end
end
else
trigger.action.outText("+++uZne: unknown matching: " .. theZone.matching, 30)
return {}
end
return collector
end
function unitZone.checkZoneStatus(theZone)
-- returns true (at least one unit found in zone)
-- or false (no unit found in zone)
-- collect all groups to inspect
local theGroups = unitZone.collectGroups(theZone)
local lookFor = theZone.lookFor
-- now see if the groups match name and then check inside status for each
local playerCheck = theZone.matching == "player"
if playerCheck then
-- we check the names for players only
for idx, pUnit in pairs(theGroups) do
local puName=pUnit:getName()
local hasMatch = false
if theZone.lookForBeginsWith then
hasMatch = dcsCommon.stringStartsWith(puName, lookFor)
else
hasMatch = puName == lookFor
end
if hasMatch then
if cfxZones.unitInZone(pUnit, theZone) then
return true
end
end
end
else
-- we perform group cehck
for idx, aGroup in pairs(theGroups) do
local gName=aGroup:getName()
local hasMatch = false
if theZone.lookForBeginsWith then
hasMatch = dcsCommon.stringStartsWith(gName, lookFor)
else
hasMatch = gName == lookFor
end
if hasMatch and aGroup:isExist() then
-- check all living units in zone
local gUnits = aGroup:getUnits()
for idy, aUnit in pairs (gUnits) do
--trigger.action.outText("trying " .. gName,10)
if cfxZones.unitInZone(aUnit, theZone) then
return true
end
end
end
end
end
return false
end
--
-- update
--
function unitZone.bangState(theZone, newState)
cfxZones.pollFlag(theZone.changeZone, "inc", theZone)
if newState then
cfxZones.pollFlag(theZone.enterZone, "inc", theZone)
if unitZone.verbose then
trigger.action.outText("+++uZone: banging enter! on <" .. theZone.enterZone .. "> for " .. theZone.name, 30)
end
else
cfxZones.pollFlag(theZone.exitZone, "inc", theZone)
if unitZone.verbose then
trigger.action.outText("+++uZone: banging exit! on <" .. theZone.exitZone .. "> for " .. theZone.name, 30)
end
end
end
function unitZone.update()
-- call me in a second to poll triggers
timer.scheduleFunction(unitZone.update, {}, timer.getTime() + 1/unitZone.ups)
for idx, aZone in pairs(unitZone.unitZones) do
-- scan all zones
local newState = unitZone.checkZoneStatus(aZone)
if newState ~= aZone.lastStatus then
-- bang on change!
unitZone.bangState(aZone, newState)
aZone.lastStatus = newState
end
end
end
--
-- Config & Start
--
function unitZone.readConfigZone()
local theZone = cfxZones.getZoneByName("unitZoneConfig")
if not theZone then
if unitZone.verbose then
trigger.action.outText("+++uZne: NO config zone!", 30)
end
return
end
unitZone.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
unitZone.ups = cfxZones.getNumberFromZoneProperty(theZone, "ups", 1)
if unitZone.verbose then
trigger.action.outText("+++uZne: read config", 30)
end
end
function unitZone.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("cfx Unit Zone requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx Unit Zone", unitZone.requiredLibs) then
return false
end
-- read config
unitZone.readConfigZone()
-- process cloner Zones
local attrZones = cfxZones.getZonesWithAttributeNamed("unitZone")
for k, aZone in pairs(attrZones) do
unitZone.createUnitZone(aZone) -- process attributes
unitZone.addUnitZone(aZone) -- add to list
end
-- start update
unitZone.update()
trigger.action.outText("cfx Unit Zone v" .. unitZone.version .. " started.", 30)
return true
end
-- let's go!
if not unitZone.start() then
trigger.action.outText("cfx Unit Zone aborted: missing libraries", 30)
unitZone = nil
end
--ToDo: add 'neutral' support and add 'both' option
--ToDo: add API

306
modules/xFlags.lua Normal file
View File

@ -0,0 +1,306 @@
xFlags = {}
xFlags.version = "1.0.0"
xFlags.verbose = false
xFlags.ups = 1 -- overwritten in get config!
xFlags.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
}
--[[--
xFlags - flag array transmogrifier
Version History
1.0.0 - Initial version
--]]--
xFlags.xFlagZones = {}
function xFlags.addxFlags(theZone)
table.insert(xFlags.xFlagZones, theZone)
end
--
-- create xFlag
--
function xFlags.reset()
for i = 1, #theZone.flagNames do
-- since the checksum is order dependent,
-- we must preserve the order of the array
local flagName = theZone.flagNames[i]
theZone.startFlagValues[i] = cfxZones.getFlagValue(flagName, theZone)
theZone.flagResults[i] = false
theZone.flagChecksum = theZone.flagChecksum .. "0"
trigger.action.outText("+++xF: flag " .. flagName, 30)
end
theZone.xHasFired = false
end
function xFlags.createXFlagsWithZone(theZone)
local theArray = ""
if cfxZones.hasProperty(theZone, "xFlags") then
theArray = cfxZones.getStringFromZoneProperty(theZone, "xFlags", "<none>")
else
theArray = cfxZones.getStringFromZoneProperty(theZone, "xFlags?", "<none>")
end
-- now process the array and create the value arrays
theZone.flagNames = cfxZones.flagArrayFromString(theArray)
theZone.startFlagValues = {} -- reference/reset time we read these
theZone.flagResults = {} -- individual flag check result
theZone.flagChecksum = "" -- to detect change. is either '0' or 'X'
for i = 1, #theZone.flagNames do
-- since the checksum is order dependent,
-- we must preserve the order of the array
local flagName = theZone.flagNames[i]
theZone.startFlagValues[i] = cfxZones.getFlagValue(flagName, theZone)
theZone.flagResults[i] = false
theZone.flagChecksum = theZone.flagChecksum .. "0"
trigger.action.outText("+++xF: flag " .. flagName, 30)
end
theZone.xHasFired = false
theZone.xSuccess = cfxZones.getStringFromZoneProperty(theZone, "xSuccess!", "<none>")
if cfxZones.hasProperty(theZone, "out!") then
theZone.xSuccess = cfxZones.getStringFromZoneProperty(theZone, "out!", "<none>")
end
if cfxZones.hasProperty(theZone, "xChange!") then
theZone.xChange = cfxZones.getStringFromZoneProperty(theZone, "xChange!", "<none>")
end
theZone.inspect = cfxZones.getStringFromZoneProperty(theZone, "require", "or") -- same as any
-- supported any/or, all/and, moreThan, atLeast, exactly
theZone.inspect = string.lower(theZone.inspect)
theZone.inspect = dcsCommon.trim(theZone.inspect)
theZone.matchNum = cfxZones.getNumberFromZoneProperty(theZone, "#hits", 0)
theZone.lookFor = cfxZones.getStringFromZoneProperty(theZone, "lookFor", "change") -- (<>=[number or reference flag], off, on, yes, no, true, false, change
theZone.lookFor = string.lower(theZone.lookFor)
theZone.lookFor = dcsCommon.trim(theZone.lookFor)
if cfxZones.hasProperty(theZone, "xReset?") then
theZone.xReset = cfxZones.getStringFromZoneProperty(theZone, "xReset?", "<none>")
theZone.xLastReset = cfxZones.getFlagValue(theZone.xReset, theZone)
end
theZone.xMethod = cfxZones.getStringFromZoneProperty(theZone, "xMethod", "flip")
if cfxZones.hasProperty(theZone, "method") then
theZone.xMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "flip")
end
theZone.xOneShot = cfxZones.getBoolFromZoneProperty(theZone, "oneShot", true)
end
function xFlags.evaluateFlags(theZone)
local currVals = {}
-- read new values
for i = 1, #theZone.flagNames do
-- since the checksum is order dependent,
-- we must preserve the order of the array
local flagName = theZone.flagNames[i]
currVals[i] = cfxZones.getFlagValue(flagName, theZone)
end
-- now perform comparison flag by flag
local op = theZone.lookFor
local hits = 0
local checkSum = ""
local firstChar = string.sub(op, 1, 1)
local remainder = string.sub(op, 2)
local rNum = tonumber(remainder)
for i = 1, #theZone.flagNames do
local lastHits = hits
if op == "change" then
-- look for a change in flag line
if currVals[i] ~= theZone.startFlagValues[i] then
hits = hits + 1
checkSum = checkSum .. "X"
else
checkSum = checkSum .. "0"
end
elseif op == "on" or op == "yes" or op == "true" then
if currVals[i] ~= 0 then
hits = hits + 1
checkSum = checkSum .. "X"
else
checkSum = checkSum .. "0"
end
elseif op == "off" or op == "no" or op == "false"
then
if currVals[i] == 0 then
hits = hits + 1
checkSum = checkSum .. "X"
else
checkSum = checkSum .. "0"
end
elseif firstChar == "<" and rNum then
if currVals[i] < rNum then
hits = hits + 1
checkSum = checkSum .. "X"
else
checkSum = checkSum .. "0"
end
elseif firstChar == "=" and rNum then
if currVals[i] == rNum then
hits = hits + 1
checkSum = checkSum .. "X"
else
checkSum = checkSum .. "0"
end
elseif firstChar == ">" and rNum then
if currVals[i] > rNum then
hits = hits + 1
checkSum = checkSum .. "X"
else
checkSum = checkSum .. "0"
end
else
trigger.action.outText("+++xF: unknown lookFor: <" .. op .. ">", 30)
return 0, ""
end
if xFlags.verbose and lastHits ~= hits then
--trigger.action.outText("+++xF: hit detected for " .. theZone.flagNames[i] .. " in " .. theZone.name .. "(" .. op .. ")", 30)
end
end
return hits, checkSum
end
function xFlags.evaluateZone(theZone)
local hits, checkSum = xFlags.evaluateFlags(theZone)
-- depending on inspect see what the outcome is
-- supported any/or, all/and, moreThan, atLeast, exactly
local op = theZone.inspect
local evalResult = false
if (op == "or" or op == "any") and hits > 0 then
evalResult = true
elseif (op == "and" or op == "all") and hits == #theZone.flagNames then
evalResult = true
elseif (op == "morethan" or op == "more than") and hits > theZone.matchNum then
evalResult = true
elseif (op == "atleast" or op == "at lest") and hits >= theZone.matchNum then
evalResult = true
elseif op == "exactly" and hits == theZone.matchNum then
evalResult = true
end
-- now check if changed and if result true
if checkSum ~= theZone.flagChecksum then
if xFlags.verbose then
trigger.action.outText("+++xFlag: change detected for " .. theZone.name .. ": " .. theZone.flagChecksum .. "-->" ..checkSum, 30)
end
if theZone.xChange then
cfxZones.pollFlag(theZone.xChange, theZone.xMethod, theZone)
if xFlags.verbose then
trigger.action.outText("+++xFlag: change bang! on " .. theZone.xChange .. " for " .. theZone.name, 30)
end
end
theZone.flagChecksum = checkSum
end
if theZone.xHasFired and theZone.xOneShot then return end
if evalResult then
if xFlags.verbose then
trigger.action.outText("+++xFlag: success bang! on " .. theZone.xSuccess .. " for " .. theZone.name, 30)
end
cfxZones.pollFlag(theZone.xSuccess, theZone.xMethod, theZone)
theZone.xHasFired = true
end
end
--
-- Update
--
function xFlags.update()
timer.scheduleFunction(xFlags.update, {}, timer.getTime() + 1/xFlags.ups)
for idx, theZone in pairs (xFlags.xFlagZones) do
-- see if they should fire
xFlags.evaluateZone(theZone)
-- see if they should reset
if theZone.xReset then
local currVal = cfxZones.getFlagValue(theZone.xReset, theZone)
if currVal ~= theZone.xLastReset then
theZone.xLastReset = currVal
if xFlags.verbose then
trigger.action.outText("+++xF: reset command for " .. theZone.name, 30)
end
xFlags.reset(theZone)
end
end
end
end
--
-- start
--
function xFlags.readConfigZone()
-- note: must match exactly!!!!
local theZone = cfxZones.getZoneByName("xFlagsConfig")
if not theZone then
if xFlags.verbose then
trigger.action.outText("***xFlg: NO config zone!", 30)
end
return
end
xFlags.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
xFlags.ups = cfxZones.getNumberFromZoneProperty(theZone, "ups", 1)
if xFlags.verbose then
trigger.action.outText("***xFlg: read config", 30)
end
end
function xFlags.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("xFlags requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx xFlags",
xFlags.requiredLibs) then
return false
end
-- read config
xFlags.readConfigZone()
-- process RND Zones
local attrZones = cfxZones.getZonesWithAttributeNamed("xFlags")
-- now create an rnd gen for each one and add them
-- to our watchlist
for k, aZone in pairs(attrZones) do
xFlags.createXFlagsWithZone(aZone) -- process attribute and add to zone
xFlags.addxFlags(aZone) -- remember it
end
local attrZones = cfxZones.getZonesWithAttributeNamed("xFlags?")
-- now create an rnd gen for each one and add them
-- to our watchlist
for k, aZone in pairs(attrZones) do
xFlags.createXFlagsWithZone(aZone) -- process attribute and add to zone
xFlags.addxFlags(aZone) -- remember it
end
-- start update
timer.scheduleFunction(xFlags.update, {}, timer.getTime() + 1/xFlags.ups)
trigger.action.outText("cfx xFlags v" .. xFlags.version .. " started.", 30)
return true
end
-- let's go!
if not xFlags.start() then
trigger.action.outText("cf/x xFlags aborted: missing libraries", 30)
xFlags = nil
end

Binary file not shown.

Binary file not shown.