Version 0.96

rndZone, pulseZone
This commit is contained in:
Christian Franz 2022-01-27 18:25:58 +01:00
parent bcf319b0df
commit 46193f0ba3
16 changed files with 955 additions and 47 deletions

Binary file not shown.

View File

@ -1,17 +1,21 @@
FARPZones = {}
FARPZones.version = "1.0.2"
FARPZones.version = "1.1.0"
FARPZones.verbose = false
--[[--
Version History
1.0.0 - Initial Version
1.0.1 - support "none" as defender types
- default types for defenders to none
1.0.2 - hiddenRed, hiddenBlue, hiddenGrey
1.1.0 - config zone
- rFormation attribute added
- verbose flag
- verbose cleanup ("FZ: something happened")
--]]--
FARPZones.requiredLibs = {
"dcsCommon", -- common is of course needed for everything
-- pretty stupid to check for this since we
-- need common to invoke the check, but anyway
"dcsCommon",
"cfxZones", -- Zones, of course
-- "cfxCommander", -- to make troops do stuff
-- "cfxGroundTroops", -- generic when dropping troops
@ -134,25 +138,29 @@ function FARPZones.createFARPFromZone(aZone)
aZone,
"rPhiHDef",
3)
-- trigger.action.outText("*** DEF rPhi are " .. rPhi[1] .. " and " .. rPhi[2], 30)
--trigger.action.outText("*** DEF rPhi are " .. rPhi[1] .. " and " .. rPhi[2] .. " heading " .. rPhi[3], 30)
-- get r and phi for facilities
-- create a new defenderzone for this
local r = rPhi[1]
local phi = rPhi[2] * 0.0174533 -- 1 degree = 0.0174533 rad
local dx = aZone.point.x + r * math.cos(phi)
local dz = aZone.point.z + r * math.sin(phi)
theFarp.defZone = cfxZones.createSimpleZone(aZone.name .. "-Def", {x=dx, y = 0, z=dz}, 100)
local formRad = cfxZones.getNumberFromZoneProperty(aZone, "rFormation", 100)
theFarp.defZone = cfxZones.createSimpleZone(aZone.name .. "-Def", {x=dx, y = 0, z=dz}, formRad)
theFarp.defHeading = rPhi[3]
rPhi = {}
rPhi = cfxZones.getVectorFromZoneProperty(
aZone,
"rPhiHRes",
3) -- optional, will reterurn {0,0} else
-- trigger.action.outText("*** RES rPhi are " .. rPhi[1] .. " and " .. rPhi[2] .. " heading " .. rPhi[3], 30)
3)
--trigger.action.outText("*** RES rPhi are " .. rPhi[1] .. " and " .. rPhi[2] .. " heading " .. rPhi[3], 30)
r = rPhi[1]
phi = rPhi[2] * 0.0174533 -- 1 degree = 0.0174533 rad
dx = aZone.point.x + r * math.cos(phi)
dz = aZone.point.z + r * math.sin(phi)
theFarp.resZone = cfxZones.createSimpleZone(aZone.name .. "-Res", {x=dx, y = 0, z=dz}, 50)
theFarp.resHeading = rPhi[3]
@ -307,7 +315,10 @@ function FARPZones.produceVehicles(theFarp)
table.insert(unitTypes, "Soldier M4") -- make it one m4 trooper as fallback
end
-- trigger.action.outText("*** ENTER produce vehicles, will produce " .. theTypes , 30)
if FARPZones.verbose then
trigger.action.outText("*** ENTER produce DEF vehicles, will produce " .. theTypes , 30)
end
local theCoalition = theFarp.owner
if theTypes ~= "none" then
@ -364,12 +375,14 @@ function FARPZones.somethingHappened(event)
local theUnit = event.initiator
local ID = event.id
trigger.action.outText("FZ: something happened", 30)
--trigger.action.outText("FZ: something happened", 30)
local aFarp = event.place
local zonedFarp = FARPZones.getFARPZoneForFARP(aFarp)
if not zonedFarp then
trigger.action.outText("Hand change, NOT INTERESTING", 30)
if FARPZones.verbose then
trigger.action.outText("Hand change, NOT INTERESTING", 30)
end
return
end
@ -380,9 +393,7 @@ function FARPZones.somethingHappened(event)
trigger.action.outSound("Quest Snare 3.wav")
zonedFarp.owner = newOwner
zonedFarp.zone.owner = newOwner
-- better: sound winm and lose to different sides
-- update color in map
-- FARPZones.drawFarp(zonedFarp)
FARPZones.drawFARPCircleInMap(zonedFarp)
-- remove all existing resources immediately,
@ -406,6 +417,23 @@ end
--
-- Start
--
function FARPZones.readConfig()
local theZone = cfxZones.getZoneByName("farpZonesConfig")
if not theZone then
if FARPZones.verbose then
trigger.action.outText("***frpZ: NO config zone!", 30)
end
return
end
FARPZones.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
FARPZones.spinUpDelay = cfxZones.getNumberFromZoneProperty(theZone, "spinUpDelay", 30)
if FARPZones.verbose then
trigger.action.outText("***frpZ: read config", 30)
end
end
function FARPZones.start()
@ -417,6 +445,9 @@ function FARPZones.start()
FARPZones.startingUp = true
-- read config zone
FARPZones.readConfig()
-- install callbacks for FARP-relevant events
dcsCommon.addEventHandler(FARPZones.somethingHappened,
FARPZones.preProcessor,
@ -427,10 +458,11 @@ function FARPZones.start()
for k, aZone in pairs(theZones) do
local aFARP = FARPZones.createFARPFromZone(aZone) -- read attributes from DCS
FARPZones.addFARPZone(aFARP) -- add to managed zones
-- FARPZones.drawFarp(aFARP)
FARPZones.drawFARPCircleInMap(aFARP) -- mark in map
FARPZones.produceVehicles(aFARP) -- allocate initial vehicles
--trigger.action.outText("processed FARP " .. aZone.name .. " now owned by " .. aZone.owner, 30)
if FARPZones.verbose then
trigger.action.outText("processed FARP <" .. aZone.name .. "> now owned by " .. aZone.owner, 30)
end
end
FARPZones.startingUp = false

350
modules/RNDFlags.lua Normal file
View File

@ -0,0 +1,350 @@
rndFlags = {}
rndFlags.version = "1.0.0"
rndFlags.verbose = false
rndFlags.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
}
--[[
Random Flags: DML module to select flags at random
and then change them
Copyright 2022 by Christian Franz and cf/x
Version History
1.0.0 - Initial Version
--]]
rndFlags.rndGen = {}
function rndFlags.addRNDZone(aZone)
table.insert(rndFlags.rndGen, aZone)
end
function rndFlags.flagArrayFromString(inString)
if string.len(inString) < 1 then
trigger.action.outText("+++RND: empty flags", 30)
return {}
end
if rndFlags.verbose then
trigger.action.outText("+++RND: processing <" .. inString .. ">", 30)
end
local flags = {}
local rawElements = dcsCommon.splitString(inString, ",")
for idx, anElement in pairs(rawElements) do
if dcsCommon.containsString(anElement, "-") then
-- interpret this as a range
local theRange = dcsCommon.splitString(anElement, "-")
local lowerBound = theRange[1]
lowerBound = tonumber(lowerBound)
local upperBound = theRange[2]
upperBound = tonumber(upperBound)
if lowerBound and upperBound then
-- swap if wrong order
if lowerBound > upperBound then
local temp = upperBound
upperBound = lowerBound
lowerBound = temp
end
-- now add add numbers to flags
for f=lowerBound, upperBound do
table.insert(flags, f)
--trigger.action.outText("+++RND: added <" .. f .. "> (range)", 30)
end
else
-- bounds illegal
trigger.action.outText("+++RND: ignored range <" .. anElement .. "> (range)", 30)
end
else
-- single number
f = tonumber(anElement)
if f then
table.insert(flags, f)
--trigger.action.outText("+++RND: added <" .. f .. "> (single)", 30)
else
trigger.action.outText("+++RND: ignored element <" .. anElement .. "> (single)", 30)
end
end
end
if rndFlags.verbose then
trigger.action.outText("+++RND: <" .. #flags .. "> flags total", 30)
end
return flags
end
--
-- create rnd gen from zone
--
function rndFlags.createRNDWithZone(theZone)
local flags = cfxZones.getStringFromZoneProperty(theZone, "flags!", "")
if flags == "" then
-- let's try alternate spelling without "!"
flags = cfxZones.getStringFromZoneProperty(theZone, "flags", "")
end
-- now build the flag array from strings
local theFlags = rndFlags.flagArrayFromString(flags)
theZone.myFlags = theFlags
theZone.pollSizeMin, theZone.pollSize = cfxZones.getPositiveRangeFromZoneProperty(theZone, "pollSize", 1)
if rndFlags.verbose then
trigger.action.outText("+++RND: pollSize is <" .. theZone.pollSizeMin .. ", " .. theZone.pollSize .. ">", 30)
end
theZone.remove = cfxZones.getBoolFromZoneProperty(theZone, "remove", false)
-- trigger flag
if cfxZones.hasProperty(theZone, "f?") then
theZone.triggerFlag = cfxZones.getStringFromZoneProperty(theZone, "f?", "none")
end
if theZone.triggerFlag then
theZone.lastTriggerValue = trigger.misc.getUserFlag(theZone.triggerFlag) -- save last value
end
theZone.onStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", false)
if not theZone.onStart and not theZone.triggerFlag then
theZone.onStart = true
end
theZone.method = cfxZones.getStringFromZoneProperty(theZone, "method", "on")
theZone.reshuffle = cfxZones.getBoolFromZoneProperty(theZone, "reshuffle", false)
if theZone.reshuffle then
-- create a backup copy we can reshuffle from
theZone.flagStore = dcsCommon.copyArray(theFlags)
end
--theZone.rndPollSize = cfxZones.getBoolFromZoneProperty(theZone, "rndPollSize", false)
-- done flag
if cfxZones.hasProperty(theZone, "done+1") then
theZone.doneFlag = cfxZones.getStringFromZoneProperty(theZone, "done+1", "none")
end
end
function rndFlags.reshuffle(theZone)
if rndFlags.verbose then
trigger.action.outText("+++RND: reshuffling zone " .. theZone.name, 30)
end
theZone.myFlags = dcsCommon.copyArray(theZone.flagStore)
end
--
-- fire RND
--
function rndFlags.pollFlag(theFlag, method)
if rndFlags.verbose then
trigger.action.outText("+++RND: 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("+++RND: unknown method <" .. method .. "> - using 'on'", 30)
end
-- default: on.
trigger.action.setUserFlag(theFlag, 1)
end
local newVal = trigger.misc.getUserFlag(theFlag)
if rndFlags.verbose then
trigger.action.outText("+++RND: flag <" .. theFlag .. "> changed from " .. currVal .. " to " .. newVal, 30)
end
end
function rndFlags.fire(theZone)
-- fire this rnd
-- create a local copy of all flags
if theZone.reshuffle and #theZone.myFlags < 1 then
rndFlags.reshuffle(theZone)
end
local availableFlags = dcsCommon.copyArray(theZone.myFlags)--{}
-- for idx, aFlag in pairs(theZone.myFlags) do
-- table.insert(availableFlags, aFlag)
-- end
-- do this pollSize times
local pollSize = theZone.pollSize
local pollSizeMin = theZone.pollSizeMin
if pollSize ~= pollSizeMin then
-- pick random in range , say 3-7 --> 5 items!
pollSize = (pollSize - pollSizeMin) + 1 -- 7-3 + 1
pollSize = dcsCommon.smallRandom(pollSize) - 1 --> 0-4
-- trigger.action.outText("+++RND: RAW pollsize " .. pollSize, 30)
pollSize = pollSize + pollSizeMin
-- trigger.action.outText("+++RND: adj pollsize " .. pollSize, 30)
if pollSize > theZone.pollSize then pollSize = theZone.pollSize end
if pollSize < 1 then pollSize = 1 end
if rndFlags.verbose then
trigger.action.outText("+++RND: RND " .. theZone.name .. " range " .. pollSizeMin .. "-" .. theZone.pollSize .. ": selected " .. pollSize, 30)
end
end
if #availableFlags < 1 then
if rndFlags.verbose then
trigger.action.outText("+++RND: RND " .. theZone.name .. " ran out of flags. aborting fire", 30)
end
if theZone.doneFlag then
local currVal = trigger.misc.getUserFlag(theZone.doneFlag)
trigger.action.setUserFlag(theZone.doneFlag, currVal + 1)
end
return
end
if rndFlags.verbose then
trigger.action.outText("+++RND: firing RND " .. theZone.name .. " with pollsize " .. pollSize .. " on " .. #availableFlags .. " set size", 30)
end
for i=1, pollSize do
-- check there are still flags left
if #availableFlags < 1 then
trigger.action.outText("+++RND: no flags left in " .. theZone.name .. " in index " .. i, 30)
theZone.myFlags = {}
if theZone.reshuffle then
rndFlags.reshuffle(theZone)
end
return
end
-- select a flag, enforce uniqueness
local theFlagIndex = dcsCommon.smallRandom(#availableFlags)
-- poll this flag and remove from available
local theFlag = table.remove(availableFlags,theFlagIndex)
rndFlags.pollFlag(theFlag, theZone.method)
end
-- remove if requested
if theZone.remove then
theZone.myFlags = availableFlags
end
end
--
-- update
--
function rndFlags.update()
-- call me in a second to poll triggers
timer.scheduleFunction(rndFlags.update, {}, timer.getTime() + 1)
for idx, aZone in pairs(rndFlags.rndGen) do
if aZone.triggerFlag then
local currTriggerVal = trigger.misc.getUserFlag(aZone.triggerFlag)
if currTriggerVal ~= aZone.lastTriggerValue
then
if rndFlags.verbose then
trigger.action.outText("+++RND: triggering " .. aZone.name, 30)
end
rndFlags.fire(aZone)
aZone.lastTriggerValue = currTriggerVal
end
end
end
end
--
-- start cycle: force all onStart to fire
--
function rndFlags.startCycle()
for idx, theZone in pairs(rndFlags.rndGen) do
if theZone.onStart then
trigger.action.outText("+++RND: starting " .. theZone.name, 30)
rndFlags.fire(theZone)
end
end
end
--
-- start module and read config
--
function rndFlags.readConfigZone()
-- note: must match exactly!!!!
local theZone = cfxZones.getZoneByName("rndFlagsConfig")
if not theZone then
if rndFlags.verbose then
trigger.action.outText("***RND: NO config zone!", 30)
end
return
end
rndFlags.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
if rndFlags.verbose then
trigger.action.outText("***RND: read config", 30)
end
end
function rndFlags.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("RNDFlags requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx Random Flags",
rndFlags.requiredLibs) then
return false
end
-- read config
rndFlags.readConfigZone()
-- process RND Zones
local attrZones = cfxZones.getZonesWithAttributeNamed("RND")
-- now create an rnd gen for each one and add them
-- to our watchlist
for k, aZone in pairs(attrZones) do
rndFlags.createRNDWithZone(aZone) -- process attribute and add to zone
rndFlags.addRNDZone(aZone) -- remember it so we can smoke it
end
-- start cycle
timer.scheduleFunction(rndFlags.startCycle, {}, timer.getTime() + 0.25)
-- start update
timer.scheduleFunction(rndFlags.update, {}, timer.getTime() + 1)
trigger.action.outText("cfx random Flags v" .. rndFlags.version .. " started.", 30)
return true
end
-- let's go!
if not rndFlags.start() then
trigger.action.outText("cf/x RND Flags aborted: missing libraries", 30)
rndFlags = nil
end
--[[
pulser / repeat until
--]]

View File

@ -1,5 +1,5 @@
cargoSuper = {}
cargoSuper.version = "1.1.0"
cargoSuper.version = "1.1.1"
--[[--
version history
1.0.0 - initial version
@ -13,6 +13,7 @@ version history
- getAllCategoriesFor alias for getAllCargos
- getManifestForCategory alias for getManifestFor
- removeAllMassFor()
1.1.1 - deleteMassObject corrected index bug
CargoSuper manages weigth for a logical named unit. Weight can be added
to arbitrary categories like 'passengers', 'cargo' or "whatever". In order
@ -68,7 +69,7 @@ function cargoSuper.deleteMassObject(massObject)
else
theName = massObject.name
end
cargoSuper.massObjects[massName] = nil
cargoSuper.massObjects[theName] = nil -- 1.1.1 corrected to theName from massName
end
function cargoSuper.addMassObjectTo(name, category, theMassObject)

View File

@ -1,5 +1,5 @@
cfxNDB = {}
cfxNDB.version = "1.0.0"
cfxNDB.version = "1.1.0"
--[[--
cfxNDB:
@ -12,10 +12,20 @@ cfxNDB.version = "1.0.0"
correctly if it's longer than the module's refresh and
an even multiple of module's refresh, else it will be
refreshed at the next module update cycle
VERSION HISTORY
1.0.0 - initial version
1.1.0 - on? flag
- off? flag
- ups at 1, decoupled update from refresh
- paused flag, paused handling
- startNDB() can accept string
- stopNDB() can accept string
--]]--
cfxNDB.verbose = false
cfxNDB.ups = 10 -- every 10 seconds
cfxNDB.ups = 1 -- once every 1 second
cfxNDB.requiredLibs = {
"dcsCommon",
"cfxZones",
@ -30,6 +40,18 @@ cfxNDB.ndbs = {} -- all ndbs
--
function cfxNDB.startNDB(theNDB)
if type(theNDB) == "string" then
theNDB = cfxZones.getZoneByName(theNDB)
end
if not theNDB.freq then
-- this zone is not an NDB. Exit
if cfxNDB.verbose then
trigger.action.outText("+++ndb: start() -- " .. theNDB.name .. " is not a cfxNDB.", 30)
end
return
end
theNDB.ndbRefreshTime = timer.getTime() + theNDB.ndbRefresh -- only used in linkedUnit, but set up anyway
-- generate new ID
theNDB.ndbID = dcsCommon.uuid("ndb")
@ -47,10 +69,31 @@ function cfxNDB.startNDB(theNDB)
end
trigger.action.outText("+++ndb: started " .. theNDB.name .. dsc .. " at " .. theNDB.freq/1000000 .. "mod " .. modulation .. " with w=" .. theNDB.power .. " s=<" .. fileName .. ">", 30)
end
theNDB.paused = false
if cfxNDB.verbose then
trigger.action.outText("+++ndb: " .. theNDB.name .. " started", 30)
end
end
function cfxNDB.stopNDB(theNDB)
if type(theNDB) == "string" then
theNDB = cfxZones.getZoneByName(theNDB)
end
if not theNDB.freq then
-- this zone is not an NDB. Exit
if cfxNDB.verbose then
trigger.action.outText("+++ndb: stop() -- " .. theNDB.name .. " is not a cfxNDB.", 30)
end
return
end
trigger.action.stopRadioTransmission(theNDB.ndbID)
theNDB.paused = true
if cfxNDB.verbose then
trigger.action.outText("+++ndb: " .. theNDB.name .. " stopped", 30)
end
end
function cfxNDB.createNDBWithZone(theZone)
@ -65,8 +108,31 @@ function cfxNDB.createNDBWithZone(theZone)
-- when LARGER than module's refresh.
theZone.ndbRefresh = cfxZones.getNumberFromZoneProperty(theZone, "ndbRefresh", cfxNDB.refresh) -- only used if linked
theZone.ndbRefreshTime = timer.getTime() + theZone.ndbRefresh -- only used with linkedUnit, but set up nonetheless
-- paused
theZone.paused = cfxZones.getBoolFromZoneProperty(theZone, "paused", false)
-- on/offf query flags
if cfxZones.hasProperty(theZone, "on?") then
theZone.onFlag = cfxZones.getStringFromZoneProperty(theZone, "on?", "none")
end
if theZone.onFlag then
theZone.onFlagVal = trigger.misc.getUserFlag(theZone.onFlag) -- save last value
end
if cfxZones.hasProperty(theZone, "off?") then
theZone.offFlag = cfxZones.getStringFromZoneProperty(theZone, "off?", "none")
end
if theZone.offFlag then
theZone.offFlagVal = trigger.misc.getUserFlag(theZone.offFlag) -- save last value
end
-- start it
cfxNDB.startNDB(theZone)
if not theZone.paused then
cfxNDB.startNDB(theZone)
end
-- add it to my watchlist
table.insert(cfxNDB.ndbs, theZone)
@ -84,9 +150,30 @@ function cfxNDB.update()
-- moving with the linked unit
if theNDB.linkedUnit then
-- yupp, need to update
if now > theNDB.ndbRefreshTime then
cfxNDB.stopNDB(theNDB)
if (not theNDB.paused) and
(now > theNDB.ndbRefreshTime) then
cfxNDB.stopNDB(theNDB) -- also pauses
cfxNDB.startNDB(theNDB) -- turns off pause
end
end
-- now check triggers to start/stop
if theNDB.onFlagVal then
-- see if this changed
local currTriggerVal = trigger.misc.getUserFlag(theNDB.onFlag)
if currTriggerVal ~= theNDB.onFlagVal then
-- yupp, trigger start
cfxNDB.startNDB(theNDB)
theNDB.onFlagVal = currTriggerVal
end
end
if theNDB.offFlagVal then
local currTriggerVal = trigger.misc.getUserFlag(theNDB.offFlag)
if currTriggerVal ~= theNDB.offFlagVal then
-- yupp, trigger start
cfxNDB.stopNDB(theNDB)
theNDB.offFlagVal = currTriggerVal
end
end
end

View File

@ -1,5 +1,5 @@
cfxObjectSpawnZones = {}
cfxObjectSpawnZones.version = "1.1.3"
cfxObjectSpawnZones.version = "1.1.4"
cfxObjectSpawnZones.requiredLibs = {
"dcsCommon", -- common is of course needed for everything
-- pretty stupid to check for this since we
@ -22,6 +22,7 @@ cfxObjectSpawnZones.ups = 1
-- 1.1.2 - autoRemove option re-installed
-- - added possibility to autoUnlink
-- 1.1.3 - ME-triggered flag via f? and triggerFlag
-- 1.1.4 - activate?, pause? attributes
-- Object spawn zones have the following major uses:
-- - dynamically spawn cargo
@ -84,6 +85,16 @@ function cfxObjectSpawnZones.createSpawner(inZone)
theSpawner.lastTriggerValue = trigger.misc.getUserFlag(theSpawner.triggerFlag)
end
if cfxZones.hasProperty(inZone, "activate?") then
theSpawner.activateFlag = cfxZones.getStringFromZoneProperty(inZone, "activate?", "none")
theSpawner.lastActivateValue = trigger.misc.getUserFlag(theSpawner.activateFlag)
end
if cfxZones.hasProperty(inZone, "pause?") then
theSpawner.pauseFlag = cfxZones.getStringFromZoneProperty(inZone, "pause?", "none")
theSpawner.lastPauseValue = trigger.misc.getUserFlag(theSpawner.pauseFlag)
end
--theSpawner.types = cfxZones.getZoneProperty(inZone, "types")
theSpawner.types = cfxZones.getStringFromZoneProperty(inZone, "types", "White_Tyre")
local n = cfxZones.getNumberFromZoneProperty(inZone, "count", 1) -- DO NOT CONFUSE WITH OWN PROPERTY COUNT for unique names!!!
@ -410,6 +421,15 @@ function cfxObjectSpawnZones.update()
local needsSpawn = cfxObjectSpawnZones.needsSpawning(spawner)
-- check if perhaps our watchtrigger causes spawn
if spawner.pauseFlag then
local currTriggerVal = trigger.misc.getUserFlag(spawner.pauseFlag)
if currTriggerVal ~= spawner.lastPauseValue then
spawner.paused = true
needsSpawn = false
spawner.lastPauseValue = currTriggerVal
end
end
if spawner.triggerFlag then
local currTriggerVal = trigger.misc.getUserFlag(spawner.triggerFlag)
if currTriggerVal ~= spawner.lastTriggerValue then
@ -418,6 +438,17 @@ function cfxObjectSpawnZones.update()
end
end
if spawner.activateFlag then
local currTriggerVal = trigger.misc.getUserFlag(spawner.activateFlag)
if currTriggerVal ~= spawner.lastActivateValue then
spawner.paused = false
spawner.lastActivateValue = currTriggerVal
end
end
if needsSpawn then
cfxObjectSpawnZones.spawnWithSpawner(spawner)
if spawner.maxSpawns > 0 then

View File

@ -1,5 +1,5 @@
cfxSmokeZone = {}
cfxSmokeZone.version = "1.0.2"
cfxSmokeZone.version = "1.0.3"
cfxSmokeZone.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
@ -9,6 +9,9 @@ cfxSmokeZone.requiredLibs = {
1.0.0 - initial version
1.0.1 - added removeSmokeZone
1.0.2 - added altitude
1.0.3 - added paused attribute
- added f? attribute --> onFlag
- broke out startSmoke
SMOKE ZONES *** EXTENDS ZONES ***
keeps 'eternal' smoke up for any zone that has the
@ -34,27 +37,61 @@ function cfxSmokeZone.processSmokeZone(aZone)
aZone.smokeColor = theColor
aZone.smokeAlt = cfxZones.getNumberFromZoneProperty(aZone, "altitude", 1)
-- paused
aZone.paused = cfxZones.getBoolFromZoneProperty(aZone, "paused", false)
-- f? query flags
if cfxZones.hasProperty(aZone, "f?") then
aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "f?", "none")
end
if aZone.onFlag then
aZone.onFlagVal = trigger.misc.getUserFlag(aZone.onFlag) -- save last value
end
end
function cfxSmokeZone.addSmokeZone(aZone)
table.insert(cfxSmokeZone.smokeZones, aZone)
end
function cfxSmokeZone.addSmokeZoneWithColor(aZone, aColor, anAltitude)
function cfxSmokeZone.addSmokeZoneWithColor(aZone, aColor, anAltitude, paused, onFlag)
if not aColor then aColor = 0 end -- default green
if not anAltitude then anAltitude = 5 end
if not aZone then return end
if not paused then paused = false end
aZone.smokeColor = aColor
aZone.smokeAlt = anAltitude
aZone.paused = paused
if onFlag then
aZone.onFlag = onFlag
aZone.onFlagVal = trigger.misc.getUserFlag(onFlag)
end
cfxSmokeZone.addSmokeZone(aZone) -- add to update loop
cfxZones.markZoneWithSmoke(aZone, 0, 0, aZone.smokeColor, aZone.smokeAlt) -- smoke on!
if not paused then
cfxSmokeZone.startSmoke(aZone)
end
end
function cfxSmokeZone.removeSmokeZone(aZone)
if not aZone then return end
function cfxSmokeZone.startSmoke(aZone)
if type(aZone) == "string" then
aZone = cfxZones.getZoneByName(aZone)
end
if not aZone then return end
if not aZone.smokeColor then return end
aZone.paused = false
cfxZones.markZoneWithSmoke(aZone, 0, 0, aZone.smokeColor, aZone.smokeAlt)
end
function cfxSmokeZone.removeSmokeZone(aZone)
if type(aZone) == "string" then
aZone = cfxZones.getZoneByName(aZone)
end
if not aZone then return end
-- now create new table
local filtered = {}
@ -73,8 +110,25 @@ function cfxSmokeZone.update()
-- re-smoke all zones after delay
for idx, aZone in pairs(cfxSmokeZone.smokeZones) do
if aZone.smokeColor then
cfxZones.markZoneWithSmoke(aZone, 0, 0, aZone.smokeColor, aZone.smokeAlt)
if not aZone.paused and aZone.smokeColor then
cfxSmokeZone.startSmoke(aZone)
end
end
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
local currTriggerVal = trigger.misc.getUserFlag(aZone.onFlag)
if currTriggerVal ~= aZone.onFlagVal then
-- yupp, trigger start
cfxSmokeZone.startSmoke(aZone)
aZone.onFlagVal = currTriggerVal
end
end
end
end
@ -89,15 +143,18 @@ function cfxSmokeZone.start()
-- collect all spawn zones
local attrZones = cfxZones.getZonesWithAttributeNamed("smoke")
-- now create a spawner for all, add them to the spawner updater, and spawn for all zones that are not
-- paused
-- now create a smoker for all, add them to updater,
-- smoke all that aren't paused
for k, aZone in pairs(attrZones) do
cfxSmokeZone.processSmokeZone(aZone) -- process attribute and add to zone
cfxSmokeZone.addSmokeZone(aZone) -- remember it so we can smoke it
end
-- start update loop
cfxSmokeZone.update()
cfxSmokeZone.update() -- also starts all unpaused
-- start check loop in one second
timer.scheduleFunction(cfxSmokeZone.checkFlags, {}, timer.getTime() + 1)
-- say hi
trigger.action.outText("cfx Smoke Zones v" .. cfxSmokeZone.version .. " started.", 30)

View File

@ -1,5 +1,5 @@
cfxSpawnZones = {}
cfxSpawnZones.version = "1.5.1"
cfxSpawnZones.version = "1.5.2"
cfxSpawnZones.requiredLibs = {
"dcsCommon", -- common is of course needed for everything
-- pretty stupid to check for this since we
@ -51,6 +51,7 @@ cfxSpawnZones.verbose = false
-- - spawnWithSpawner made string compatible
-- 1.5.1 - relaxed baseName and default to dcsCommon.uuid()
-- - verbose
-- 1.5.2 - activate?, pause? flag
--
-- new version requires cfxGroundTroops, where they are
--
@ -139,6 +140,16 @@ function cfxSpawnZones.createSpawner(inZone)
theSpawner.lastTriggerValue = trigger.misc.getUserFlag(theSpawner.triggerFlag)
end
if cfxZones.hasProperty(inZone, "activate?") then
theSpawner.activateFlag = cfxZones.getStringFromZoneProperty(inZone, "activate?", "none")
theSpawner.lastActivateValue = trigger.misc.getUserFlag(theSpawner.activateFlag)
end
if cfxZones.hasProperty(inZone, "pause?") then
theSpawner.pauseFlag = cfxZones.getStringFromZoneProperty(inZone, "pause?", "none")
theSpawner.lastPauseValue = trigger.misc.getUserFlag(theSpawner.pauseFlag)
end
theSpawner.types = cfxZones.getZoneProperty(inZone, "types")
--theSpawner.owner = cfxZones.getCoalitionFromZoneProperty(inZone, "owner", 0)
-- synthesize types * typeMult
@ -407,7 +418,16 @@ function cfxSpawnZones.update()
-- is master zone still alinged with me?
needsSpawn = needsSpawn and cfxSpawnZones.verifySpawnOwnership(spawner)
-- check if perhaps our watchtrigger causes spawn
-- check if perhaps our watchtriggers causes spawn
if spawner.pauseFlag then
local currTriggerVal = trigger.misc.getUserFlag(spawner.pauseFlag)
if currTriggerVal ~= spawner.lastPauseValue then
spawner.paused = true
needsSpawn = false
spawner.lastPauseValue = currTriggerVal
end
end
if spawner.triggerFlag then
local currTriggerVal = trigger.misc.getUserFlag(spawner.triggerFlag)
if currTriggerVal ~= spawner.lastTriggerValue then
@ -416,6 +436,16 @@ function cfxSpawnZones.update()
end
end
if spawner.activateFlag then
local currTriggerVal = trigger.misc.getUserFlag(spawner.activateFlag)
if currTriggerVal ~= spawner.lastActivateValue then
spawner.paused = false
spawner.lastActivateValue = currTriggerVal
end
end
-- if we get here, and needsSpawn is still set, we go ahead and spawn
if needsSpawn then
--- trigger.action.outText("+++ spawning for zone " .. spawner.zone.name, 30)

View File

@ -6,7 +6,7 @@
--
cfxZones = {}
cfxZones.version = "2.5.1"
cfxZones.version = "2.5.2"
--[[-- VERSION HISTORY
- 2.2.4 - getCoalitionFromZoneProperty
- getStringFromZoneProperty
@ -43,6 +43,8 @@ cfxZones.version = "2.5.1"
- 2.4.12 - getStringFromZoneProperty
- 2.5.0 - harden getZoneProperty and all getPropertyXXXX
- 2.5.1 - markZoneWithSmoke supports alt attribute
- 2.5.2 - getPoint also writes through to zone itself for optimization
- new method getPositiveRangeFromZoneProperty(theZone, theProperty, default)
--]]--
cfxZones.verbose = true
@ -1100,6 +1102,45 @@ function cfxZones.getMinMaxFromZoneProperty(theZone, theProperty)
end
function cfxZones.getPositiveRangeFromZoneProperty(theZone, theProperty, default)
-- reads property as string, and interprets as range 'a-b'.
-- if not a range but single number, returns both for upper and lower
--trigger.action.outText("***Zne: enter with <" .. theZone.name .. ">: range for property <" .. theProperty .. ">!", 30)
if not default then default = 0 end
local lowerBound = default
local upperBound = default
local rangeString = cfxZones.getStringFromZoneProperty(theZone, theProperty, "")
if dcsCommon.containsString(rangeString, "-") then
local theRange = dcsCommon.splitString(rangeString, "-")
lowerBound = theRange[1]
lowerBound = tonumber(lowerBound)
upperBound = theRange[2]
upperBound = tonumber(upperBound)
if lowerBound and upperBound then
-- swap if wrong order
if lowerBound > upperBound then
local temp = upperBound
upperBound = lowerBound
lowerBound = temp
end
-- if rndFlags.verbose then
-- trigger.action.outText("+++Zne: detected range <" .. lowerBound .. ", " .. upperBound .. ">", 30)
-- end
else
-- bounds illegal
trigger.action.outText("+++Zne: illegal range <" .. rangeString .. ">, using " .. default .. "-" .. default, 30)
lowerBound = default
upperBound = default
end
else
upperBound = cfxZones.getNumberFromZoneProperty(theZone, theProperty, default) -- between pulses
lowerBound = upperBound
end
-- trigger.action.outText("+++Zne: returning <" .. lowerBound .. ", " .. upperBound .. ">", 30)
return lowerBound, upperBound
end
function cfxZones.hasProperty(theZone, theProperty)
return cfxZones.getZoneProperty(theZone, theProperty) ~= nil
end
@ -1223,7 +1264,7 @@ end
--
-- requires that readFromDCS has been done
--
function cfxZones.getPoint(aZone) -- always works, wven linked, point can be reused
function cfxZones.getPoint(aZone) -- always works, even linked, point can be reused
if aZone.linkedUnit then
local theUnit = aZone.linkedUnit
-- has a link. is link existing?
@ -1237,6 +1278,8 @@ function cfxZones.getPoint(aZone) -- always works, wven linked, point can be reu
thePos.x = aZone.point.x
thePos.y = 0 -- aZone.y
thePos.z = aZone.point.z
-- since we are at it, update the zone as well
aZone.point = thePos
return thePos
end

View File

@ -1,5 +1,5 @@
dcsCommon = {}
dcsCommon.version = "2.5.1"
dcsCommon.version = "2.5.2"
--[[-- VERSION HISTORY
2.2.6 - compassPositionOfARelativeToB
- clockPositionOfARelativeToB
@ -56,6 +56,8 @@ dcsCommon.version = "2.5.1"
2.5.0 - "Line" formation with one unit places unit at center
2.5.1 - vNorm(a)
2.5.1 - added SA-18 Igla manpad to unitIsInfantry()
2.5.2 - added copyArray method
- corrected heading in createStaticObjectData
--]]--
-- dcsCommon is a library of common lua functions
@ -825,7 +827,14 @@ dcsCommon.version = "2.5.1"
return copy
end
function dcsCommon.copyArray(inArray)
-- warning: this is a ref copy!
local theCopy = {}
for idx, element in pairs(inArray) do
table.insert(theCopy, element)
end
return theCopy
end
--
--
-- S P A W N I N G
@ -1355,7 +1364,7 @@ dcsCommon.version = "2.5.1"
-- now loop and create a unit for each table
local num = 1
for key, theType in pairs(theUnitTypes) do
-- trigger.action.outText("creating unit " .. name .. "-" .. num, 30)
-- trigger.action.outText("+++dcsC: creating unit " .. name .. "-" .. num .. ": " .. theType, 30)
local aUnit = dcsCommon.createGroundUnitData(name .. "-"..num, theType, false)
dcsCommon.addUnitToGroupData(aUnit, theNewGroup, 0, 0)
num = num + 1
@ -1478,7 +1487,7 @@ dcsCommon.version = "2.5.1"
if not cargo then cargo = false end
objType = dcsCommon.trim(objType)
staticObj.heading = 0
staticObj.heading = heading
-- staticObj.groupId = 0
-- staticObj.shape_name = shape -- e.g. H-Windsock_RW
staticObj.type = objType -- e.g. Windsock

268
modules/pulseFlags.lua Normal file
View File

@ -0,0 +1,268 @@
pulseFlags = {}
pulseFlags.version = "1.0.0"
pulseFlags.verbose = false
pulseFlags.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
}
--[[--
Pulse Flags: DML module to regularly change a flag
Copyright 2022 by Christian Franz and cf/x
Version History
- 1.0.0 Initial version
--]]--
pulseFlags.pulses = {}
function pulseFlags.addPulse(aZone)
table.insert(pulseFlags.pulses, aZone)
end
--
-- create a pulse
--
function pulseFlags.createPulseWithZone(theZone)
theZone.flag = cfxZones.getNumberFromZoneProperty(theZone, "flag!", -1) -- the flag to pulse
-- time can be number, or number-number range
theZone.minTime, theZone.time = cfxZones.getPositiveRangeFromZoneProperty(theZone, "time", 1)
trigger.action.outText("***PulF: zone <" .. theZone.name .. "> time is <".. theZone.minTime ..", " .. theZone.time .. "!", 30)
theZone.pulses = cfxZones.getNumberFromZoneProperty(theZone, "pulses", -1)
theZone.pulsesLeft = 0 -- will start new cycle
-- trigger flags
if cfxZones.hasProperty(theZone, "activate?") then
theZone.activateFlag = cfxZones.getStringFromZoneProperty(theZone, "activate?", "none")
theZone.lastActivateValue = trigger.misc.getUserFlag(theZone.activateFlag) -- save last value
end
if cfxZones.hasProperty(theZone, "pause?") then
theZone.pauseFlag = cfxZones.getStringFromZoneProperty(theZone, "pause?", "none")
theZone.lastPauseValue = trigger.misc.getUserFlag(theZone.pauseFlag) -- save last value
end
theZone.paused = cfxZones.getBoolFromZoneProperty(theZone, "paused", false)
theZone.method = cfxZones.getStringFromZoneProperty(theZone, "method", "flip")
-- done flag
if cfxZones.hasProperty(theZone, "done+1") then
theZone.doneFlag = cfxZones.getStringFromZoneProperty(theZone, "done+1", "none")
end
theZone.pulsing = false -- not running
end
--
-- update
--
function pulseFlags.pollFlag(theFlag, method)
if pulseFlags.verbose then
trigger.action.outText("+++PulF: 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("+++PulF: unknown method <" .. method .. "> - using 'on'", 30)
end
-- default: on.
trigger.action.setUserFlag(theFlag, 1)
end
local newVal = trigger.misc.getUserFlag(theFlag)
if pulseFlags.verbose then
trigger.action.outText("+++PulF: flag <" .. theFlag .. "> changed from " .. currVal .. " to " .. newVal, 30)
end
end
function pulseFlags.doPulse(args)
local theZone = args[1]
-- check if we have been paused. if so, simply
-- exit with no new schedule
if theZone.paused then
theZone.pulsing = false
return
end
-- do a poll on flags
pulseFlags.pollFlag(theZone.flag, theZone.method)
-- decrease count
if theZone.pulses > 0 then
-- only do this if ending
theZone.pulsesLeft = theZone.pulsesLeft - 1
-- see if we are done
if theZone.pulsesLeft < 1 then
-- increment done flag if set
if theZone.doneFlag then
local currVal = trigger.misc.getUserFlag(theZone.doneFlag)
trigger.action.setUserFlag(theZone.doneFlag, currVal + 1)
end
if pulseFlags.verbose then
trigger.action.outText("***PulF: pulse <" .. theZone.name .. "> ended!", 30)
end
theZone.pulsing = false
theZone.paused = true
return
end
end
-- if we get here, we'll do another one soon
-- refresh pulse
local delay = theZone.time
if theZone.minTime > 0 and theZone.minTime < delay then
-- we want a randomized from time from minTime .. delay
local varPart = delay - theZone.minTime + 1
varPart = dcsCommon.smallRandom(varPart) - 1
delay = theZone.minTime + varPart
end
--trigger.action.outText("***PulF: pulse <" .. theZone.name .. "> scheduled in ".. delay .."!", 30)
-- schedule in delay time
timer.scheduleFunction(pulseFlags.doPulse, args, timer.getTime() + delay)
if pulseFlags.verbose then
trigger.action.outText("+++PulF: pulse <" .. theZone.name .. "> rescheduled in " .. delay, 30)
end
end
-- start new pulse, will reset
function pulseFlags.startNewPulse(theZone)
theZone.pulsesLeft = theZone.pulses
local args = {theZone}
theZone.pulsing = true
if pulseFlags.verbose then
trigger.action.outText("+++PulF: starting pulse <" .. theZone.name .. ">", 30)
end
pulseFlags.doPulse(args)
end
function pulseFlags.update()
-- call me in a second to poll triggers
timer.scheduleFunction(pulseFlags.update, {}, timer.getTime() + 1)
for idx, aZone in pairs(pulseFlags.pulses) do
-- see if pulse is running
if aZone.pulsing then
-- this zone has a pulse and has scheduled
-- a new pulse, nothing to do
else
-- this zone has not scheduled a new pulse
-- let's see why
if aZone.paused then
-- ok, zone is paused. all clear
else
-- zone isn't paused. we need to start the zone
pulseFlags.startNewPulse(aZone)
end
end
-- see if we got a pause or activate command
if aZone.activateFlag then
local currTriggerVal = trigger.misc.getUserFlag(aZone.activateFlag)
if currTriggerVal ~= aZone.lastActivateValue
then
trigger.action.outText("+++PulF: activating <" .. aZone.name .. ">", 30)
aZone.lastActivateValue = currTriggerVal
theZone.paused = false -- will start anew
end
end
if aZone.pauseFlag then
local currTriggerVal = trigger.misc.getUserFlag(aZone.pauseFlag)
if currTriggerVal ~= aZone.lastPauseValue
then
trigger.action.outText("+++PulF: pausing <" .. aZone.name .. ">", 30)
aZone.lastPauseValue = currTriggerVal
theZone.paused = true -- will start anew
end
end
end
end
--
-- start module and read config
--
function pulseFlags.readConfigZone()
-- note: must match exactly!!!!
local theZone = cfxZones.getZoneByName("pulseFlagsConfig")
if not theZone then
if pulseFlags.verbose then
trigger.action.outText("+++PulF: NO config zone!", 30)
end
return
end
pulseFlags.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
if pulseFlags.verbose then
trigger.action.outText("+++PulF: read config", 30)
end
end
function pulseFlags.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("PulseFlags requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx Pulse Flags",
pulseFlags.requiredLibs) then
return false
end
-- read config
pulseFlags.readConfigZone()
-- process RND Zones
local attrZones = cfxZones.getZonesWithAttributeNamed("pulse")
-- now create a pulse gen for each one and add them
-- to our watchlist
for k, aZone in pairs(attrZones) do
pulseFlags.createPulseWithZone(aZone) -- process attribute and add to zone
pulseFlags.addPulse(aZone) -- remember it so we can pulse it
end
-- start update in 1 second
--pulseFlags.update()
timer.scheduleFunction(pulseFlags.update, {}, timer.getTime() + 1)
trigger.action.outText("cfx Pulse Flags v" .. pulseFlags.version .. " started.", 30)
return true
end
-- let's go!
if not pulseFlags.start() then
trigger.action.outText("cf/x Pulse Flags aborted: missing libraries", 30)
pulseFlags = nil
end

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.