mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 0.992
unitZone xFlags (preview) follow me island defender
This commit is contained in:
parent
a1f5ca8567
commit
a35087c234
Binary file not shown.
Binary file not shown.
@ -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!
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
--
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
272
modules/unitZone.lua
Normal 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
306
modules/xFlags.lua
Normal 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
|
||||
BIN
tutorial & demo missions/demo - follow me!.miz
Normal file
BIN
tutorial & demo missions/demo - follow me!.miz
Normal file
Binary file not shown.
BIN
tutorial & demo missions/full - Island Defender.miz
Normal file
BIN
tutorial & demo missions/full - Island Defender.miz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user