Version 1.1.7

autoCSAR
williePete
ssbClient 3.0.0
This commit is contained in:
Christian Franz 2022-10-12 12:33:35 +02:00
parent 4c0b0e8bed
commit 5ec26aaaf1
13 changed files with 369 additions and 137 deletions

Binary file not shown.

Binary file not shown.

View File

@ -27,7 +27,7 @@ function autoCSAR.createNewCSAR(theUnit)
-- unit has no group -- unit has no group
local coa = theUnit:getCoalition() local coa = theUnit:getCoalition()
if coa == 0 then -- neutral if coa == 0 then -- neutral
trigger.action.outText("Neutal Pilot made it safely to ground.", 30) trigger.action.outText("Neutral Pilot made it safely to ground.", 30)
return return
end end
if coa == 1 and not autoCSAR.redCSAR then if coa == 1 and not autoCSAR.redCSAR then

View File

@ -1,5 +1,5 @@
cfxSSBClient = {} cfxSSBClient = {}
cfxSSBClient.version = "2.1.0" cfxSSBClient.version = "3.0.0"
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
@ -19,7 +19,7 @@ Version History
1.1.1 - performance tuning. only read player groups once 1.1.1 - performance tuning. only read player groups once
- and remove in-air-start groups from scan. this requires - and remove in-air-start groups from scan. this requires
- ssb (server) be not modified - ssb (server) be not modified
1.2.0 - API to close airfields: invoke openAirfieldNamed() 1.2.0 - API to close airfields: invoke openAirFieldNamed()
and closeAirfieldNamed() with name as string (exact match required) and closeAirfieldNamed() with name as string (exact match required)
to block an airfield for any player aircraft. to block an airfield for any player aircraft.
Works for FARPS as well Works for FARPS as well
@ -42,6 +42,12 @@ Version History
in onEvent in onEvent
2.1.0 - slotState 2.1.0 - slotState
- persistence - persistence
3.0.0 - closing an airfield will not kick players who are active
- much better verbosity
- open?
- close?
- also persists closed airfield list
WHAT IT IS WHAT IT IS
@ -92,8 +98,59 @@ cfxSSBClient.closedAirfields = {} -- list that closes airfields for any aircraft
cfxSSBClient.playerPlanes = {} -- names of units that a player is flying cfxSSBClient.playerPlanes = {} -- names of units that a player is flying
cfxSSBClient.crashedGroups = {} -- names of groups to block after crash of their player-flown plane cfxSSBClient.crashedGroups = {} -- names of groups to block after crash of their player-flown plane
cfxSSBClient.slotState = {} -- keeps a record of which slot has which value. For persistence and debugging cfxSSBClient.slotState = {} -- keeps a record of which slot has which value. For persistence and debugging
cfxSSBClient.occupiedUnits = {} -- by unit name if occupied to prevent kicking. clears after crash or leaving plane
-- will not be persisted because on start all planes are empty
-- dml zone interface for open/close interface
cfxSSBClient.clientZones = {}
function cfxSSBClient.addClientZone(theZone)
table.insert(cfxSSBClient.clientZones, theZone)
end
function cfxSSBClient.getClientZoneByName(aName)
for idx, aZone in pairs(cfxSSBClient.clientZones) do
if aName == aZone.name then return aZone end
end
if cfxSSBClient.verbose then
trigger.action.outText("+++ssbc: no client zone with name <" .. aName ..">", 30)
end
return nil
end
--
-- read client zones
--
function cfxSSBClient.createClientZone(theZone)
local thePoint = cfxZones.getPoint(theZone)
local theAF = cfxSSBClient.getClosestAirbaseTo(thePoint)
local afName = theAF:getName()
if cfxSSBClient.verbose or theZone.verbose then
trigger.action.outText("+++ssbc: zone <" .. theZone.name .. "> linked to AF/FARP <" .. afName .. ">", 30)
end
theZone.afName = afName
theZone.ssbTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "ssbTriggerMethod", "change")
if cfxZones.hasProperty(theZone, "open?") then
theZone.ssbOpen = cfxZones.getStringFromZoneProperty(theZone, "open?", "none")
theZone.lastSsbOpen = cfxZones.getFlagValue(theZone.ssbOpen, theZone)
end
if cfxZones.hasProperty(theZone, "close?") then
theZone.ssbClose = cfxZones.getStringFromZoneProperty(theZone, "close?", "none")
theZone.lastSsbClose = cfxZones.getFlagValue(theZone.ssbClose, theZone)
end
theZone.ssbOpenOnStart = cfxZones.getBoolFromZoneProperty(theZone, "openOnStart", true)
if not theZone.ssbOpenOnStart then
cfxSSBClient.closeAirfieldNamed(theZone.afName)
end
end
--
-- Open / Close Airfield API
--
function cfxSSBClient.closeAirfieldNamed(name) function cfxSSBClient.closeAirfieldNamed(name)
if not name then return end if not name then return end
cfxSSBClient.closedAirfields[name] = true cfxSSBClient.closedAirfields[name] = true
@ -155,6 +212,25 @@ function cfxSSBClient.setSlotAccessForGroup(theGroup)
if not theGroup then return end if not theGroup then return end
-- WARNING: theGroup is cfxGroup record -- WARNING: theGroup is cfxGroup record
local theName = theGroup.name local theName = theGroup.name
-- we now check if any plane of that group is still
-- existing and in the air. if so, we skip this check
-- to prevent players being kicked for losing their
-- originating airfield
-- we now iterate all playerUnits in theGroup.
-- theGroup is cfxGroup
for idx, playerData in pairs (theGroup.playerUnits) do
local uName = playerData.name
if cfxSSBClient.occupiedUnits[uName] then
if cfxSSBClient.verbose then
trigger.action.outText("+++ssbc: unit <" .. uName .. "> of group <" .. theName .. "> is occupied, no airfield check", 30)
end
return
end
end
-- when we get here, no unit in the entire group is occupied
local theMatchingAirfield = theGroup.airfield local theMatchingAirfield = theGroup.airfield
-- airfield was attached at startup to group -- airfield was attached at startup to group
if cfxSSBClient.singleUse and cfxSSBClient.crashedGroups[theName] then if cfxSSBClient.singleUse and cfxSSBClient.crashedGroups[theName] then
@ -194,11 +270,17 @@ function cfxSSBClient.setSlotAccessForGroup(theGroup)
end end
end end
-- set the ssb flag for this group so the server can see it -- set the ssb flag for this group so the server can see it
if cfxSSBClient.verbose then
local lastState = trigger.misc.getUserFlag(theName)
if lastState ~= blockState then
trigger.action.outText("+++ssbc: <" .. theName .. "> changes from <" .. lastState .. "> to <" .. blockState .. ">", 30)
trigger.action.outText("+++SSB: group ".. theName .. ": " .. comment, 30)
end
end
trigger.action.setUserFlag(theName, blockState) trigger.action.setUserFlag(theName, blockState)
cfxSSBClient.slotState[theName] = blockState cfxSSBClient.slotState[theName] = blockState
if cfxSSBClient.verbose then --if cfxSSBClient.verbose then
trigger.action.outText("+++SSB: group ".. theName .. ": " .. comment, 30) --end
end
else else
if cfxSSBClient.verbose then if cfxSSBClient.verbose then
trigger.action.outText("+++SSB: group ".. theName .. " no bound airfield: available", 30) trigger.action.outText("+++SSB: group ".. theName .. " no bound airfield: available", 30)
@ -206,6 +288,18 @@ function cfxSSBClient.setSlotAccessForGroup(theGroup)
end end
end end
function cfxSSBClient.setSlotAccessForUnit(theUnit) -- calls setSlotAccessForGroup
if not theUnit then return end
local theGroup = theUnit:getGroup()
if not theGroup then return end
local gName = theGroup:getName()
if not gName then return end
local pGroup = cfxSSBClient.getPlayerGroupForGroupNamed(gName)
if pGroup then
cfxSSBClient.setSlotAccessForGroup(pGroup)
end
end
function cfxSSBClient.getPlayerGroupForGroupNamed(aName) function cfxSSBClient.getPlayerGroupForGroupNamed(aName)
local pGroups = cfxSSBClient.playerGroups local pGroups = cfxSSBClient.playerGroups
for idx, theGroup in pairs(pGroups) do for idx, theGroup in pairs(pGroups) do
@ -217,11 +311,10 @@ end
function cfxSSBClient.setSlotAccessByAirfieldOwner() function cfxSSBClient.setSlotAccessByAirfieldOwner()
-- get all groups that have a player-controlled aircraft -- get all groups that have a player-controlled aircraft
-- now uses cached, reduced set of player planes -- now uses cached, reduced set of player planes
local pGroups = cfxSSBClient.playerGroups -- cfxGroups.getPlayerGroup() -- we want the group.name attribute local pGroups = cfxSSBClient.playerGroups
for idx, theGroup in pairs(pGroups) do for idx, theGroup in pairs(pGroups) do
cfxSSBClient.setSlotAccessForGroup(theGroup) cfxSSBClient.setSlotAccessForGroup(theGroup)
end end
end end
function cfxSSBClient.reOpenSlotForGroupNamed(args) function cfxSSBClient.reOpenSlotForGroupNamed(args)
@ -243,9 +336,6 @@ end
function cfxSSBClient:onEvent(event) function cfxSSBClient:onEvent(event)
if event.id == 21 then -- S_EVENT_PLAYER_LEAVE_UNIT if event.id == 21 then -- S_EVENT_PLAYER_LEAVE_UNIT
if cfxSSBClient.verbose then
trigger.action.outText("+++SSB: Player leave unit", 30)
end
local theUnit = event.initiator local theUnit = event.initiator
if not theUnit then if not theUnit then
if cfxSSBClient.verbose then if cfxSSBClient.verbose then
@ -255,30 +345,38 @@ function cfxSSBClient:onEvent(event)
end end
local curH = theUnit:getLife() local curH = theUnit:getLife()
local maxH = theUnit:getLife0() local maxH = theUnit:getLife0()
if cfxSSBClient.verbose then local uName = theUnit:getName()
trigger.action.outText("+++SSB: Health check: " .. curH .. " of " .. maxH, 30) if cfxSSBClient.verbose then
trigger.action.outText("+++SSB: Player leaves unit <" .. uName .. ">", 30)
trigger.action.outText("+++SSB: unit health check: " .. curH .. " of " .. maxH, 30)
end end
cfxSSBClient.occupiedUnits[uName] = nil -- forget I was occupied
cfxSSBClient.setSlotAccessForUnit(theUnit) -- prevent re-slotting if airfield lost
return return
end end
if event.id == 10 then -- S_EVENT_BASE_CAPTURED if event.id == 10 then -- S_EVENT_BASE_CAPTURED
if cfxSSBClient.verbose then if cfxSSBClient.verbose then
trigger.action.outText("+++SSB: CAPTURE EVENT -- RESETTING SLOTS", 30) local place = event.place
trigger.action.outText("+++SSB: CAPTURE EVENT: <" .. place:getName() .. "> now owned by <" .. place:getCoalition() .. "> -- RESETTING SLOTS", 30)
end end
cfxSSBClient.setSlotAccessByAirfieldOwner() cfxSSBClient.setSlotAccessByAirfieldOwner()
end end
-- write down player names and planes -- write down player names and planes
if event.id == 15 then if event.id == 15 then -- birth
--trigger.action.outText("+++SSBC:SU: enter event 15", 30)
if not event.initiator then return end if not event.initiator then return end
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 -- check if this is a cloned impostor
if not theUnit.getPlayerName then if not theUnit.getPlayerName then
trigger.action.outText("+++SSBC: non-player 'client' " .. uName .. " detected, ignoring.", 30) if cfxSSBClient.verbose then
trigger.action.outText("+++SSBC: non-player 'client' " .. uName .. " detected, ignoring.", 30)
end
return return
end end
local playerName = theUnit:getPlayerName() local playerName = theUnit:getPlayerName()
@ -291,12 +389,22 @@ function cfxSSBClient:onEvent(event)
if cfxSSBClient.verbose then if cfxSSBClient.verbose then
trigger.action.outText("+++SSBC:SU: noted " .. playerName .. " piloting player unit " .. uName, 30) trigger.action.outText("+++SSBC:SU: noted " .. playerName .. " piloting player unit " .. uName, 30)
end end
-- mark it as occupied to player won't get kicked until they
-- leave the unit
cfxSSBClient.occupiedUnits[uName] = playerName
return return
end end
if event.id == 5 then -- crash PRE-processing
if not event.initiator then return end
local theUnit = event.initiator
local uName = theUnit:getName()
cfxSSBClient.occupiedUnits[uName] = nil -- no longer occupied
cfxSSBClient.setSlotAccessForUnit(theUnit) -- prevent re-slotting if airfield lost
end
if cfxSSBClient.singleUse and event.id == 5 then -- crash if cfxSSBClient.singleUse and event.id == 5 then -- crash
if not event.initiator then return end --if not event.initiator then return end
local theUnit = event.initiator local theUnit = event.initiator
local uName = theUnit:getName() local uName = theUnit:getName()
if not uName then return end if not uName then return end
@ -321,7 +429,9 @@ function cfxSSBClient:onEvent(event)
-- remember this plane to not re-enable if -- remember this plane to not re-enable if
-- airfield changes hands later -- airfield changes hands later
cfxSSBClient.crashedGroups[gName] = thePilot -- set to crash pilot cfxSSBClient.crashedGroups[gName] = thePilot -- set to crash pilot
trigger.action.outText("+++SSBC:SU: Blocked slot for group <" .. gName .. ">", 30) if cfxSSBClient.verbose then
trigger.action.outText("+++SSBC:SU: Blocked slot for group <" .. gName .. ">", 30)
end
if cfxSSBClient.reUseAfter > 0 then if cfxSSBClient.reUseAfter > 0 then
-- schedule re-opening this slot in <x> seconds -- schedule re-opening this slot in <x> seconds
@ -340,8 +450,38 @@ function cfxSSBClient.update()
-- now establish all slot blocks -- now establish all slot blocks
cfxSSBClient.setSlotAccessByAirfieldOwner() cfxSSBClient.setSlotAccessByAirfieldOwner()
-- show occupied planes
if cfxSSBClient.verbose then
for uName, pName in pairs (cfxSSBClient.occupiedUnits) do
trigger.action.outText("+++ssbc: <" .. uName .. "> occupied by <" .. pName .. ">", 30)
end
end
end end
function cfxSSBClient.dmlUpdate()
-- first, re-schedule me in one second
timer.scheduleFunction(cfxSSBClient.dmlUpdate, {}, timer.getTime() + 1)
for idx, theZone in pairs (cfxSSBClient.clientZones) do
-- see if we received any signals on out inputs
if theZone.ssbOpen and cfxZones.testZoneFlag(theZone, theZone.ssbOpen, theZone.ssbTriggerMethod, "lastSsbOpen") then
if theZone.verbose then
trigger.action.outText("+++ssbc: <" .. theZone.name .. "> open input triggered for <" .. theZone.afName .. ">", 30)
end
cfxSSBClient.openAirFieldNamed(theZone.afName)
end
if theZone.ssbClose and cfxZones.testZoneFlag(theZone, theZone.ssbClose, theZone.ssbTriggerMethod, "lastSsbClose") then
if theZone.verbose then
trigger.action.outText("+++ssbc: <" .. theZone.name .. "> close input triggered for <" .. theZone.afName .. ">", 30)
end
cfxSSBClient.closeAirfieldNamed(theZone.afName)
end
end
end
-- pre-process static player data to minimize -- pre-process static player data to minimize
-- processor load on checks -- processor load on checks
function cfxSSBClient.processPlayerData() function cfxSSBClient.processPlayerData()
@ -376,7 +516,7 @@ function cfxSSBClient.processGroupData()
theAirfield, delta = cfxSSBClient.getClosestAirbaseTo(playerData.point) theAirfield, delta = cfxSSBClient.getClosestAirbaseTo(playerData.point)
local afName = theAirfield:getName() local afName = theAirfield:getName()
if cfxSSBClient.verbose then if cfxSSBClient.verbose then
trigger.action.outText("+++SSB: group: " .. theGroup.name .. " closest to AF " .. afName .. ": " .. delta .. "m" , 30) trigger.action.outText("+++SSB: group: " .. theGroup.name .. " closest to AF " .. afName .. ": " .. math.floor(delta) .. "m" , 30)
end end
if delta > cfxSSBClient.maxAirfieldRange then if delta > cfxSSBClient.maxAirfieldRange then
-- forget airfield -- forget airfield
@ -437,8 +577,10 @@ function cfxSSBClient.saveData()
local theData = {} local theData = {}
local states = dcsCommon.clone(cfxSSBClient.slotState) local states = dcsCommon.clone(cfxSSBClient.slotState)
local crashed = dcsCommon.clone(cfxSSBClient.crashedGroups) local crashed = dcsCommon.clone(cfxSSBClient.crashedGroups)
local closed = dcsCommon.clone(cfxSSBClient.closedAirfields)
theData.states = states theData.states = states
theData.crashed = crashed theData.crashed = crashed
theData.closed = closed
return theData return theData
end end
@ -463,12 +605,17 @@ function cfxSSBClient.loadData()
trigger.action.outText("SSB: blocked <" .. slot .. "> on load", 30) trigger.action.outText("SSB: blocked <" .. slot .. "> on load", 30)
end end
end end
if theData.crashed then
cfxSSBClient.crashedGroups = theData.crashed cfxSSBClient.crashedGroups = theData.crashed
if not cfxSSBClient.crashedGroups then if not cfxSSBClient.crashedGroups then
cfxSSBClient.crashedGroups = {} cfxSSBClient.crashedGroups = {}
trigger.action.outText("SSBClient: nil crashers on load", 30) trigger.action.outText("SSBClient: nil crashers on load", 30)
end end
end
if theData.closed then
cfxSSBClient.closedAirfields = theData.closed
end
end end
@ -495,9 +642,20 @@ function cfxSSBClient.start()
-- into cfxSSBClient.playerGroups -- into cfxSSBClient.playerGroups
cfxSSBClient.processPlayerData() cfxSSBClient.processPlayerData()
-- process ssbc zones
-- for in-mission DML interface
local attrZones = cfxZones.getZonesWithAttributeNamed("ssbClient")
for k, theZone in pairs(attrZones) do
cfxSSBClient.createClientZone(theZone) -- process attributes
cfxSSBClient.addClientZone(theZone) -- add to list
end
-- install a timed update just to make sure -- install a timed update just to make sure
-- and start NOW -- and start NOW
timer.scheduleFunction(cfxSSBClient.update, {}, timer.getTime() + 1) timer.scheduleFunction(cfxSSBClient.update, {}, timer.getTime() + 1)
-- start dml update (on a different timer
cfxSSBClient.dmlUpdate()
-- now turn on ssb -- now turn on ssb
trigger.action.setUserFlag("SSB",100) trigger.action.setUserFlag("SSB",100)
@ -515,7 +673,6 @@ function cfxSSBClient.start()
-- say hi! -- say hi!
trigger.action.outText("cfxSSBClient v".. cfxSSBClient.version .. " running, SBB enabled", 30) trigger.action.outText("cfxSSBClient v".. cfxSSBClient.version .. " running, SBB enabled", 30)
--cfxSSBClient.allYourBase()
return true return true
end end

View File

@ -1,5 +1,5 @@
cfxSmokeZone = {} cfxSmokeZone = {}
cfxSmokeZone.version = "1.1.0" cfxSmokeZone.version = "1.1.1"
cfxSmokeZone.requiredLibs = { cfxSmokeZone.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
"cfxZones", -- Zones, of course "cfxZones", -- Zones, of course
@ -16,16 +16,8 @@ cfxSmokeZone.requiredLibs = {
- alphanum DML flag upgrade - alphanum DML flag upgrade
- random color support - random color support
1.1.0 - Watchflag upgrade 1.1.0 - Watchflag upgrade
1.1.1 - stopSmoke? input
SMOKE ZONES *** EXTENDS ZONES ***
keeps 'eternal' smoke up for any zone that has the
'smoke' attribute
USAGE
add a 'smoke' attribute to the zone. the value of the attribute
defines the color. Valid values are: red, green, blue, white, orange, 0 (results in green smoke), 1 (red smoke), 2 (white), 3 (orange), 4 (blue)
defaults to "green"
altiude is meters above ground height, defaults to 5m
--]]-- --]]--
cfxSmokeZone.smokeZones = {} cfxSmokeZone.smokeZones = {}
cfxSmokeZone.updateDelay = 5 * 60 -- every 5 minutes cfxSmokeZone.updateDelay = 5 * 60 -- every 5 minutes
@ -51,9 +43,7 @@ function cfxSmokeZone.processSmokeZone(aZone)
-- f? query flags -- f? query flags
if cfxZones.hasProperty(aZone, "f?") then if cfxZones.hasProperty(aZone, "f?") then
aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "f?", "*<none>") aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "f?", "*<none>")
end elseif cfxZones.hasProperty(aZone, "startSmoke?") then
if cfxZones.hasProperty(aZone, "startSmoke?") then
aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "startSmoke?", "none") aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "startSmoke?", "none")
end end
@ -61,6 +51,11 @@ function cfxSmokeZone.processSmokeZone(aZone)
aZone.onFlagVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- save last value aZone.onFlagVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- save last value
end end
if cfxZones.hasProperty(aZone, "stopSmoke?") then
aZone.smkStopFlag = cfxZones.getStringFromZoneProperty(aZone, "stopSmoke?", "<none>")
aZone.smkLastStopFlag = cfxZones.getFlagValue(aZone.smkStopFlag, aZone)
end
-- watchflags: -- watchflags:
-- triggerMethod -- triggerMethod
aZone.smokeTriggerMethod = cfxZones.getStringFromZoneProperty(aZone, "triggerMethod", "change") aZone.smokeTriggerMethod = cfxZones.getStringFromZoneProperty(aZone, "triggerMethod", "change")
@ -145,16 +140,13 @@ function cfxSmokeZone.checkFlags()
-- see if this changed -- see if this changed
if cfxZones.testZoneFlag(aZone, aZone.onFlag, aZone.smokeTriggerMethod, "onFlagVal") then if cfxZones.testZoneFlag(aZone, aZone.onFlag, aZone.smokeTriggerMethod, "onFlagVal") then
cfxSmokeZone.startSmoke(aZone) cfxSmokeZone.startSmoke(aZone)
end end
--[[-- end
-- old code
local currTriggerVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- trigger.misc.getUserFlag(aZone.onFlag) if aZone.smkStopFlag then
if currTriggerVal ~= aZone.onFlagVal then if cfxZones.testZoneFlag(aZone, aZone.smkStopFlag, aZone.smokeTriggerMethod, "smkLastStopFlag") then
-- yupp, trigger start aZone.paused = true -- will no longer re-smoke on update
cfxSmokeZone.startSmoke(aZone) end
aZone.onFlagVal = currTriggerVal
end
--]]--
end end
end end
end end

View File

@ -1,5 +1,5 @@
dcsCommon = {} dcsCommon = {}
dcsCommon.version = "2.7.5" dcsCommon.version = "2.7.6"
--[[-- VERSION HISTORY --[[-- VERSION HISTORY
2.2.6 - compassPositionOfARelativeToB 2.2.6 - compassPositionOfARelativeToB
- clockPositionOfARelativeToB - clockPositionOfARelativeToB
@ -104,6 +104,7 @@ dcsCommon.version = "2.7.5"
2.7.5 - new bitAND32() 2.7.5 - new bitAND32()
- new LSR() - new LSR()
- new num2bin() - new num2bin()
2.7.6 - new getObjectsForCatAtPointWithRadius()
--]]-- --]]--
@ -2693,6 +2694,25 @@ function dcsCommon.objectHandler(theObject, theCollector)
return true return true
end end
function dcsCommon.getObjectsForCatAtPointWithRadius(aCat, thePoint, theRadius)
if not aCat then aCat = Object.Category.UNIT end
local p = {x=thePoint.x, y=thePoint.y, z=thePoint.z}
local collector = {}
-- now build the search argument
local args = {
id = world.VolumeType.SPHERE,
params = {
point = p,
radius = theRadius
}
}
-- now call search
world.searchObjects(aCat, args, dcsCommon.objectHandler, collector)
return collector
end
function dcsCommon.getSceneryObjectsInZone(theZone) -- DCS ZONE!!! function dcsCommon.getSceneryObjectsInZone(theZone) -- DCS ZONE!!!
local aCat = 5 -- scenery local aCat = 5 -- scenery
-- WARNING: WE ARE USING DCS ZONES, NOT CFX!!! -- WARNING: WE ARE USING DCS ZONES, NOT CFX!!!

View File

@ -1,5 +1,5 @@
persistence = {} persistence = {}
persistence.version = "1.0.3" persistence.version = "1.0.4"
persistence.ups = 1 -- once every 1 seconds persistence.ups = 1 -- once every 1 seconds
persistence.verbose = false persistence.verbose = false
persistence.active = false persistence.active = false
@ -24,10 +24,11 @@ persistence.requiredLibs = {
1.0.2 - QoL when verbosity is on 1.0.2 - QoL when verbosity is on
1.0.3 - no longer always tells " mission saved to" 1.0.3 - no longer always tells " mission saved to"
new 'saveNotification" can be off new 'saveNotification" can be off
1.0.4 - new optional 'root' property
PROVIDES LOAD/SAVE ABILITY TO MODULES PROVIDES LOAD/SAVE ABILITY TO MODULES
PROVIDES STANDALONE/HOSTED SERVER COMPATIOBILITY PROVIDES STANDALONE/HOSTED SERVER COMPATIBILITY
--]]-- --]]--
@ -255,7 +256,6 @@ function persistence.initFlagsFromData(theFlags)
trigger.action.outText("+++persistence: no flags loaded, commencing mission data load", 30) trigger.action.outText("+++persistence: no flags loaded, commencing mission data load", 30)
end end
end end
function persistence.missionStartDataLoad() function persistence.missionStartDataLoad()
@ -427,7 +427,24 @@ function persistence.readConfigZone()
end end
-- serverDir is the path from the server save directory, usually "Missions/". -- serverDir is the path from the server save directory, usually "Missions/".
-- will be added to lfs.writedir(). -- will be added to lfs.writedir() unless given a root attribute
if cfxZones.hasProperty(theZone, "root") then
-- we split this to enable further processing down the
-- line if neccessary
persistence.root = cfxZones.getStringFromZoneProperty(theZone, "root", lfs.writedir()) -- safe default
if not dcsCommon.stringEndsWith(persistence.root, "\\") then
persistence.root = persistence.root .. "\\"
end
if theZone.verbose then
trigger.action.outText("+++persistence: setting root to <" .. persistence.root .. ">", 30)
end
else
persistence.root = lfs.writedir() -- safe defaulting
if theZone.verbose then
trigger.action.outText("+++persistence: defaulting root to <" .. persistence.root .. ">", 30)
end
end
persistence.serverDir = cfxZones.getStringFromZoneProperty(theZone, "serverDir", "Missions\\") persistence.serverDir = cfxZones.getStringFromZoneProperty(theZone, "serverDir", "Missions\\")
if hasConfig then if hasConfig then
@ -509,13 +526,13 @@ function persistence.start()
end end
end end
local mainDir = lfs.writedir() .. persistence.serverDir -- local mainDir = lfs.writedir() .. persistence.serverDir
local mainDir = persistence.root .. persistence.serverDir
if not dcsCommon.stringEndsWith(mainDir, "\\") then if not dcsCommon.stringEndsWith(mainDir, "\\") then
mainDir = mainDir .. "\\" mainDir = mainDir .. "\\"
end end
-- lets see if we can access the server's mission directory and -- lets see if we can access the server's mission directory and
-- save directory -- save directory
-- we first try to access server's main mission directory, called "mainDir" which is usually <writeDir>/Missions/>
if persistence.isDir(mainDir) then if persistence.isDir(mainDir) then
if persistence.verbose then if persistence.verbose then
@ -563,6 +580,7 @@ function persistence.start()
end end
end end
-- missionDir is root + serverDir + saveDir
persistence.missionDir = missionDir persistence.missionDir = missionDir
persistence.active = true -- we can load and save data persistence.active = true -- we can load and save data

View File

@ -1,7 +1,8 @@
williePete = {} williePete = {}
williePete.version = "1.0.0" williePete.version = "1.0.0"
williePete.ups = 10 -- we update at 10 fps, so accuracy of a williePete.ups = 10 -- we update at 10 fps, so accuracy of a
-- mach two missile is within 33 meters, with interpolation even less -- missile moving at Mach 2 is within 33 meters,
-- with interpolation even at 3 meters
williePete.requiredLibs = { williePete.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -12,8 +13,11 @@ williePete.requiredLibs = {
williePete.willies = {} williePete.willies = {}
williePete.wpZones = {} williePete.wpZones = {}
williePete.playerGUIs = {} -- used for unit guis williePete.playerGUIs = {} -- used for unit guis
williePete.blastedObjects = {} -- used when we detonate something
williePete.smokeWeapons = {"HYDRA_70_M274","HYDRA_70_MK61","HYDRA_70_MK1","HYDRA_70_WTU1B","BDU_45B","BDU_33","BDU_45","BDU_45LGB","BDU_50HD","BDU_50LD","BDU_50LGB","C_8CM"} -- recognizes WP munitions. May require regular update when new
-- models come out.
williePete.smokeWeapons = {"HYDRA_70_M274","HYDRA_70_MK61","HYDRA_70_MK1","HYDRA_70_WTU1B","HYDRA_70_M156","HYDRA_70_M158","BDU_45B","BDU_33","BDU_45","BDU_45LGB","BDU_50HD","BDU_50LD","BDU_50LGB","C_8CM"}
function williePete.addWillie(theWillie) function williePete.addWillie(theWillie)
table.insert(williePete.willies, theWillie) table.insert(williePete.willies, theWillie)
@ -72,8 +76,6 @@ function williePete.getClosestZoneForCoa(point, coa)
currDelta = delta currDelta = delta
closestZone = zData closestZone = zData
end end
else
-- trigger.outText("Zone <" .. zData.name .. ">, coa <" .. zData.coalition .. "> does not match <" .. coa .. ">", 30)
end end
end end
return closestZone, currDelta return closestZone, currDelta
@ -91,19 +93,20 @@ function williePete.createWPZone(aZone)
aZone.readyTime = 0 -- if readyTime > now we are not ready aZone.readyTime = 0 -- if readyTime > now we are not ready
aZone.trackingPlayer = nil -- name player's unit who is being tracked for wp. may not be neccessary aZone.trackingPlayer = nil -- name player's unit who is being tracked for wp. may not be neccessary
aZone.checkedIn = {} -- dict of all planes currently checked in aZone.checkedIn = {} -- dict of all planes currently checked in
aZone.trackingEndsTime = 0 -- if now > trackingends, we remove player and send a message
aZone.wpTriggerMethod = cfxZones.getStringFromZoneProperty(aZone, "wpTriggerMethod", "change") aZone.wpMethod = cfxZones.getStringFromZoneProperty(aZone, "wpMethod", "change")
aZone.FACTypes = cfxZones.getStringFromZoneProperty(aZone, "facTypes", "all")
aZone.checkInRange = cfxZones.getNumberFromZoneProperty(aZone, "checkInRange", williePete.checkInRange) -- default to my default aZone.checkInRange = cfxZones.getNumberFromZoneProperty(aZone, "checkInRange", williePete.checkInRange) -- default to my default
aZone.ackSound = cfxZones.getStringFromZoneProperty(aZone, "ackSound", williePete.ackSound) aZone.ackSound = cfxZones.getStringFromZoneProperty(aZone, "ackSound", williePete.ackSound)
aZone.guiSound = cfxZones.getStringFromZoneProperty(aZone, "guiSound", williePete.guiSound) aZone.guiSound = cfxZones.getStringFromZoneProperty(aZone, "guiSound", williePete.guiSound)
if cfxZones.hasProperty(aZone, "triggerMethod") then if cfxZones.hasProperty(aZone, "method") then
aZone.wpTriggerMethod = cfxZones.getStringFromZoneProperty(aZone, "triggerMethod", "change") aZone.wpMethod = cfxZones.getStringFromZoneProperty(aZone, "method", "change")
end
if cfxZones.hasProperty(aZone, "wpFire!") then
aZone.wpFire = cfxZones.getStringFromZoneProperty(aZone, "wpFire!", "<none)")
end end
if aZone.verbose then if aZone.verbose then
@ -112,7 +115,7 @@ function williePete.createWPZone(aZone)
end end
-- --
-- player management -- PLAYER MANAGEMENT
-- --
function williePete.startPlayerGUI() function williePete.startPlayerGUI()
-- scan all mx players -- scan all mx players
@ -158,22 +161,33 @@ function williePete.startPlayerGUI()
end end
end end
--
-- BOOM
--
-- --
-- BOOM command -- BOOM command
-- --
function williePete.doBoom(args) function williePete.doBoom(args)
local unitInfo = args.unitInfo
if unitInfo then
-- note that unit who commânded fire may no longer be alive
-- so check it every time. unit must be alive
-- to receive credits later
local uName = unitInfo.name
local blastRad = math.floor(math.sqrt(args.strength)) * 2
if blastRad < 10 then blastRad = 10 end
local affectedUnits = dcsCommon.getObjectsForCatAtPointWithRadius(nil, args.point, blastRad)
for idx, aUnit in pairs(affectedUnits) do
local aName = aUnit:getName()
if williePete.verbose then
trigger.action.outText("<" .. aName .. "> is in blast Radius (" .. blastRad .. "m) of shells for <" .. uName .. ">'s target coords", 30)
end
williePete.blastedObjects[aName] = uName -- last one gets the kill
end
end
trigger.action.explosion(args.point, args.strength) trigger.action.explosion(args.point, args.strength)
data = {}
data.point = args.point
data.strength = args.strength
-- cfxArtilleryZones.invokeCallbacksFor('impact', args.zone, data)
end end
function williePete.doParametricFireAt(aPoint, accuracy, shellNum, shellBaseStrength, shellVariance, transitionTime) function williePete.doParametricFireAt(aPoint, accuracy, shellNum, shellBaseStrength, shellVariance, transitionTime, unitInfo)
if williePete.verbose then if williePete.verbose then
trigger.action.outText("fire with accuracy <" .. accuracy .. "> shellNum <" .. shellNum .. "> baseStren <" .. shellBaseStrength .. "> variance <" .. shellVariance .. ">, ttime <" .. transitionTime .. ">", 30) trigger.action.outText("fire with accuracy <" .. accuracy .. "> shellNum <" .. shellNum .. "> baseStren <" .. shellBaseStrength .. "> variance <" .. shellVariance .. ">, ttime <" .. transitionTime .. ">", 30)
end end
@ -200,6 +214,7 @@ function williePete.doParametricFireAt(aPoint, accuracy, shellNum, shellBaseStre
thePoint.y = land.getHeight({x = thePoint.x, y = thePoint.z}) + 1 -- elevate to ground height + 1 thePoint.y = land.getHeight({x = thePoint.x, y = thePoint.z}) + 1 -- elevate to ground height + 1
boomArgs.point = thePoint boomArgs.point = thePoint
boomArgs.zone = aZone boomArgs.zone = aZone
boomArgs.unitInfo = unitInfo
local timeVar = 5 * (2 * dcsCommon.randomPercent() - 1.0) -- +/- 1.5 seconds local timeVar = 5 * (2 * dcsCommon.randomPercent() - 1.0) -- +/- 1.5 seconds
if timeVar < 0 then timeVar = -timeVar end if timeVar < 0 then timeVar = -timeVar end
@ -218,6 +233,12 @@ end
function williePete.doCheckIn(unitInfo) function williePete.doCheckIn(unitInfo)
--trigger.action.outText("check-in received", 30) --trigger.action.outText("check-in received", 30)
local theUnit = Unit.getByName(unitInfo.name) local theUnit = Unit.getByName(unitInfo.name)
if not theUnit then
-- dead man calling. Pilot dead but unit still alive
trigger.action.outText("Calling station, say again, can't read you.", 30)
return
end
local p = theUnit:getPoint() local p = theUnit:getPoint()
local theZone, dist = williePete.closestCheckInTgtZoneForCoa(p, unitInfo.coa) local theZone, dist = williePete.closestCheckInTgtZoneForCoa(p, unitInfo.coa)
@ -245,12 +266,12 @@ function williePete.doCheckIn(unitInfo)
theZone.checkedIn[unitInfo.name] = unitInfo theZone.checkedIn[unitInfo.name] = unitInfo
-- add the 'Target marked' menu -- add the 'Target marked' menu
unitInfo.targetMarked = missionCommands.addCommandForGroup(unitInfo.gID, "Target Marked", unitInfo.root, williePete.redirectTargetMarked, unitInfo) unitInfo.targetMarked = missionCommands.addCommandForGroup(unitInfo.gID, "Target Marked, commence firing", unitInfo.root, williePete.redirectTargetMarked, unitInfo)
-- remove 'check in' -- remove 'check in'
missionCommands.removeItemForGroup(unitInfo.gID, unitInfo.checkIn) missionCommands.removeItemForGroup(unitInfo.gID, unitInfo.checkIn)
unitInfo.checkIn = nil unitInfo.checkIn = nil
-- add 'check out' -- add 'check out'
unitInfo.checkOut = missionCommands.addCommandForGroup(unitInfo.gID, "Check Out", unitInfo.root, williePete.redirectCheckOut, unitInfo) unitInfo.checkOut = missionCommands.addCommandForGroup(unitInfo.gID, "Check Out of " .. theZone.name, unitInfo.root, williePete.redirectCheckOut, unitInfo)
trigger.action.outTextForGroup(unitInfo.gID, "Roger " .. unitInfo.name .. ", " .. theZone.name .. " tracks you, standing by for target data.", 30) trigger.action.outTextForGroup(unitInfo.gID, "Roger " .. unitInfo.name .. ", " .. theZone.name .. " tracks you, standing by for target data.", 30)
trigger.action.outSoundForGroup(unitInfo.gID, theZone.guiSound) trigger.action.outSoundForGroup(unitInfo.gID, theZone.guiSound)
@ -261,8 +282,6 @@ function williePete.redirectCheckOut(unitInfo)
end end
function williePete.doCheckOut(unitInfo) function williePete.doCheckOut(unitInfo)
--trigger.action.outText("check-out received", 30)
-- check out of all zones -- check out of all zones
local wasCheckedIn = false local wasCheckedIn = false
local fromZone = "" local fromZone = ""
@ -305,10 +324,15 @@ function williePete.rogerDodger(args)
end end
function williePete.doTargetMarked(unitInfo) function williePete.doTargetMarked(unitInfo)
--trigger.action.outText("mark received", 30)
-- first, check if we are past the time-out -- first, check if we are past the time-out
local now = timer.getTime() local now = timer.getTime()
if not unitInfo.wpInZone then
trigger.action.outTextForGroup(unitInfo.gID, "No target mark visible, please mark again", 30)
trigger.action.outSoundForGroup(unitInfo.gID, williePete.guiSound)
return
end
-- now check if zone matches check-in -- now check if zone matches check-in
if not unitInfo.expiryTime or unitInfo.expiryTime < now then if not unitInfo.expiryTime or unitInfo.expiryTime < now then
trigger.action.outTextForGroup(unitInfo.gID, "Target mark stale or ambiguous, set fresh mark", 30) trigger.action.outTextForGroup(unitInfo.gID, "Target mark stale or ambiguous, set fresh mark", 30)
@ -357,13 +381,15 @@ function williePete.doTargetMarked(unitInfo)
local transitionTime = tgtZone.transitionTime local transitionTime = tgtZone.transitionTime
local accuracy = tgtZone.baseAccuracy local accuracy = tgtZone.baseAccuracy
williePete.doParametricFireAt(unitInfo.pos, accuracy, shellNum, shellStrength, 0.2, transitionTime) williePete.doParametricFireAt(unitInfo.pos, accuracy, shellNum, shellStrength, 0.2, transitionTime, unitInfo)
-- set zone's cooldown -- set zone's cooldown
tgtZone.readyTime = now + tgtZone.coolDown tgtZone.readyTime = now + tgtZone.coolDown
-- erase player's wp mark
unitInfo.wpInZone = nil -- if we have an output, trigger it now
unitInfo.pos = nil if tgtZone.wpFire then
cfxZones.pollFlag(tgtZone.wpFire, tgtZone.wpMethod, tgtZone)
end
end end
-- return true if a zone is actively tracking theUnit to place -- return true if a zone is actively tracking theUnit to place
-- a wp -- a wp
@ -381,16 +407,43 @@ function williePete.isWP(theWeapon)
for idx, wpw in pairs(williePete.smokeWeapons) do for idx, wpw in pairs(williePete.smokeWeapons) do
if theDesc == wpw then return true end if theDesc == wpw then return true end
end end
trigger.action.outText(theDesc .. " is no wp, ignoring.", 30)
return false return false
end end
function williePete.zedsDead(theObject)
if not theObject then return end
local theName = theObject:getName()
-- now check if it's a registered blasted object:getSampleRate()
local blaster = williePete.blastedObjects[theName]
if blaster then
local theUnit = Unit.getByName(blaster)
if theUnit then
-- interface to playerscore
if cfxPlayerScore then
local fakeEvent = {}
fakeEvent.initiator = theUnit -- killer
fakeEvent.target = theObject -- vic
cfxPlayerScore.killDetected(fakeEvent)
end
end
williePete.blastedObjects[theName] = nil
end
end
function williePete:onEvent(event) function williePete:onEvent(event)
if not event.initiator then if not event.initiator then
--trigger.action.outText("onEvent - " .. event.id .. ": no initiator",30)
return return
end end
-- check if it's a dead event
if event.id == 8 then
-- death event
williePete.zedsDead(event.initiator)
end
if not event.weapon then if not event.weapon then
--trigger.action.outText("onEvent - " .. event.id .. ": no WEAPON",30)
return return
end end
@ -401,21 +454,18 @@ function williePete:onEvent(event)
if event.id == 1 then -- S_EVENT_SHOT if event.id == 1 then -- S_EVENT_SHOT
-- initiator is who fired. maybe want to test if player -- initiator is who fired. maybe want to test if player
--trigger.action.outText(theUnit:getName() .. " " .. pType .. " fired " .. event.weapon:getTypeName() .. ".", 30)
if not williePete.isWP(event.weapon) then if not williePete.isWP(event.weapon) then
--trigger.action.outText("<" .. event.weapon:getTypeName() .. "> not a smoke weapon", 30) -- we only trigger on WP weapons
return return
end end
-- make sure that whoever fired it is being tracked by -- make sure that whoever fired it is being tracked by
-- a zone -- a zone
if not williePete.zoneIsTracking(theUnit) then if not williePete.zoneIsTracking(theUnit) then
--trigger.action.outText("<" .. event.weapon:getTypeName() .. "> fired while not being tracked by zone", 30)
return return
end end
-- assuming it's a willie, let's track it -- it's a willie, fired by player who is checked in: let's track it
local theWillie = {} local theWillie = {}
theWillie.firedBy = theUnit:getName() theWillie.firedBy = theUnit:getName()
theWillie.theUnit = theUnit theWillie.theUnit = theUnit
@ -427,16 +477,18 @@ function williePete:onEvent(event)
williePete.addWillie(theWillie) williePete.addWillie(theWillie)
end end
--[[--
if event.id == 2 then -- hit if event.id == 2 then -- hit
local what = "something" local what = "something"
if event.target then what = event.target:getName() end if event.target then what = event.target:getName() end
--trigger.action.outText("Weapon " .. event.weapon:getTypeName() .. " fired by unit ".. theUnit:getName() .. " " .. pType .. " hit " .. what, 30) --trigger.action.outText("Weapon " .. event.weapon:getTypeName() .. " fired by unit ".. theUnit:getName() .. " " .. pType .. " hit " .. what, 30)
-- may need to remove willie from willies -- may need to remove willie from willies
end end
--]]--
end end
-- test if a projectile hit ground inside a wp zone -- test if a projectile has hit the ground inside a wp zone
function williePete.isInside(theWillie) function williePete.isInside(theWillie)
local thePoint = theWillie.pos local thePoint = theWillie.pos
local theUnitName = theWillie.firedBy -- may be dead already, but who cares local theUnitName = theWillie.firedBy -- may be dead already, but who cares
@ -457,8 +509,6 @@ function williePete.isInside(theWillie)
end end
-- if we want to allow neutral zones (doens't make sense) -- if we want to allow neutral zones (doens't make sense)
-- add another guard below -- add another guard below
else
--trigger.action.outText("willie outside " .. theZone.name, 30)
end end
end end
return nil return nil
@ -471,7 +521,6 @@ function williePete.projectileHit(theWillie)
-- interpolate pos: half time between updates times last velocity -- interpolate pos: half time between updates times last velocity
local vmod = dcsCommon.vMultScalar(theWillie.v, 0.5 / williePete.ups) local vmod = dcsCommon.vMultScalar(theWillie.v, 0.5 / williePete.ups)
theWillie.pos = dcsCommon.vAdd(theWillie.pos, vmod) theWillie.pos = dcsCommon.vAdd(theWillie.pos, vmod)
--trigger.action.outText("Willie " .. theWillie.wt .. " expired at " .. dcsCommon.point2text(theWillie.pos) .. " interpolated.", 30)
-- reset last mark for player -- reset last mark for player
local thePlayer = williePete.playerGUIs[theWillie.firedBy] local thePlayer = williePete.playerGUIs[theWillie.firedBy]
@ -493,15 +542,6 @@ function williePete.projectileHit(theWillie)
thePlayer.pos = theWillie.pos -- remember the loc thePlayer.pos = theWillie.pos -- remember the loc
thePlayer.wpInZone = theZone -- remember the zone thePlayer.wpInZone = theZone -- remember the zone
-- mark point with smoke blue
--dcsCommon.markPointWithSmoke(theWillie.pos, 4)
if cfxArtilleryZones then
--cfxArtilleryZones.doParametricFireAt(theWillie.pos, 50, 10)
else
-- mark point with smoke blue
--dcsCommon.markPointWithSmoke(theWillie.pos, 4)
end
end end
function williePete.updateWP() function williePete.updateWP()
@ -635,14 +675,3 @@ if not williePete.start() then
trigger.action.outText("cf/x Willie Pete aborted: missing libraries", 30) trigger.action.outText("cf/x Willie Pete aborted: missing libraries", 30)
williePete = nil williePete = nil
end end
--[[--
Mechanics:
- unit checks in with arty zone. if not in range of arty zone + safe dist, error 'not in range' is returned, else <artillery zone: status> is sent. <status can be ready, firing, or reloading>. Zone will advise on status change when checked in.
- if unit leaves arty zone + safe dist, <leaving zone> is displayed and <checkout> is invoked
- unit can check out any time
- when checked in, any wp hitting the ground is remembered if still inside target zone
- player then gives 'target marked'
- if artillery on cooldown, or wp not inside zone error, else fire sequence starts, and cooldown starts for entire zone
--]]--

View File

@ -1,5 +1,5 @@
xFlags = {} xFlags = {}
xFlags.version = "1.3.0" xFlags.version = "1.3.1"
xFlags.verbose = false xFlags.verbose = false
xFlags.hiVerbose = false xFlags.hiVerbose = false
xFlags.ups = 1 -- overwritten in get config when configZone is present xFlags.ups = 1 -- overwritten in get config when configZone is present
@ -27,7 +27,13 @@ xFlags.requiredLibs = {
- hiVerbose option - hiVerbose option
- corrected bug in reset checksum - corrected bug in reset checksum
1.3.0 - xCount! flag 1.3.0 - xCount! flag
- "never" operator - "never" operator
1.3.1 - guards for xtriggerOffFlag and xtriggerOnFlag
to prevent QoL warnings
- guards for xDirect
- guards for xCount
--]]-- --]]--
xFlags.xFlagZones = {} xFlags.xFlagZones = {}
@ -96,9 +102,13 @@ function xFlags.createXFlagsWithZone(theZone)
theZone.xChange = cfxZones.getStringFromZoneProperty(theZone, "xChange!", "*<none>") theZone.xChange = cfxZones.getStringFromZoneProperty(theZone, "xChange!", "*<none>")
end end
theZone.xDirect = cfxZones.getStringFromZoneProperty(theZone, "xDirect", "*<none>") if cfxZones.hasProperty(theZone, "xDirect") then
theZone.xDirect = cfxZones.getStringFromZoneProperty(theZone, "xDirect", "*<none>")
end
theZone.xCount = cfxZones.getStringFromZoneProperty(theZone, "xCount", "*<none>") if cfxZones.hasProperty(theZone, "xCount") then
theZone.xCount = cfxZones.getStringFromZoneProperty(theZone, "xCount", "*<none>")
end
theZone.inspect = cfxZones.getStringFromZoneProperty(theZone, "require", "or") -- same as any theZone.inspect = cfxZones.getStringFromZoneProperty(theZone, "require", "or") -- same as any
-- supported any/or, all/and, moreThan, atLeast, exactly -- supported any/or, all/and, moreThan, atLeast, exactly
@ -132,11 +142,14 @@ function xFlags.createXFlagsWithZone(theZone)
trigger.action.outText("+++xFlg: <" .. theZone.name .. "> starts suspended", 30) trigger.action.outText("+++xFlg: <" .. theZone.name .. "> starts suspended", 30)
end end
theZone.xtriggerOnFlag = cfxZones.getStringFromZoneProperty(theZone, "xOn?", "*<none1>") if cfxZones.hasProperty(theZone, "xOn?") then
theZone.xlastTriggerOnValue = cfxZones.getFlagValue(theZone.xtriggerOnFlag, theZone) theZone.xtriggerOnFlag = cfxZones.getStringFromZoneProperty(theZone, "xOn?", "*<none1>")
theZone.xlastTriggerOnValue = cfxZones.getFlagValue(theZone.xtriggerOnFlag, theZone)
theZone.xtriggerOffFlag = cfxZones.getStringFromZoneProperty(theZone, "xOff?", "*<none2>") end
theZone.xlastTriggerOffValue = cfxZones.getFlagValue(theZone.xtriggerOffFlag, theZone) if cfxZones.hasProperty(theZone, "xOff?") then
theZone.xtriggerOffFlag = cfxZones.getStringFromZoneProperty(theZone, "xOff?", "*<none2>")
theZone.xlastTriggerOffValue = cfxZones.getFlagValue(theZone.xtriggerOffFlag, theZone)
end
end end
function xFlags.evaluateNumOrFlag(theAttribute, theZone) function xFlags.evaluateNumOrFlag(theAttribute, theZone)
@ -363,15 +376,18 @@ function xFlags.evaluateZone(theZone)
-- now directly set the value of evalResult (0 = false, 1 = true) -- now directly set the value of evalResult (0 = false, 1 = true)
-- to "xDirect". Always sets output to current result of evaluation -- to "xDirect". Always sets output to current result of evaluation
-- true (1)/false(0), no matter if changed or not -- true (1)/false(0), no matter if changed or not
if theZone.xDirect then
if evalResult then if evalResult then
cfxZones.setFlagValueMult(theZone.xDirect, 1, theZone) cfxZones.setFlagValueMult(theZone.xDirect, 1, theZone)
else else
cfxZones.setFlagValueMult(theZone.xDirect, 0, theZone) cfxZones.setFlagValueMult(theZone.xDirect, 0, theZone)
end end
end
-- directly set the xCount flag -- directly set the xCount flag
cfxZones.setFlagValueMult(theZone.xCount, hits, theZone) if theZone.xCount then
cfxZones.setFlagValueMult(theZone.xCount, hits, theZone)
end
-- 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
@ -391,14 +407,14 @@ function xFlags.update()
for idx, theZone in pairs (xFlags.xFlagZones) do for idx, theZone in pairs (xFlags.xFlagZones) do
-- see if we should suspend -- see if we should suspend
if cfxZones.testZoneFlag(theZone, theZone.xtriggerOnFlag, "change", "xlastTriggerOnValue") then if theZone.xtriggerOnFlag and cfxZones.testZoneFlag(theZone, theZone.xtriggerOnFlag, "change", "xlastTriggerOnValue") then
if xFlags.verbose or theZone.verbose then if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xFlg: enabling " .. theZone.name, 30) trigger.action.outText("+++xFlg: enabling " .. theZone.name, 30)
end end
theZone.xSuspended = false theZone.xSuspended = false
end end
if cfxZones.testZoneFlag(theZone, theZone.xtriggerOffFlag, "change", "xlastTriggerOffValue") then if theZone.xtriggerOffFlag and cfxZones.testZoneFlag(theZone, theZone.xtriggerOffFlag, "change", "xlastTriggerOffValue") then
if xFlags.verbose or theZone.verbose then if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xFlg: DISabling " .. theZone.name, 30) trigger.action.outText("+++xFlg: DISabling " .. theZone.name, 30)
end end

Binary file not shown.

Binary file not shown.