diff --git a/Doc/DML Documentation.pdf b/Doc/DML Documentation.pdf index 9257ff6..e5917a7 100644 Binary files a/Doc/DML Documentation.pdf and b/Doc/DML Documentation.pdf differ diff --git a/modules/cfxMX.lua b/modules/cfxMX.lua index 4caebf4..8db19f5 100644 --- a/modules/cfxMX.lua +++ b/modules/cfxMX.lua @@ -1,5 +1,5 @@ cfxMX = {} -cfxMX.version = "1.0.0" +cfxMX.version = "1.0.1" --[[-- Mission data decoder. Access to ME-built mission structures @@ -7,6 +7,7 @@ cfxMX.version = "1.0.0" Version History 1.0.0 - initial version + 1.0.1 - getStaticFromDCSbyName() --]]-- @@ -67,6 +68,70 @@ function cfxMX.getGroupFromDCSbyName(aName, fetchOriginal) return nil, "none", "none" end +function cfxMX.getStaticFromDCSbyName(aName, fetchOriginal) + if not fetchOriginal then fetchOriginal = false end + -- fetch the static description for static named aName (if exists) + -- returned structure must be parsed for useful information + -- returns data, category, countyID and parent group name + -- unless fetchOriginal is true, creates a deep clone of + -- static data structure + + for coa_name_miz, coa_data in pairs(env.mission.coalition) do -- iterate all coalitions + local coa_name = coa_name_miz + if string.lower(coa_name_miz) == 'neutrals' then -- remove 's' at neutralS + coa_name = 'neutral' + end + -- directly convert coalition into number for easier access later + local coaNum = 0 + if coa_name == "red" then coaNum = 1 end + if coa_name == "blue" then coaNum = 2 end + + if type(coa_data) == 'table' then -- coalition = {bullseye, nav_points, name, county}, + -- with county being an array + if coa_data.country then -- make sure there a country table for this coalition + for cntry_id, cntry_data in pairs(coa_data.country) do -- iterate all countries for this + -- per country = {id, name, vehicle, helicopter, plane, ship, static} + local countryName = string.lower(cntry_data.name) + local countryID = cntry_data.id + if type(cntry_data) == 'table' then -- filter strings .id and .name + for obj_type_name, obj_type_data in pairs(cntry_data) do + if obj_type_name == "static" +-- obj_type_name == "helicopter" or +-- obj_type_name == "ship" or +-- obj_type_name == "plane" or +-- obj_type_name == "vehicle" or +-- obj_type_name == "static" + then -- (only look at statics) + local category = obj_type_name + if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's at least one static in group! + for group_num, group_data in pairs(obj_type_data.group) do + if group_data and group_data.units and type(group_data.units) == 'table' + then --make sure - again - that this is a valid group + for unit_num, unit_data in pairs(group_data.units) do -- iterate units + if unit_data.name == aName then + local groupName = group_data.name + local theStatic = unit_data + if not fetchOriginal then + theStatic = dcsCommon.clone(unit_data) + end + return theStatic, category, countryID, groupName + + end -- if name match + end -- for all units + end -- has groups + + end -- is a static + end --if has category data + end --if plane, helo etc... category + end --for all objects in country + end --if has country data + end --for all countries in coalition + end --if coalition has country table + end -- if there is coalition data + end --for all coalitions in mission + return nil, "", "", "" +end + function cfxMX.catText2ID(inText) local outCat = 0 -- airplane local c = inText:lower() diff --git a/modules/cfxZones.lua b/modules/cfxZones.lua index 5d638a2..7d8a849 100644 --- a/modules/cfxZones.lua +++ b/modules/cfxZones.lua @@ -6,7 +6,7 @@ -- cfxZones = {} -cfxZones.version = "2.5.3" +cfxZones.version = "2.5.5" --[[-- VERSION HISTORY - 2.2.4 - getCoalitionFromZoneProperty - getStringFromZoneProperty @@ -48,9 +48,11 @@ cfxZones.version = "2.5.3" - 2.5.3 - new getAllGroupsInZone() - 2.5.4 - cleaned up getZoneProperty break on no properties - extractPropertyFromDCS trims key and property + - 2.5.5 - pollFlag() centralized for banging + - allStaticsInZone --]]-- -cfxZones.verbose = true +cfxZones.verbose = false cfxZones.caseSensitiveProperties = false -- set to true to make property names case sensitive cfxZones.ups = 1 -- updates per second. updates moving zones @@ -561,6 +563,22 @@ function cfxZones.allGroupsInZone(theZone, categ) -- categ is optional, must be return inZones end +function cfxZones.allStaticsInZone(theZone) -- categ is optional, must be code + -- warning: does not check for exiting! + local inZones = {} + local coals = {0, 1, 2} -- all coalitions + for idx, coa in pairs(coals) do + local allStats = coalition.getStaticObjects(coa) + for key, statO in pairs(allStats) do -- iterate all groups + local oP = statO:getPoint() + if cfxZones.pointInZone(oP, theZone) then + table.insert(inZones, statO) + end + end + end + return inZones +end + function cfxZones.groupsOfCoalitionPartiallyInZone(coal, theZone, categ) -- categ is optional local groupsInZone = {} local allGroups = coalition.getGroups(coal, categ) @@ -1027,6 +1045,46 @@ function cfxZones.processCraterZones () end end --]]-- +-- +-- Flag Pulling +-- +function cfxZones.pollFlag(theFlag, method) + if cfxZones.verbose then + trigger.action.outText("+++zones: polling flag " .. theFlag .. " with " .. method, 30) + end + + method = method:lower() + local currVal = trigger.misc.getUserFlag(theFlag) + if method == "inc" or method == "f+1" then + trigger.action.setUserFlag(theFlag, currVal + 1) + + elseif method == "dec" or method == "f-1" then + trigger.action.setUserFlag(theFlag, currVal - 1) + + elseif method == "off" or method == "f=0" then + trigger.action.setUserFlag(theFlag, 0) + + elseif method == "flip" or method == "xor" then + if currVal ~= 0 then + trigger.action.setUserFlag(theFlag, 0) + else + trigger.action.setUserFlag(theFlag, 1) + end + + else + if method ~= "on" and method ~= "f=1" then + trigger.action.outText("+++zones: unknown method <" .. method .. "> - using 'on'", 30) + end + -- default: on. + trigger.action.setUserFlag(theFlag, 1) + end + + local newVal = trigger.misc.getUserFlag(theFlag) + if cfxZones.verbose then + trigger.action.outText("+++zones: flag <" .. theFlag .. "> changed from " .. currVal .. " to " .. newVal, 30) + end +end + -- -- PROPERTY PROCESSING diff --git a/modules/cloneZone.lua b/modules/cloneZone.lua index b70f0f0..fdbcd4c 100644 --- a/modules/cloneZone.lua +++ b/modules/cloneZone.lua @@ -1,5 +1,5 @@ cloneZones = {} -cloneZones.version = "1.0.1" +cloneZones.version = "1.1.0" cloneZones.verbose = false cloneZones.requiredLibs = { "dcsCommon", -- always @@ -15,6 +15,8 @@ cloneZones.cloners = {} Version History 1.0.0 - initial version 1.0.1 - preWipe attribute + 1.1.0 - support for static objects + - despawn? attribute --]]-- @@ -42,8 +44,10 @@ end function cloneZones.createClonerWithZone(theZone) -- has "Cloner" local localZones = cfxZones.allGroupsInZone(theZone) + local localObjects = cfxZones.allStaticsInZone(theZone) theZone.cloner = true -- this is a cloner zoner theZone.mySpawns = {} + theZone.myStatics = {} --theZone.groupVectors = {} theZone.origin = cfxZones.getPoint(theZone) -- save reference point for all groupVectors @@ -60,20 +64,30 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner" if not theZone.source then theZone.cloneNames = {} -- names of the groups. only present in template spawners + theZone.staticNames = {} -- names of all statics. only present in templates + for idx, aGroup in pairs(localZones) do local gName = aGroup:getName() if gName then table.insert(theZone.cloneNames, gName) table.insert(theZone.mySpawns, aGroup) -- collect them for initial despawn - end - + end end + for idx, aStatic in pairs (localObjects) do + local sName = aStatic:getName() + if sName then + table.insert(theZone.staticNames, sName) + table.insert(theZone.myStatics, aStatic) + end + end + cloneZones.despawnAll(theZone) - if #theZone.cloneNames < 1 then + if (#theZone.cloneNames + #theZone.staticNames) < 1 then if cloneZones.verbose then trigger.action.outText("+++clnZ: WARNING - Template in clone zone <" .. theZone.name .. "> is empty", 30) end - theZone.cloneNames = nil + theZone.cloneNames = nil + theZone.staticNames = nil end if cloneZones.verbose then trigger.action.outText(theZone.name .. " clone template saved", 30) @@ -85,11 +99,18 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner" theZone.spawnFlag = cfxZones.getStringFromZoneProperty(theZone, "f?", "none") theZone.lastSpawnValue = trigger.misc.getUserFlag(theZone.spawnFlag) -- save last value end + if cfxZones.hasProperty(theZone, "spawn?") then theZone.spawnFlag = cfxZones.getStringFromZoneProperty(theZone, "spawn?", "none") theZone.lastSpawnValue = trigger.misc.getUserFlag(theZone.spawnFlag) -- save last value end + -- deSpawn? + if cfxZones.hasProperty(theZone, "deSpawn?") then + theZone.deSpawnFlag = cfxZones.getStringFromZoneProperty(theZone, "deSpawn?", "none") + theZone.lastDeSpawnValue = trigger.misc.getUserFlag(theZone.deSpawnFlag) -- save last value + end + theZone.onStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", false) theZone.moveRoute = cfxZones.getBoolFromZoneProperty(theZone, "moveRoute", false) @@ -123,7 +144,14 @@ function cloneZones.despawnAll(theZone) for idx, aGroup in pairs(theZone.mySpawns) do Group.destroy(aGroup) end + for idx, aStatic in pairs(theZone.myStatics) do + -- warning! may be mismatch because we are looking at groups + -- not objects. let's see + trigger.action.outText("Destroying static <" .. aStatic:getName() .. ">", 30) + Object.destroy(aStatic) -- we don't aStatio:destroy() to find out what it is + end theZone.mySpawns = {} + theZone.myStatics = {} end function cloneZones.updateLocationsInGroupData(theData, zoneDelta, adjustAllWaypoints) @@ -226,6 +254,7 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone) local zoneDelta = dcsCommon.vSub(newCenter, theZone.origin) local spawnedGroups = {} + local spawnedStatics = {} for idx, aGroupName in pairs(theZone.cloneNames) do local rawData, cat, ctry = cfxMX.getGroupFromDCSbyName(aGroupName) @@ -237,7 +266,6 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone) -- now use raw data to spawn and see if it works outabox local theCat = cfxMX.catText2ID(cat) - --TODO: if theCat == -1 the group is static, may need to code for that -- update their position if not spawning to exact same location cloneZones.updateLocationsInGroupData(rawData, zoneDelta, spawnZone.moveRoute) @@ -245,7 +273,7 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone) -- apply turning dcsCommon.rotateGroupData(rawData, spawnZone.turn, newCenter.x, newCenter.z) - -- make sure all names (group and units) are unique + -- make sure unit and group names are unique cloneZones.uniqueNameGroupData(rawData) -- see waht country we spawn for @@ -255,7 +283,45 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone) table.insert(spawnedGroups, theGroup) end - return spawnedGroups + -- static spawns + for idx, aStaticName in pairs(theZone.staticNames) do + local rawData, cat, ctry, parent = cfxMX.getStaticFromDCSbyName(aStaticName) + + if not rawData then + trigger.action.outText("Static Clone: no such group <"..aStaticName .. ">", 30) + + elseif rawData.name == aStaticName then + trigger.action.outText("Static Clone: suxess!!! <".. aStaticName ..">", 30) + + else + trigger.action.outText("Static Clone: FAILED name check for <" .. aStaticName .. ">", 30) + end + + -- now use raw data to spawn and see if it works outabox + local theCat = cfxMX.catText2ID(cat) -- will be "static" + + -- move origin + rawData.x = rawData.x + zoneDelta.x + rawData.y = rawData.y + zoneDelta.z -- !!! + + -- apply turning + dcsCommon.rotateUnitData(rawData, spawnZone.turn, newCenter.x, newCenter.z) + + -- make sure static name is unique +-- cloneZones.uniqueNameGroupData(rawData) + rawData.name = dcsCommon.uuid(rawData.name) + rawData.unitID = nil -- simply forget, will be newly issued + + -- see waht country we spawn for + ctry = cloneZones.resolveOwnership(spawnZone, ctry) + + local theStatic = coalition.addStaticObject(ctry, rawData) + table.insert(spawnedStatics, theStatic) + --]]-- + trigger.action.outText("Static spawn: spawned " .. aStaticName, 30) + end + + return spawnedGroups, spawnedStatics end function cloneZones.spawnWithCloner(theZone) @@ -307,46 +373,74 @@ function cloneZones.spawnWithCloner(theZone) cloneZones.despawnAll(theZone) end --- local myLoc = cfxZones.getPoint(theZone) - local theClones = cloneZones.spawnWithTemplateForZone(templateZone, theZone) + + local theClones, theStatics = cloneZones.spawnWithTemplateForZone(templateZone, theZone) -- reset hasClones so we know our spawns are full and we can -- detect complete destruction - if theClones and #theClones > 0 then + if (theClones and #theClones > 0) or + (theStatics and #theStatics > 0) + then theZone.hasClones = true theZone.mySpawns = theClones + theZone.myStatics = theStatics + else + theZone.hasClones = false + theZone.mySpawns = {} + theZone.myStatics = {} end end function cloneZones.countLiveUnits(theZone) if not theZone then return 0 end - if not theZone.mySpawns then return 0 end local count = 0 - for idx, aGroup in pairs(theZone.mySpawns) do - if aGroup:isExist() then - local allUnits = aGroup:getUnits() - for idy, aUnit in pairs(allUnits) do - if aUnit:isExist() and aUnit:getLife() >= 1 then - count = count + 1 + -- count units + if theZone.mySpawns then + for idx, aGroup in pairs(theZone.mySpawns) do + if aGroup:isExist() then + local allUnits = aGroup:getUnits() + for idy, aUnit in pairs(allUnits) do + if aUnit:isExist() and aUnit:getLife() >= 1 then + count = count + 1 + end end end end end + + -- count statics + if theZone.myStatics then + for idx, aStatic in pairs(theZone.myStatics) do + if aStatic:isExist() and aStatic:getLife() >= 1 then + count = count + 1 + end + end + end return count end function cloneZones.hasLiveUnits(theZone) if not theZone then return 0 end - if not theZone.mySpawns then return 0 end - for idx, aGroup in pairs(theZone.mySpawns) do - if aGroup:isExist() then - local allUnits = aGroup:getUnits() - for idy, aUnit in pairs(allUnits) do - if aUnit:isExist() and aUnit:getLife() >= 1 then - return true + if theZone.mySpawns then + for idx, aGroup in pairs(theZone.mySpawns) do + if aGroup:isExist() then + local allUnits = aGroup:getUnits() + for idy, aUnit in pairs(allUnits) do + if aUnit:isExist() and aUnit:getLife() >= 1 then + return true + end end end end + end + + if theZone.myStatics then + for idx, aStatic in pairs(theZone.myStatics) do + if aStatic:isExist() and aStatic.getLife() >= 1 then + return true + end + end end + return false end @@ -362,7 +456,17 @@ function cloneZones.update() timer.scheduleFunction(cloneZones.update, {}, timer.getTime() + 1) for idx, aZone in pairs(cloneZones.cloners) do - -- see if pulse is running + -- see if deSpawn was pulled. Must run before spawn + if aZone.deSpawnFlag then + local currTriggerVal = trigger.misc.getUserFlag(aZone.deSpawnFlag) + if currTriggerVal ~= aZone.lastDeSpawnValue then + if cloneZones.verbose then + trigger.action.outText("+++clnZ: DEspawn triggered for <" .. aZone.name .. ">", 30) + end + cloneZones.despawnAll(aZone) + aZone.lastDeSpawnValue = currTriggerVal + end + end -- see if we got spawn? command if aZone.spawnFlag then @@ -386,6 +490,8 @@ function cloneZones.update() aZone.hasClones = false end end + + end end diff --git a/modules/countDown.lua b/modules/countDown.lua new file mode 100644 index 0000000..07a4239 --- /dev/null +++ b/modules/countDown.lua @@ -0,0 +1,216 @@ +countDown = {} +countDown.version = "1.0.0" +countDown.verbose = true +countDown.requiredLibs = { + "dcsCommon", -- always + "cfxZones", -- Zones, of course +} + +--[[-- + count down on flags to generate new signal on out + Copyright (c) 2022 by Christian Franz and cf/x AG + + Version History + 1.0.0 - initial version + +--]]-- + +countDown.counters = {} + + +-- +-- add/remove zones +-- +function countDown.addCountDown(theZone) + table.insert(countDown.counters, theZone) +end + +function countDown.getCountDownZoneByName(aName) + for idx, aZone in pairs(countDown.counters) do + if aName == aZone.name then return aZone end + end + if countDown.verbose then + trigger.action.outText("+++cntD: no count down with name <" .. aName ..">", 30) + end + + return nil +end + +-- +-- read attributes +-- +function countDown.createCountDownWithZone(theZone) + -- start val - a range + theZone.startMinVal, theZone.startMaxVal = cfxZones.getPositiveRangeFromZoneProperty(theZone, "countDown", 1) -- we know this exists + theZone.currVal = dcsCommon.randomBetween(theZone.startMinVal, theZone.startMaxVal) + + if countDown.verbose then + trigger.action.outText("+++cntD: initing count down <" .. theZone.name .. "> with " .. theZone.currVal, 30) + end + + + -- loop + theZone.loop = cfxZones.getBoolFromZoneProperty(theZone, "loop", false) + + -- extend after zero + theZone.belowZero = cfxZones.getBoolFromZoneProperty(theZone, "belowZero", false) + + -- method + theZone.method = cfxZones.getStringFromZoneProperty(theZone, "method", "flip") + + -- trigger flag "count" / "start?" + if cfxZones.hasProperty(theZone, "count?") then + theZone.triggerFlag = cfxZones.getStringFromZoneProperty(theZone, "count?", "none") + end + + + -- can also use in? for counting. we always use triggerflag + if cfxZones.hasProperty(theZone, "in?") then + theZone.triggerFlag = cfxZones.getStringFromZoneProperty(theZone, "in?", "none") + end + + if theZone.triggerFlag then + theZone.lastTriggerValue = trigger.misc.getUserFlag(theZone.triggerFlag) -- save last value + end + + -- zero! bang + if cfxZones.hasProperty(theZone, "zero!") then + theZone.zeroFlag = cfxZones.getNumberFromZoneProperty(theZone, "zero!", -1) + end + + if cfxZones.hasProperty(theZone, "out!") then + theZone.zeroFlag = cfxZones.getNumberFromZoneProperty(theZone, "out!", -1) + end + + -- TMinus! bang + if cfxZones.hasProperty(theZone, "tMinus!") then + theZone.tMinusFlag = cfxZones.getNumberFromZoneProperty(theZone, "tMinus!", -1) + end + +end + +-- +-- Update +-- +function countDown.isTriggered(theZone) + -- this module has triggered + local val = theZone.currVal - 1 -- decrease counter + if theZone.verbose then + trigger.action.outText("+++cntD: enter triggered: val now: " .. val, 30) + end + if val > 0 then + + -- see if we need to bang Tminus + if theZone.tMinusFlag then + if theZone.verbose then + trigger.action.outText("+++cntD: TMINUTS", 30) + end + cfxZones.pollFlag(theZone.tMinusFlag, theZone.method) + end + + elseif val == 0 then + -- reached zero + if theZone.zeroFlag then + if theZone.verbose then + trigger.action.outText("+++cntD: ZERO", 30) + end + cfxZones.pollFlag(theZone.zeroFlag, theZone.method) + end + + if theZone.loop then + -- restart time + if theZone.verbose then + trigger.action.outText("+++cntD: Looping", 30) + end + val = dcsCommon.randomBetween(theZone.startMinVal, theZone.startMaxVal) + end + + else + -- below zero + if theZone.belowZero and theZone.zeroFlag then + if theZone.verbose then + trigger.action.outText("+++cntD: Below Zero", 30) + end + cfxZones.pollFlag(theZone.zeroFlag, theZone.method) + end + + end + + theZone.currVal = val + +end + +function countDown.update() + -- call me in a second to poll triggers + timer.scheduleFunction(countDown.update, {}, timer.getTime() + 1) + + for idx, aZone in pairs(countDown.counters) do + -- make sure to re-start before reading time limit + if aZone.triggerFlag then + local currTriggerVal = trigger.misc.getUserFlag(aZone.triggerFlag) + if currTriggerVal ~= aZone.lastTriggerValue + then + if aZone.verbose then + trigger.action.outText("+++cntD: triggered on in?", 30) + end + countDown.isTriggered(aZone) + aZone.lastTriggerValue = trigger.misc.getUserFlag(aZone.triggerFlag) -- save last value + end + end + end +end + +-- +-- Config & Start +-- +function countDown.readConfigZone() + local theZone = cfxZones.getZoneByName("countDownConfig") + if not theZone then + if countDown.verbose then + trigger.action.outText("+++cntD: NO config zone!", 30) + end + return + end + + countDown.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false) + + if countDown.verbose then + trigger.action.outText("+++cntD: read config", 30) + end +end + +function countDown.start() + -- lib check + if not dcsCommon.libCheck then + trigger.action.outText("cfx Count Down requires dcsCommon", 30) + return false + end + if not dcsCommon.libCheck("cfx Count Down", countDown.requiredLibs) then + return false + end + + -- read config + countDown.readConfigZone() + + -- process cloner Zones + local attrZones = cfxZones.getZonesWithAttributeNamed("countDown") + for k, aZone in pairs(attrZones) do + countDown.createCountDownWithZone(aZone) -- process attributes + countDown.addCountDown(aZone) -- add to list + end + + + -- start update + countDown.update() + + trigger.action.outText("cfx Count Down v" .. countDown.version .. " started.", 30) + return true +end + +-- let's go! +if not countDown.start() then + trigger.action.outText("cfx Count Down aborted: missing libraries", 30) + countDown = nil +end + +-- additions: range for start value to randomize \ No newline at end of file diff --git a/modules/dcsCommon.lua b/modules/dcsCommon.lua index 40a00aa..925e774 100644 --- a/modules/dcsCommon.lua +++ b/modules/dcsCommon.lua @@ -1,5 +1,5 @@ dcsCommon = {} -dcsCommon.version = "2.5.3" +dcsCommon.version = "2.5.4" --[[-- VERSION HISTORY 2.2.6 - compassPositionOfARelativeToB - clockPositionOfARelativeToB @@ -59,6 +59,10 @@ dcsCommon.version = "2.5.3" 2.5.2 - added copyArray method - corrected heading in createStaticObjectData 2.5.3 - corrected rotateGroupData bug for cz + - removed forced error in failed pickRandom + 2.5.4 - rotateUnitData() + - randomBetween() + --]]-- -- dcsCommon is a library of common lua functions @@ -85,6 +89,33 @@ dcsCommon.version = "2.5.3" return canRun end + -- returns only positive values, lo must be >0 and <= hi + function dcsCommon.randomBetween(loBound, hiBound) + if not loBound then loBound = 1 end + if not hiBound then hiBound = 1 end + if loBound == hiBound then return loBound end + + local delayMin = loBound + local delayMax = hiBound + local delay = delayMax + + if delayMin ~= delayMax then + -- pick random in range , say 3-7 --> 5 s! + local delayDiff = (delayMax - delayMin) + 1 -- 7-3 + 1 + delay = dcsCommon.smallRandom(delayDiff) - 1 --> 0-4 + delay = delay + delayMin + if delay > delayMax then delay = delayMax end + if delay < 1 then delay = 1 end + + if dcsCommon.verbose then + trigger.action.outText("+++dcsC: delay range " .. delayMin .. "-" .. delayMax .. ": selected " .. delay, 30) + end + end + + return delay + end + + -- taken inspiration from mist, as dcs lua has issues with -- random numbers smaller than 50. Given a range of x numbers 1..x, it is -- repeated a number of times until it fills an array of at least @@ -140,7 +171,7 @@ dcsCommon.version = "2.5.3" if #theTable < 1 then trigger.action.outText("*** warning: zero choice in pick random", 30) - local k = i.ll + --local k = i.ll return nil end if #theTable == 1 then return theTable[1] end @@ -1443,6 +1474,26 @@ dcsCommon.version = "2.5.3" return px, py end + function dcsCommon.rotateUnitData(theUnit, degrees, cx, cy) + if not cx then cx = 0 end + if not cz then cz = 0 end + local cy = cz + --trigger.action.outText("+++dcsC:rotGrp cy,cy = "..cx .. "," .. cy, 30) + + local rads = degrees * 3.14152 / 180 + do + theUnit.x = theUnit.x - cx -- MOVE TO ORIGIN OF ROTATION + theUnit.y = theUnit.y - cy + theUnit.x, theUnit.y = dcsCommon.rotatePointAroundOrigin(theUnit.x, theUnit.y, degrees) + theUnit.x = theUnit.x + cx -- MOVE BACK + theUnit.y = theUnit.y + cy + + -- may also want to increase heading by degreess + theUnit.heading = theUnit.heading + rads + end + end + + function dcsCommon.rotateGroupData(theGroup, degrees, cx, cz) if not cx then cx = 0 end if not cz then cz = 0 end diff --git a/modules/delayFlags.lua b/modules/delayFlags.lua index 934c2d5..961b85d 100644 --- a/modules/delayFlags.lua +++ b/modules/delayFlags.lua @@ -15,6 +15,10 @@ delayFlag.flags = {} Version History 1.0.0 - Initial Version + 1.0.1 - message attribute + 1.0.2 - slight spelling correction + - using cfxZones for polling + - removed pollFlag --]]-- @@ -75,7 +79,7 @@ function delayFlag.createTimerWithZone(theZone) -- message if cfxZones.hasProperty(theZone, "message") then - theZone.myMessage = cfxZones.getBoolStringZoneProperty(theZone, "message", "") + theZone.myMessage = cfxZones.getStringZoneProperty(theZone, "message", "") end -- init @@ -88,6 +92,7 @@ end -- -- do the pulling -- +--[[-- function delayFlag.pollFlag(theFlag, method) if delayFlag.verbose then trigger.action.outText("+++dlyF: polling flag " .. theFlag .. " with " .. method, 30) @@ -113,7 +118,7 @@ function delayFlag.pollFlag(theFlag, method) else if method ~= "on" and method ~= "f=1" then - trigger.action.outText("+++RND: unknown method <" .. method .. "> - using 'on'", 30) + trigger.action.outText("+++dlyF: unknown method <" .. method .. "> - using 'on'", 30) end -- default: on. trigger.action.setUserFlag(theFlag, 1) @@ -124,7 +129,7 @@ function delayFlag.pollFlag(theFlag, method) trigger.action.outText("+++dlyF flag <" .. theFlag .. "> changed from " .. currVal .. " to " .. newVal, 30) end end - +--]]-- -- -- update -- @@ -184,7 +189,7 @@ function delayFlag.update() -- end timer aZone.running = false -- poll flag - delayFlag.pollFlag(aZone.outFlag, aZone.method) + cfxZones.pollFlag(aZone.outFlag, aZone.method) -- say message if aZone.myMessage then trigger.action.outText(aZone.myMessage, 30) diff --git a/modules/pulseFlags.lua b/modules/pulseFlags.lua index 8d087c4..128e470 100644 --- a/modules/pulseFlags.lua +++ b/modules/pulseFlags.lua @@ -1,5 +1,5 @@ pulseFlags = {} -pulseFlags.version = "1.0.0" +pulseFlags.version = "1.0.1" pulseFlags.verbose = false pulseFlags.requiredLibs = { "dcsCommon", -- always @@ -12,6 +12,7 @@ pulseFlags.requiredLibs = { Version History - 1.0.0 Initial version + - 1.0.1 pause behavior debugged --]]-- @@ -50,6 +51,7 @@ function pulseFlags.createPulseWithZone(theZone) theZone.paused = cfxZones.getBoolFromZoneProperty(theZone, "paused", false) + theZone.method = cfxZones.getStringFromZoneProperty(theZone, "method", "flip") -- done flag @@ -148,7 +150,7 @@ function pulseFlags.doPulse(args) --trigger.action.outText("***PulF: pulse <" .. theZone.name .. "> scheduled in ".. delay .."!", 30) -- schedule in delay time - timer.scheduleFunction(pulseFlags.doPulse, args, timer.getTime() + delay) + theZone.timerID = timer.scheduleFunction(pulseFlags.doPulse, args, timer.getTime() + delay) if pulseFlags.verbose then trigger.action.outText("+++PulF: pulse <" .. theZone.name .. "> rescheduled in " .. delay, 30) end @@ -194,7 +196,8 @@ function pulseFlags.update() then trigger.action.outText("+++PulF: activating <" .. aZone.name .. ">", 30) aZone.lastActivateValue = currTriggerVal - theZone.paused = false -- will start anew + aZone.paused = false -- will start anew + end end @@ -204,7 +207,11 @@ function pulseFlags.update() then trigger.action.outText("+++PulF: pausing <" .. aZone.name .. ">", 30) aZone.lastPauseValue = currTriggerVal - theZone.paused = true -- will start anew + aZone.paused = true -- prevents new start + if aZone.timerID then + timer.removeFunction(aZone.timerID) + aZone.timerID = nil + end end end end diff --git a/tutorial & demo missions/demo - Attack of the CloneZ.miz b/tutorial & demo missions/demo - Attack of the CloneZ.miz index 605cbee..a214033 100644 Binary files a/tutorial & demo missions/demo - Attack of the CloneZ.miz and b/tutorial & demo missions/demo - Attack of the CloneZ.miz differ diff --git a/tutorial & demo missions/demo - once, twice, three times a maybe.miz b/tutorial & demo missions/demo - once, twice, three times a maybe.miz new file mode 100644 index 0000000..e30f7c3 Binary files /dev/null and b/tutorial & demo missions/demo - once, twice, three times a maybe.miz differ