diff --git a/Doc/DML Documentation.pdf b/Doc/DML Documentation.pdf index 607b5d2..1a85d49 100644 Binary files a/Doc/DML Documentation.pdf and b/Doc/DML Documentation.pdf differ diff --git a/Doc/DML Quick Reference.pdf b/Doc/DML Quick Reference.pdf index ed8695f..7c49277 100644 Binary files a/Doc/DML Quick Reference.pdf and b/Doc/DML Quick Reference.pdf differ diff --git a/modules/cfxGroudTroops.lua b/modules/cfxGroudTroops.lua index eb428f0..b8217e9 100644 --- a/modules/cfxGroudTroops.lua +++ b/modules/cfxGroudTroops.lua @@ -1,5 +1,5 @@ cfxGroundTroops = {} -cfxGroundTroops.version = "1.7.4" +cfxGroundTroops.version = "1.7.5" cfxGroundTroops.ups = 1 cfxGroundTroops.verbose = false cfxGroundTroops.requiredLibs = { @@ -59,6 +59,7 @@ cfxGroundTroops.deployedTroops = {} -- - callback when group is being engaged under guard orders -- 1.7.3 - callbacks for lase:tracking and lase:stop -- 1.7.4 - verbose flag, warnings suppressed +-- 1.7.5 - some troop.group hardening with isExist() @@ -199,6 +200,11 @@ end -- enemies are an attribute of the troop structure function cfxGroundTroops.makeTroopsEngageEnemies(troop) local group = troop.group + if not group:isExist() then + trigger.action.outText("+++gndT: troup don't exist, dropping", 30) + return + end + local enemies = troop.enemy local from = dcsCommon.getGroupLocation(group) if not from then return end -- the commandos died @@ -218,6 +224,11 @@ end -- attribute function cfxGroundTroops.makeTroopsEngageZone(troop) local group = troop.group + if not group:isExist() then + trigger.action.outText("+++gndT: make engage zone: troops do not exist, exiting", 30) + return + end + local enemyZone = troop.destination -- must be cfxZone local from = dcsCommon.getGroupLocation(group) if not from then return end -- the group died @@ -250,6 +261,10 @@ function cfxGroundTroops.switchToOffroad(troops) -- on their route for longer than allowed -- we now force a direct approach local group = troops.group + if not group.isExist() then + return + end + local enemies = troops.destination local from = dcsCommon.getGroupLocation(group) if not from then return end -- the commandos died @@ -315,6 +330,7 @@ end function cfxGroundTroops.updateAttackers(troop) if not troop then return end if not troop.destination then return end + if not troop.group:isExist() then return end if cfxZones.isGroupPartiallyInZone(troop.group, troop.destination) then -- we have arrived @@ -335,6 +351,10 @@ end -- 'engaged' means that the troop.enemy attribute is set function cfxGroundTroops.updateGuards(troop) + if not troop.group:isExist() then + return + end + local theEnemy = troop.enemy if theEnemy then -- see if enemy is dead @@ -807,7 +827,7 @@ function cfxGroundTroops.checkPileUp() for idx, troop in pairs(cfxGroundTroops.deployedTroops) do -- get each group and count them if they are inside -- their destination - if troop.insideDestination then + if troop.insideDestination and troop.group:isExist() then local side = troop.group:getCoalition() local thePile = thePiles[troop.destination] local theSide = troop.group:getCoalition() @@ -879,7 +899,7 @@ function cfxGroundTroops.checkSchedules() -- plan and needs to be scheduled if troop.updateID == nil then troop.unscheduleCount = troop.unscheduleCount + 1 - if (troop.unscheduleCount > 1) then + if (troop.unscheduleCount > 1) and troop.group:isExist() then trigger.action.outText("+++ groundT: unscheduled group " .. troop.group:getName() .. " cnt=" .. troop.unscheduleCount , 30) end end @@ -896,7 +916,7 @@ function cfxGroundTroops.getTroopReport(theSide, ignoreInfantry) if not ignoreInfantry then ignoreInfantry = false end local report = "GROUND FORCES REPORT" for idx, troop in pairs(cfxGroundTroops.deployedTroops) do - if troop.side == theSide then + if troop.side == theSide and troop.group:isExist() then local unitNum = troop.group:getSize() report = report .. "\n" .. troop.name .. " (".. unitNum .."): <" .. troop.orders .. ">" if troop.orders == "attackOwnedZone" then @@ -975,8 +995,14 @@ function cfxGroundTroops.addGroundTroopsToPool(troops) -- troops MUST be a table end function cfxGroundTroops.removeTroopsFromPool(troops) + if not troops then return end if troops.signature ~= "cfx" then return end + + if not troops.group:isExist() then + trigger.action.outText("warning: removeFromPool called with inexistant group", 30) + return + end if cfxGroundTroops.deployedTroops[troops.group:getName()] then local troop = cfxGroundTroops.deployedTroops[troops.group:getName()] @@ -1066,7 +1092,9 @@ function cfxGroundTroops.manageQueues() -- trnasfer items from the front to the managed queue local theTroops = cfxGroundTroops.troopQueue[1] table.remove(cfxGroundTroops.troopQueue, 1) - cfxGroundTroops.deployedTroops[theTroops.group:getName()] = theTroops + if theTroops.group:isExist() then + cfxGroundTroops.deployedTroops[theTroops.group:getName()] = theTroops + end -- trigger.action.outText("+++gT: dequed and activaed " .. theTroops.group:getName(), 30) end end diff --git a/modules/cfxSmokeZones.lua b/modules/cfxSmokeZones.lua index 4fa1737..13b9a35 100644 --- a/modules/cfxSmokeZones.lua +++ b/modules/cfxSmokeZones.lua @@ -1,5 +1,5 @@ cfxSmokeZone = {} -cfxSmokeZone.version = "1.0.4" +cfxSmokeZone.version = "1.1.0" cfxSmokeZone.requiredLibs = { "dcsCommon", -- always "cfxZones", -- Zones, of course @@ -15,6 +15,7 @@ cfxSmokeZone.requiredLibs = { 1.0.4 - startSmoke? synonym - alphanum DML flag upgrade - random color support + 1.1.0 - Watchflag upgrade SMOKE ZONES *** EXTENDS ZONES *** keeps 'eternal' smoke up for any zone that has the @@ -49,7 +50,7 @@ function cfxSmokeZone.processSmokeZone(aZone) -- f? query flags if cfxZones.hasProperty(aZone, "f?") then - aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "f?", "none") + aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "f?", "*") end if cfxZones.hasProperty(aZone, "startSmoke?") then @@ -59,6 +60,15 @@ function cfxSmokeZone.processSmokeZone(aZone) if aZone.onFlag then aZone.onFlagVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- save last value end + + -- watchflags: + -- triggerMethod + aZone.smokeTriggerMethod = cfxZones.getStringFromZoneProperty(aZone, "triggerMethod", "change") + + if cfxZones.hasProperty(aZone, "smokeTriggerMethod") then + aZone.delayTriggerMethod = cfxZones.getStringFromZoneProperty(aZone, "smokeTriggerMethod", "change") + end + end function cfxSmokeZone.addSmokeZone(aZone) @@ -122,7 +132,6 @@ function cfxSmokeZone.update() for idx, aZone in pairs(cfxSmokeZone.smokeZones) do if not aZone.paused and aZone.smokeColor then cfxSmokeZone.startSmoke(aZone) - end end end @@ -131,14 +140,21 @@ end function cfxSmokeZone.checkFlags() timer.scheduleFunction(cfxSmokeZone.checkFlags, {}, timer.getTime() + 1) -- every second for idx, aZone in pairs(cfxSmokeZone.smokeZones) do + if aZone.paused and aZone.onFlagVal then -- see if this changed + if cfxZones.testZoneFlag(aZone, aZone.onFlag, aZone.smokeTriggerMethod, "onFlagVal") then + cfxSmokeZone.startSmoke(aZone) + end +--[[-- + -- old code local currTriggerVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- trigger.misc.getUserFlag(aZone.onFlag) if currTriggerVal ~= aZone.onFlagVal then -- yupp, trigger start cfxSmokeZone.startSmoke(aZone) aZone.onFlagVal = currTriggerVal - end + end +--]]-- end end end diff --git a/modules/cfxZones.lua b/modules/cfxZones.lua index 9e7b88f..44bd820 100644 --- a/modules/cfxZones.lua +++ b/modules/cfxZones.lua @@ -64,6 +64,7 @@ cfxZones.version = "2.7.0" - verbose for zone-local accepted (but not acted upon) - hasProperty now offers active information when looking for '*?' and '*!' - 2.7.0 - doPollFlag - fully support multiple flags per bang! + - 2.7.1 - setFlagValueMult() --]]-- cfxZones.verbose = false @@ -2881,6 +2882,25 @@ function cfxZones.pollFlag(theFlag, method, theZone) end +function cfxZones.setFlagValueMult(theFlag, theValue, theZone) + local allFlags = {} + if dcsCommon.containsString(theFlag, ",") then + if cfxZones.verbose then + trigger.action.outText("+++zones: will multi-set flags <" .. theFlag .. "> to " .. theValue, 30) + end + allFlags = dcsCommon.splitString(theFlag, ",") + else + table.insert(allFlags, theFlag) + end + + for idx, aFlag in pairs(allFlags) do + aFlag = dcsCommon.trim(aFlag) + -- note: mey require range preprocessing, but that's not + -- a priority + cfxZones.setFlagValue(aFlag, theValue, theZone) + end +end + function cfxZones.setFlagValue(theFlag, theValue, theZone) local zoneName = "" if not theZone then @@ -3036,7 +3056,7 @@ function cfxZones.testFlagByMethodForZone(currVal, lastVal, theMethod, theZone) end function cfxZones.testZoneFlag(theZone, theFlagName, theMethod, latchName) - -- returns true if method contraints are met for flag theFlagName + -- returns true if method constraints are met for flag theFlagName -- as defined by theMethod if not theMethod then theMethod = "change" diff --git a/modules/changer.lua b/modules/changer.lua new file mode 100644 index 0000000..adaed69 --- /dev/null +++ b/modules/changer.lua @@ -0,0 +1,148 @@ +changer = {} +changer.version = "0.0.0" +changer.verbose = false +changer.ups = 1 +changer.requiredLibs = { + "dcsCommon", -- always + "cfxZones", -- Zones, of course +} +changer.changers = {} +--[[-- + Version History + 1.0.0 - Initial version + +--]]-- + +function changer.addChanger(theZone) + table.insert(changer.changers, theZone) +end + +function changer.getChangerByName(aName) + for idx, aZone in pairs(changer.changers) do + if aName == aZone.name then return aZone end + end + if changer.verbose then + trigger.action.outText("+++chgr: no changer with name <" .. aName ..">", 30) + end + + return nil +end + +-- +-- read zone +-- +function wiper.createWiperWithZone(theZone) + theZone.triggerWiperFlag = cfxZones.getStringFromZoneProperty(theZone, "wipe?", "*") + + -- triggerWiperMethod + theZone.triggerWiperMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change") + if cfxZones.hasProperty(theZone, "triggerWiperMethod") then + theZone.triggerWiperMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerWiperMethod", "change") + end + + if theZone.triggerWiperFlag then + theZone.lastTriggerWiperValue = cfxZones.getFlagValue(theZone.triggerWiperFlag, theZone) + end + + local theCat = cfxZones.getStringFromZoneProperty(theZone, "category", "static") + if cfxZones.hasProperty(theZone, "wipeCategory") then + theCat = cfxZones.getStringFromZoneProperty(theZone, "wipeCategory", "static") + end + if cfxZones.hasProperty(theZone, "wipeCat") then + theCat = cfxZones.getStringFromZoneProperty(theZone, "wipeCat", "static") + end + + theZone.wipeCategory = dcsCommon.string2ObjectCat(theCat) + + if cfxZones.hasProperty(theZone, "wipeNamed") then + theZone.wipeNamed = cfxZones.getStringFromZoneProperty(theZone, "wipeNamed", "") + + if dcsCommon.stringEndsWith(theZone.wipeNamed, "*") then + theZone.wipeNamedBeginsWith = true + theZone.wipeNamed = dcsCommon.removeEnding(theZone.wipeNamed, "*") + end + end + + theZone.wipeInventory = cfxZones.getBoolFromZoneProperty(theZone, "wipeInventory", false) + + if wiper.verbose or theZone.verbose then + trigger.action.outText("+++wpr: new wiper zone <".. theZone.name ..">", 30) + end +end + +-- +-- MAIN ACTION +-- +function changer.isTriggered(theZone) + +end + + +-- +-- Update +-- + +function changer.update() + -- call me in a second to poll triggers + timer.scheduleFunction(changer.update, {}, timer.getTime() + 1/changer.ups) + + for idx, aZone in pairs(changer.changers) do + + + end +end + + +-- +-- Config & Start +-- +function changer.readConfigZone() + local theZone = cfxZones.getZoneByName("changerConfig") + if not theZone then + if changer.verbose then + trigger.action.outText("+++chgr: NO config zone!", 30) + end + theZone = cfxZones.createSimpleZone("changerConfig") -- temp only + end + + changer.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false) + + changer.ups = cfxZones.getNumberFromZoneProperty(theZone, "ups", 1) + + if changer.verbose then + trigger.action.outText("+++chgr: read config", 30) + end +end + +function wiper.start() + -- lib check + if not dcsCommon.libCheck then + trigger.action.outText("cfx Wiper requires dcsCommon", 30) + return false + end + if not dcsCommon.libCheck("cfx Wiper", wiper.requiredLibs) then + return false + end + + -- read config + wiper.readConfigZone() + + -- process cloner Zones + local attrZones = cfxZones.getZonesWithAttributeNamed("wipe?") + for k, aZone in pairs(attrZones) do + wiper.createWiperWithZone(aZone) -- process attributes + wiper.addWiper(aZone) -- add to list + end + + -- start update + wiper.update() + + trigger.action.outText("cfx Wiper v" .. wiper.version .. " started.", 30) + return true +end + +-- let's go! +if not wiper.start() then + trigger.action.outText("cfx Wiper aborted: missing libraries", 30) + wiper = nil +end \ No newline at end of file diff --git a/modules/countDown.lua b/modules/countDown.lua index ef4dfe1..5138cf2 100644 --- a/modules/countDown.lua +++ b/modules/countDown.lua @@ -1,6 +1,6 @@ countDown = {} countDown.version = "1.3.0" -countDown.verbose = true +countDown.verbose = false countDown.ups = 1 countDown.requiredLibs = { "dcsCommon", -- always diff --git a/modules/dcsCommon.lua b/modules/dcsCommon.lua index f8921e1..2b40b6c 100644 --- a/modules/dcsCommon.lua +++ b/modules/dcsCommon.lua @@ -1,5 +1,5 @@ dcsCommon = {} -dcsCommon.version = "2.5.8" +dcsCommon.version = "2.5.9" --[[-- VERSION HISTORY 2.2.6 - compassPositionOfARelativeToB - clockPositionOfARelativeToB @@ -68,6 +68,7 @@ dcsCommon.version = "2.5.8" 2.5.6 - corrected stringEndsWith() bug with str 2.5.7 - point2text(p) 2.5.8 - string2GroupCat() + 2.5.9 - string2ObjectCat() --]]-- @@ -1806,6 +1807,28 @@ dcsCommon.version = "2.5.8" return catNum end + function dcsCommon.string2ObjectCat(inString) + + if not inString then return 3 end -- default static + inString = inString:lower() + inString = dcsCommon.trim(inString) + + local catNum = tonumber(inString) + if catNum then + if catNum < 0 then catNum = 0 end + if catNum > 6 then catNum = 6 end + return catNum + end + + catNum = 3 -- static default + if dcsCommon.stringStartsWith(inString, "uni") then catNum = 1 end + if dcsCommon.stringStartsWith(inString, "wea") then catNum = 2 end + if dcsCommon.stringStartsWith(inString, "bas") then catNum = 4 end + if dcsCommon.stringStartsWith(inString, "sce") then catNum = 5 end + if dcsCommon.stringStartsWith(inString, "car") then catNum = 6 end + + return catNum + end -- recursively show the contents of a variable function dcsCommon.dumpVar(key, value, prefix, inrecursion) diff --git a/modules/unitZone.lua b/modules/unitZone.lua index 889aaab..62c4986 100644 --- a/modules/unitZone.lua +++ b/modules/unitZone.lua @@ -1,5 +1,5 @@ unitZone={} -unitZone.version = "1.1.0" +unitZone.version = "1.2.0" unitZone.verbose = false unitZone.ups = 1 unitZone.requiredLibs = { @@ -11,6 +11,7 @@ unitZone.requiredLibs = { 1.0.0 - Initial Version 1.1.0 - DML flag integration - method/uzMethod + 1.2.0 - uzOn?, uzOff?, triggerMethod --]]-- @@ -73,11 +74,11 @@ function unitZone.createUnitZone(theZone) theZone.uzCoalition = cfxZones.getCoalitionFromZoneProperty(theZone, "uzCoalition", 0) end - if unitZone.verbose then + if unitZone.verbose or theZone.verbose then trigger.action.outText("+++uZne: set coa " .. theZone.uzCoalition .. " for <" .. theZone.name .. ">", 30) end - -- DML M;ethod + -- DML Method theZone.uzMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc") if cfxZones.hasProperty(theZone, "uzMethod") then theZone.uzMethod = cfxZones.getStringFromZoneProperty(theZone, "uzMethod", "inc") @@ -90,16 +91,30 @@ function unitZone.createUnitZone(theZone) if cfxZones.hasProperty(theZone, "filterFor") then local filterString = cfxZones.getStringFromZoneProperty(theZone, "filterFor", "1") -- ground theZone.filterFor = unitZone.string2cat(filterString) - if unitZone.verbose then + if unitZone.verbose or theZone.verbose then trigger.action.outText("+++uZne: filtering " .. theZone.filterFor .. " in " .. theZone.name, 30) end end + -- on/off flags + theZone.uzPaused = false -- we are turned on + theZone.triggerOnFlag = cfxZones.getStringFromZoneProperty(theZone, "uzOn?", "*") + theZone.lastTriggerOnValue = cfxZones.getFlagValue(theZone.triggerOnFlag, theZone) + + theZone.triggerOffFlag = cfxZones.getStringFromZoneProperty(theZone, "uzOff?", "*") + theZone.lastTriggerOffValue = cfxZones.getFlagValue(theZone.triggerOffFlag, theZone) + + theZone.uzTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change") + if cfxZones.hasProperty(theZone, "uzTriggerMethod") then + theZone.uzTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "uzTriggerMethod", "change") + end + -- now get initial zone status ? theZone.lastStatus = unitZone.checkZoneStatus(theZone) - if unitZone.verbose then + if unitZone.verbose or theZone.verbose then trigger.action.outText("+++uZne: processsed unit zone " .. theZone.name, 30) end + end @@ -221,14 +236,31 @@ function unitZone.update() 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 + -- check if we need to pause/unpause + if cfxZones.testZoneFlag(aZone, aZone.triggerOnFlag, aZone.uzTriggerMethod, "lastTriggerOnValue") then + if unitZone.verbose or aZone.verbose then + trigger.action.outText("+++uZone: turning " .. aZone.name .. " on", 30) + end + aZone.uzPaused = false end + + if cfxZones.testZoneFlag(aZone, aZone.triggerOffFlag, aZone.uzTriggerMethod, "lastTriggerOffValue") then + if unitZone.verbose or aZone.verbose then + trigger.action.outText("+++uZone: turning " .. aZone.name .. " OFF", 30) + end + aZone.uzPaused = true + end + + -- scan all zones + if not aZone.uzPaused then + local newState = unitZone.checkZoneStatus(aZone) + + if newState ~= aZone.lastStatus then + -- bang on change! + unitZone.bangState(aZone, newState) + aZone.lastStatus = newState + end + end end end diff --git a/modules/wiper.lua b/modules/wiper.lua new file mode 100644 index 0000000..1f2d837 --- /dev/null +++ b/modules/wiper.lua @@ -0,0 +1,278 @@ +wiper = {} +wiper.version = "1.0.0" +wiper.verbose = false +wiper.ups = 1 +wiper.requiredLibs = { + "dcsCommon", -- always + "cfxZones", -- Zones, of course +} +wiper.wipers = {} +--[[-- + Version History + 1.0.0 - Initial Version + +--]]-- + +function wiper.addWiper(theZone) + table.insert(wiper.wipers, theZone) +end + +function wiper.getWiperByName(aName) + for idx, aZone in pairs(wiper.wipers) do + if aName == aZone.name then return aZone end + end + if wiper.verbose then + trigger.action.outText("+++wpr: no wiper with name <" .. aName ..">", 30) + end + + return nil +end + +-- +-- read zone +-- +function wiper.createWiperWithZone(theZone) + theZone.triggerWiperFlag = cfxZones.getStringFromZoneProperty(theZone, "wipe?", "*") + + -- triggerWiperMethod + theZone.triggerWiperMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change") + if cfxZones.hasProperty(theZone, "triggerWiperMethod") then + theZone.triggerWiperMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerWiperMethod", "change") + end + + if theZone.triggerWiperFlag then + theZone.lastTriggerWiperValue = cfxZones.getFlagValue(theZone.triggerWiperFlag, theZone) + end + + local theCat = cfxZones.getStringFromZoneProperty(theZone, "category", "static") + if cfxZones.hasProperty(theZone, "wipeCategory") then + theCat = cfxZones.getStringFromZoneProperty(theZone, "wipeCategory", "static") + end + if cfxZones.hasProperty(theZone, "wipeCat") then + theCat = cfxZones.getStringFromZoneProperty(theZone, "wipeCat", "static") + end + + theZone.wipeCategory = dcsCommon.string2ObjectCat(theCat) + + if cfxZones.hasProperty(theZone, "wipeNamed") then + theZone.wipeNamed = cfxZones.getStringFromZoneProperty(theZone, "wipeNamed", "") + theZone.oWipeNamed = theZone.wipeNamed -- save original + -- assemble list of all names to wipe, including wildcard + local allNames = {} + if dcsCommon.containsString(theZone.wipeNamed, ",") then + allNames = dcsCommon.splitString(theZone.wipeNamed, ",") + allNames = dcsCommon.trimArray(allNames) + else + allNames = {dcsCommon.trim(theZone.wipeNamed)} + end + + -- assemble dict of all wipeNamed and endswith + local theDict = {} + for idx, aName in pairs(allNames) do + local shortName = aName + local ew = dcsCommon.stringEndsWith(aName, "*") + if ew then + shortName = dcsCommon.removeEnding(aName, "*") + end + theDict[shortName] = ew + if wiper.verbose or theZone.verbose then + trigger.action.outText("+++wpr: dict [".. shortName .."] = " .. dcsCommon.bool2Text(ew),30) + end + end + + theZone.wipeNamed = theDict + + end + + theZone.wipeInventory = cfxZones.getBoolFromZoneProperty(theZone, "wipeInventory", false) + + if wiper.verbose or theZone.verbose then + trigger.action.outText("+++wpr: new wiper zone <".. theZone.name ..">", 30) + end +end + +-- +-- Wiper main action +-- +function wiper.objectHandler(theObject, theCollector) + table.insert(theCollector, theObject) + return true +end + +wiper.inventory = "" +function wiper.seeZoneInventory(theZone) + -- run a diag which objects are in the zone, and which cat they are + -- set up args + local allCats = {1, 2, 3, 4, 5, 6} + wiper.inventory = "" + for idx, aCat in pairs(allCats) do + local p = cfxZones.getPoint(theZone) + local lp = {x = p.x, y = p.z} + p.y = land.getHeight(lp) + local collector = {} + + -- now build the search argument + local args = { + id = world.VolumeType.SPHERE, + params = { + point = p, + radius = theZone.radius + } + } + + -- now call search + world.searchObjects(aCat, args, wiper.objectHandler, collector) + wiper.inventory = wiper.inventory .. "Cat = " .. aCat .. ":" + for idy, anObject in pairs(collector) do + wiper.inventory = wiper.inventory .. anObject:getName() .. " " + end + wiper.inventory = wiper.inventory .. "\n" + end +end + + +function wiper.isTriggered(theZone) + -- see if we need a diagnostic run + wiper.inventory = "" + if theZone.wipeInventory then + wiper.seeZoneInventory(theZone) + -- inventory data + if theZone.wipeInventory then + trigger.action.outText(wiper.inventory, 30) + end + end + + -- get current location in case theZone is moving + local p = cfxZones.getPoint(theZone) + local lp = {x = p.x, y = p.z} + p.y = land.getHeight(lp) + local collector = {} + + -- now build the search argument + local args = { + id = world.VolumeType.SPHERE, + params = { + point = p, + radius = theZone.radius + } + } + -- set up remaining arguments + local cat = theZone.wipeCategory -- Object.Category.STATIC + + -- now call search + world.searchObjects(cat, args, wiper.objectHandler, collector) + if #collector < 1 and (wiper.verbose or theZone.verbose) then + trigger.action.outText("+++wpr: world search returned zero elements for <" .. theZone.name .. "> (cat=" .. theZone.wipeCategory .. ")",30) + end + + -- wipe'em! + for idx, anObject in pairs(collector) do + local doWipe = true + + -- see if we filter to only named objects + if theZone.wipeNamed then + doWipe = false + local oName = tostring(anObject:getName()) -- prevent number mismatch + for wipeName, beginsWith in pairs(theZone.wipeNamed) do + if beginsWith then + doWipe = doWipe or dcsCommon.stringStartsWith(oName, wipeName) + else + doWipe = doWipe or oName == wipeName + end + end + + if wiper.verbose or theZone.verbose then + if not doWipe then + trigger.action.outText("+++wpr: <"..oName.."> not removed, name restriction <" .. theZone.oWipeNamed .. "> not met.",30) + end + end + end + + if doWipe then + if wiper.verbose or theZone.verbose then + trigger.action.outText("+++wpr: wiping " .. anObject:getName(), 30) + end + anObject:destroy() + else + if wiper.verbose or theZone.verbose then + trigger.action.outText("+++wpr: spared object <" .. anObject:getName() .. ">",30) + end + end + end + + +end + +-- +-- Update +-- +function wiper.update() + -- call me in a second to poll triggers + timer.scheduleFunction(wiper.update, {}, timer.getTime() + 1/wiper.ups) + + for idx, aZone in pairs(wiper.wipers) do + + if cfxZones.testZoneFlag(aZone, aZone.triggerWiperFlag, aZone.triggerWiperMethod, "lastTriggerWiperValue") then + if wiper.verbose or aZone.verbose then + trigger.action.outText("+++wpr: triggered on ".. aZone.triggerWiperFlag .. " for <".. aZone.name ..">", 30) + end + wiper.isTriggered(aZone) + end + + end +end + + +-- +-- Config & Start +-- +function wiper.readConfigZone() + local theZone = cfxZones.getZoneByName("wiperConfig") + if not theZone then + if wiper.verbose then + trigger.action.outText("+++wpr: NO config zone!", 30) + end + theZone = cfxZones.createSimpleZone("wiperConfig") -- temp only + end + + wiper.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false) + + wiper.ups = cfxZones.getNumberFromZoneProperty(theZone, "ups", 1) + + if wiper.verbose then + trigger.action.outText("+++wpr: read config", 30) + end +end + +function wiper.start() + -- lib check + if not dcsCommon.libCheck then + trigger.action.outText("cfx Wiper requires dcsCommon", 30) + return false + end + if not dcsCommon.libCheck("cfx Wiper", wiper.requiredLibs) then + return false + end + + -- read config + wiper.readConfigZone() + + -- process cloner Zones + local attrZones = cfxZones.getZonesWithAttributeNamed("wipe?") + for k, aZone in pairs(attrZones) do + wiper.createWiperWithZone(aZone) -- process attributes + wiper.addWiper(aZone) -- add to list + end + + -- start update + wiper.update() + + trigger.action.outText("cfx Wiper v" .. wiper.version .. " started.", 30) + return true +end + +-- let's go! +if not wiper.start() then + trigger.action.outText("cfx Wiper aborted: missing libraries", 30) + wiper = nil +end \ No newline at end of file diff --git a/modules/xFlags.lua b/modules/xFlags.lua index 2cf1fc9..8ce58ff 100644 --- a/modules/xFlags.lua +++ b/modules/xFlags.lua @@ -1,5 +1,5 @@ xFlags = {} -xFlags.version = "1.0.1" +xFlags.version = "1.2.0" xFlags.verbose = false xFlags.ups = 1 -- overwritten in get config when configZone is present xFlags.requiredLibs = { @@ -13,6 +13,8 @@ xFlags.requiredLibs = { 1.0.0 - Initial version 1.0.1 - allow flags names for ops as well 1.1.0 - Watchflags harmonization + 1.2.0 - xDirect flag, + - direct array support --]]-- xFlags.xFlagZones = {} @@ -62,13 +64,17 @@ function xFlags.createXFlagsWithZone(theZone) theZone.xHasFired = false theZone.xSuccess = cfxZones.getStringFromZoneProperty(theZone, "xSuccess!", "") + if cfxZones.hasProperty(theZone, "out!") then - theZone.xSuccess = cfxZones.getStringFromZoneProperty(theZone, "out!", "") + theZone.xSuccess = cfxZones.getStringFromZoneProperty(theZone, "out!", "*") end if cfxZones.hasProperty(theZone, "xChange!") then - theZone.xChange = cfxZones.getStringFromZoneProperty(theZone, "xChange!", "") + theZone.xChange = cfxZones.getStringFromZoneProperty(theZone, "xChange!", "*") end + + theZone.xDirect = cfxZones.getStringFromZoneProperty(theZone, "xDirect!", "*") + theZone.inspect = cfxZones.getStringFromZoneProperty(theZone, "require", "or") -- same as any -- supported any/or, all/and, moreThan, atLeast, exactly theZone.inspect = string.lower(theZone.inspect) @@ -89,13 +95,15 @@ function xFlags.createXFlagsWithZone(theZone) theZone.xLastReset = cfxZones.getFlagValue(theZone.xReset, theZone) end - theZone.xMethod = cfxZones.getStringFromZoneProperty(theZone, "xMethod", "flip") + theZone.xMethod = cfxZones.getStringFromZoneProperty(theZone, "xMethod", "inc") if cfxZones.hasProperty(theZone, "method") then - theZone.xMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "flip") + theZone.xMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc") end theZone.xOneShot = cfxZones.getBoolFromZoneProperty(theZone, "oneShot", true) + + end function xFlags.evaluateFlags(theZone) @@ -187,21 +195,28 @@ end function xFlags.evaluateZone(theZone) + -- short circuit if we are done + if theZone.xHasFired and theZone.xOneShot then return end + 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 + if (op == "or" or op == "any" or op == "some") 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 + elseif (op == "atleast" or op == "at least") and hits >= theZone.matchNum then evalResult = true elseif op == "exactly" and hits == theZone.matchNum then evalResult = true + elseif (op == "none" or op == "nor") and hits == 0 then + evalResult = true + elseif (op == "not all" or op == "notall" or op == "nand") and hits < #theZone.flagNames then + evalResult = true end -- now check if changed and if result true @@ -219,7 +234,17 @@ function xFlags.evaluateZone(theZone) theZone.flagChecksum = checkSum end - if theZone.xHasFired and theZone.xOneShot then return end + -- now directly set the value of evalResult (0 = false, 1 = true) + -- to "xDirect!". Always sets output to current result of evaluation + -- true (1)/false(0), no matter if changed or not + + if evalResult then + cfxZones.setFlagValueMult(theZone.xDirect, 1, theZone) + else + cfxZones.setFlagValueMult(theZone.xDirect, 0, theZone) + end + + -- now see if we bang the output according to method if evalResult then if xFlags.verbose then trigger.action.outText("+++xFlag: success bang! on " .. theZone.xSuccess .. " for " .. theZone.name, 30) diff --git a/tutorial & demo missions/demo - 000 smoke em! DML intro.miz b/tutorial & demo missions/demo - 000 smoke em! DML intro.miz index aa83fcf..76f2c58 100644 Binary files a/tutorial & demo missions/demo - 000 smoke em! DML intro.miz and b/tutorial & demo missions/demo - 000 smoke em! DML intro.miz differ diff --git a/tutorial & demo missions/demo - Random Glory.miz b/tutorial & demo missions/demo - Random Glory.miz index 623dc60..45f5fc5 100644 Binary files a/tutorial & demo missions/demo - Random Glory.miz and b/tutorial & demo missions/demo - Random Glory.miz differ diff --git a/tutorial & demo missions/demo - viper with a double youu.miz b/tutorial & demo missions/demo - viper with a double youu.miz new file mode 100644 index 0000000..c5280d9 Binary files /dev/null and b/tutorial & demo missions/demo - viper with a double youu.miz differ