Version 1.5.0

- groundExplosion
- Liveries for CivAir
- too many others to list
This commit is contained in:
Christian Franz 2023-11-16 09:04:13 +01:00
parent c3ba1e7c05
commit a3cffa58d1
23 changed files with 751 additions and 454 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
rndFlags = {} rndFlags = {}
rndFlags.version = "1.4.1" rndFlags.version = "2.0.0"
rndFlags.verbose = false rndFlags.verbose = false
rndFlags.requiredLibs = { rndFlags.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -33,6 +33,7 @@ rndFlags.requiredLibs = {
- minor clean-up - minor clean-up
1.4.0 - persistence 1.4.0 - persistence
1.4.1 - a little less verbosity 1.4.1 - a little less verbosity
2.0.0 - dmlZones, OOP
--]] --]]
@ -59,14 +60,14 @@ end
-- --
function rndFlags.createRNDWithZone(theZone) function rndFlags.createRNDWithZone(theZone)
local flags = "" local flags = ""
if cfxZones.hasProperty(theZone, "RND!") then if theZone:hasProperty("RND!") then
flags = cfxZones.getStringFromZoneProperty(theZone, "RND!", "") flags = theZone:getStringFromZoneProperty("RND!", "")
elseif cfxZones.hasProperty(theZone, "flags!") then elseif theZone:hasProperty("flags!") then
trigger.action.outText("+++RND: warning - zone <" .. theZone.name .. ">: deprecated 'flags!' usage, use 'RND!' instead.", 30) trigger.action.outText("+++RND: warning - zone <" .. theZone.name .. ">: deprecated 'flags!' usage, use 'RND!' instead.", 30)
flags = cfxZones.getStringFromZoneProperty(theZone, "flags!", "") flags = theZone:getStringFromZoneProperty("flags!", "")
elseif cfxZones.hasProperty(theZone, "flags") then elseif theZone:hasProperty("flags") then
trigger.action.outText("+++RND: warning - zone <" .. theZone.name .. ">: deprecated 'flags' (no bang) usage, use 'RND!' instead.", 30) trigger.action.outText("+++RND: warning - zone <" .. theZone.name .. ">: deprecated 'flags' (no bang) usage, use 'RND!' instead.", 30)
flags = cfxZones.getStringFromZoneProperty(theZone, "flags", "") flags = theZone:getStringFromZoneProperty("flags", "")
else else
trigger.action.outText("+++RND: warning - zone <" .. theZone.name .. ">: no flags defined!", 30) trigger.action.outText("+++RND: warning - zone <" .. theZone.name .. ">: no flags defined!", 30)
end end
@ -78,73 +79,65 @@ function rndFlags.createRNDWithZone(theZone)
trigger.action.outText("+++RND: output set for <" .. theZone.name .. "> is <" .. flags .. ">",30) trigger.action.outText("+++RND: output set for <" .. theZone.name .. "> is <" .. flags .. ">",30)
end end
theZone.pollSizeMin, theZone.pollSize = cfxZones.getPositiveRangeFromZoneProperty(theZone, "pollSize", 1) theZone.pollSizeMin, theZone.pollSize = theZone:getPositiveRangeFromZoneProperty("pollSize", 1)
if rndFlags.verbose or theZone.verbose then if rndFlags.verbose or theZone.verbose then
trigger.action.outText("+++RND: pollSize is <" .. theZone.pollSizeMin .. ", " .. theZone.pollSize .. ">", 30) trigger.action.outText("+++RND: pollSize is <" .. theZone.pollSizeMin .. ", " .. theZone.pollSize .. ">", 30)
end end
theZone.remove = theZone:getBoolFromZoneProperty("remove", false)
theZone.rndTriggerMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
theZone.remove = cfxZones.getBoolFromZoneProperty(theZone, "remove", false) if theZone:hasProperty("rndTriggerMethod") then
theZone.rndTriggerMethod = theZone:getStringFromZoneProperty("rndTriggerMethod", "change")
-- watchflag:
-- triggerMethod
theZone.rndTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
if cfxZones.hasProperty(theZone, "rndTriggerMethod") then
theZone.rndTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "rndTriggerMethod", "change")
end end
-- trigger flag -- trigger flag
if cfxZones.hasProperty(theZone, "f?") then if theZone:hasProperty("f?") then
theZone.triggerFlag = cfxZones.getStringFromZoneProperty(theZone, "f?", "none") theZone.triggerFlag = theZone:getStringFromZoneProperty("f?", "none")
end end
if cfxZones.hasProperty(theZone, "in?") then if theZone:hasProperty("in?") then
theZone.triggerFlag = cfxZones.getStringFromZoneProperty(theZone, "in?", "none") theZone.triggerFlag = theZone:getStringFromZoneProperty("in?", "none")
end end
if cfxZones.hasProperty(theZone, "rndPoll?") then if theZone:hasProperty("rndPoll?") then
theZone.triggerFlag = cfxZones.getStringFromZoneProperty(theZone, "rndPoll?", "none") theZone.triggerFlag = theZone:getStringFromZoneProperty("rndPoll?", "none")
end end
if theZone.triggerFlag then if theZone.triggerFlag then
theZone.lastTriggerValue = cfxZones.getFlagValue(theZone.triggerFlag, theZone) theZone.lastTriggerValue = theZone:getFlagValue(theZone.triggerFlag)
if rndFlags.verbose or theZone.verbose then if rndFlags.verbose or theZone.verbose then
trigger.action.outText("+++RND: randomizer in <" .. theZone:getName() .. "> triggers on flag <" .. theZone.triggerFlag .. ">", 30) trigger.action.outText("+++RND: randomizer in <" .. theZone:getName() .. "> triggers on flag <" .. theZone.triggerFlag .. ">", 30)
end end
--trigger.misc.getUserFlag(theZone.triggerFlag) -- save last value
end end
theZone.onStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", false) theZone.onStart = theZone:getBoolFromZoneProperty("onStart", false)
if not theZone.onStart and not theZone.triggerFlag then if not theZone.onStart and not theZone.triggerFlag then
-- theZone.onStart = true trigger.action.outText("+++RND - WARNING: no triggers and no onStart, RND in <" .. theZone.name .. "> can't be triggered.", 30)
if true or theZone.verbose or rndFlags.verbose then
trigger.action.outText("+++RND - WARNING: no triggers and no onStart, RND in <" .. theZone.name .. "> can't be triggered.", 30)
end
end end
theZone.rndMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc") theZone.rndMethod = theZone:getStringFromZoneProperty("method", "inc")
if cfxZones.hasProperty(theZone, "rndMethod") then if theZone:hasProperty("rndMethod") then
theZone.rndMethod = cfxZones.getStringFromZoneProperty(theZone, "rndMethod", "inc") theZone.rndMethod = theZone:getStringFromZoneProperty("rndMethod", "inc")
end end
theZone.reshuffle = cfxZones.getBoolFromZoneProperty(theZone, "reshuffle", false) theZone.reshuffle = theZone:getBoolFromZoneProperty("reshuffle", false)
if theZone.reshuffle then if theZone.reshuffle then
-- create a backup copy we can reshuffle from -- create a backup copy we can reshuffle from
theZone.flagStore = dcsCommon.copyArray(theFlags) theZone.flagStore = dcsCommon.copyArray(theFlags)
end end
-- done flag OLD, to be deprecated -- done flag OLD, to be deprecated
if cfxZones.hasProperty(theZone, "done+1") then if theZone:hasProperty("done+1") then
theZone.doneFlag = cfxZones.getStringFromZoneProperty(theZone, "done+1", "<none>") theZone.doneFlag = theZone:getStringFromZoneProperty("done+1", "<none>")
trigger.action.outText("Warning: RND zone <" .. theZone.name .. "> uses depreceated 'done+1'.", 30)
-- now NEW replacements -- now NEW replacements
elseif cfxZones.hasProperty(theZone, "done!") then elseif theZone:hasProperty("done!") then
theZone.doneFlag = cfxZones.getStringFromZoneProperty(theZone, "done!", "<none>") theZone.doneFlag = theZone:getStringFromZoneProperty("done!", "<none>")
elseif cfxZones.hasProperty(theZone, "rndDone!") then elseif theZone:hasProperty("rndDone!") then
theZone.doneFlag = cfxZones.getStringFromZoneProperty(theZone, "rndDone!", "<none>") theZone.doneFlag = theZone.getStringFromZoneProperty("rndDone!", "<none>")
end end
end end
@ -210,7 +203,7 @@ function rndFlags.fire(theZone)
trigger.action.outText("+++RND: polling " .. theFlag .. " with " .. theZone.rndMethod, 30) trigger.action.outText("+++RND: polling " .. theFlag .. " with " .. theZone.rndMethod, 30)
end end
cfxZones.pollFlag(theFlag, theZone.rndMethod, theZone) theZone:pollFlag(theFlag, theZone.rndMethod)
end end
-- remove if requested -- remove if requested
@ -317,9 +310,7 @@ function rndFlags.readConfigZone()
end end
return return
end end
rndFlags.verbose = theZone.verbose
rndFlags.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
if rndFlags.verbose then if rndFlags.verbose then
trigger.action.outText("***RND: read config", 30) trigger.action.outText("***RND: read config", 30)
end end
@ -349,17 +340,15 @@ function rndFlags.start()
-- now create an rnd gen for each one and add them -- now create an rnd gen for each one and add them
-- to our watchlist -- to our watchlist
for k, aZone in pairs(attrZones) do for k, aZone in pairs(attrZones) do
rndFlags.createRNDWithZone(aZone) -- process attribute and add to zone rndFlags.createRNDWithZone(aZone)
rndFlags.addRNDZone(aZone) -- remember it so we can smoke it rndFlags.addRNDZone(aZone)
end end
-- obsolete here -- obsolete here
attrZones = cfxZones.getZonesWithAttributeNamed("RND") 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 for k, aZone in pairs(attrZones) do
rndFlags.createRNDWithZone(aZone) -- process attribute and add to zone rndFlags.createRNDWithZone(aZone)
rndFlags.addRNDZone(aZone) -- remember it so we can smoke it rndFlags.addRNDZone(aZone)
end end
-- persistence -- persistence

View File

@ -1,9 +1,15 @@
tdz = {} tdz = {}
tdz.version = "0.9.0dev" tdz.version = "1.0.0"
tdz.requiredLibs = { tdz.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
"cfxZones", -- Zones, of course "cfxZones", -- Zones, of course
} }
--[[--
VERSION HISTORY
1.0.0 - Initial version
--]]--
tdz.allTdz = {} tdz.allTdz = {}
tdz.watchlist = {} tdz.watchlist = {}
tdz.watching = false tdz.watching = false
@ -52,31 +58,7 @@ function tdz.translatePoly(thePoly, v) -- straight rot, translate to 0 first
if aPoint.z then aPoint.z = aPoint.z + v.z end if aPoint.z then aPoint.z = aPoint.z + v.z end
end end
end end
--[[--
function tdz.frameRwy(center, length, width, rads, a, b) -- bearing in rads
if not a then a = 0 end
if not b then b = 1 end
-- create a 0-rotated centered poly
local poly = {}
local half = length / 2
local leftEdge = -half
poly[4] = { x = leftEdge + a * length, z = width / 2, y = 0}
poly[3] = { x = leftEdge + b * length, z = width / 2, y = 0}
poly[2] = { x = leftEdge + b * length, z = -width / 2, y = 0}
poly[1] = { x = leftEdge + a * length, z = -width / 2, y = 0}
-- move it to center in map
tdz.translatePoly(poly, center)
-- rotate it
tdz.rotateXZPolyAroundCenterInRads(poly, center, rads)
-- frame it
local mId = dcsCommon.numberUUID()
trigger.action.quadToAll(-1, mId, poly[1], poly[2], poly[3], poly[4], {1, 0, 0, 1}, {1, 0, 0, .5}, 3) -- dotted line, red
end
--]]--
function tdz.calcTDZone(name, center, length, width, rads, a, b) function tdz.calcTDZone(name, center, length, width, rads, a, b)
if not a then a = 0 end if not a then a = 0 end
if not b then b = 1 end if not b then b = 1 end
@ -94,7 +76,7 @@ function tdz.calcTDZone(name, center, length, width, rads, a, b)
tdz.rotateXZPolyAroundCenterInRads(poly, center, rads) tdz.rotateXZPolyAroundCenterInRads(poly, center, rads)
-- make it a dml zone -- make it a dml zone
local theNewZone = cfxZones.createSimplePolyZone(name, center, poly) local theNewZone = cfxZones.createSimplePolyZone(name, center, poly)
return theNewZone--, left, right return theNewZone
end end
-- --
@ -181,7 +163,6 @@ function tdz.playerLanded(theUnit, playerName)
-- make sure unit names match? -- make sure unit names match?
local entry = tdz.watchlist[playerName] local entry = tdz.watchlist[playerName]
entry.hops = entry.hops + 1 -- uh oh. entry.hops = entry.hops + 1 -- uh oh.
-- trigger.action.outText("Bump!")
end end
-- we may want to filter helicopters -- we may want to filter helicopters
@ -226,7 +207,6 @@ function tdz.playerLanded(theUnit, playerName)
if dOpHdg < dHdg then if dOpHdg < dHdg then
opposite = true opposite = true
dHdg = dOpHdg dHdg = dOpHdg
trigger.action.outText("opposite rwy detected", 30)
end end
if dHdg > math.pi * 1.5 then -- > 270+ if dHdg > math.pi * 1.5 then -- > 270+
dHdg = dHdg - math.pi * 1.5 dHdg = dHdg - math.pi * 1.5

View File

@ -1,18 +1,34 @@
bombRange = {} bombRange = {}
bombRange.version = "1.0.0" bombRange.version = "1.1.0"
bombRange.dh = 1 -- meters above ground level burst bombRange.dh = 1 -- meters above ground level burst
bombRange.requiredLibs = { bombRange.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
"cfxZones", -- Zones, of course "cfxZones", -- Zones, of course
} }
--[[--
VERSION HISTORY
1.0.0 - Initial version
1.1.0 - collector logic for collating hits
*after* impact on high-resolution scans (30fps)
set resolution to 30 ups by default
order of events: check kills against dropping projectiles
collecd dead, and compare against missing erdnance while they are fresh
GC
interpolate hits on dead when looking at kills and projectile does
not exist
also sampling kill events
--]]--
bombRange.bombs = {} -- live tracking bombRange.bombs = {} -- live tracking
bombRange.collector = {} -- post-impact collections for 0.5 secs
bombRange.ranges = {} -- all bomb ranges bombRange.ranges = {} -- all bomb ranges
bombRange.playerData = {} -- player accumulated data bombRange.playerData = {} -- player accumulated data
bombRange.unitComms = {} -- command interface per unit bombRange.unitComms = {} -- command interface per unit
bombRange.tracking = false -- if true, we are tracking projectiles bombRange.tracking = false -- if true, we are tracking projectiles
bombRange.myStatics = {} -- indexed by id bombRange.myStatics = {} -- indexed by id
bombRange.killDist = 20 -- meters, if caught within that of kill event, this weapon was the culprit
bombRange.freshKills = {} -- at max 1 second old?
function bombRange.addBomb(theBomb) function bombRange.addBomb(theBomb)
table.insert(bombRange.bombs, theBomb) table.insert(bombRange.bombs, theBomb)
@ -44,7 +60,7 @@ function bombRange.createRange(theZone) -- has bombRange attribte to mark it
end end
theZone.details = theZone:getBoolFromZoneProperty("details", false) theZone.details = theZone:getBoolFromZoneProperty("details", false)
theZone.reporter = theZone:getBoolFromZoneProperty("reporter", true) theZone.reporter = theZone:getBoolFromZoneProperty("reporter", true)
theZone.reportName = theZone:getBoolFromZoneProperty("reportName", true) theZone.reportName = theZone:getBoolFromZoneProperty("reportName", false)
theZone.smokeHits = theZone:getBoolFromZoneProperty("smokeHits", false) theZone.smokeHits = theZone:getBoolFromZoneProperty("smokeHits", false)
theZone.smokeColor = theZone:getSmokeColorStringFromZoneProperty("smokeColor", "blue") theZone.smokeColor = theZone:getSmokeColorStringFromZoneProperty("smokeColor", "blue")
theZone.flagHits = theZone:getBoolFromZoneProperty("flagHits", false) theZone.flagHits = theZone:getBoolFromZoneProperty("flagHits", false)
@ -237,26 +253,51 @@ end
-- Event Proccing -- Event Proccing
-- --
function bombRange.suspectedHit(weapon, target) function bombRange.suspectedHit(weapon, target)
if not bombRange.tracking then local wType = weapon:getTypeName()
if not target then return end
if target:getCategory() == 5 then -- scenery
return return
end end
if not target then return end
local theType = target:getTypeName()
local theDesc = target:getDesc()
local theType = theDesc.typeName -- getTypeName gets display name
-- filter statics that we want to ignore
for idx, aType in pairs(bombRange.filterTypes) do for idx, aType in pairs(bombRange.filterTypes) do
if theType == aType then return end if theType == aType then
return
end
end end
-- try and match target to my known statics, exit if match -- try and match target to my known statics, exit if match
if not target.getID then return end -- units have no getID! if target.getID then -- units have no getID, so skip for those
local theID = tonumber(target:getID()) local theID = tonumber(target:getID())
if bombRange.myStatics[theID] then if bombRange.myStatics[theID] then
return
end
end
-- look through the collector (recent impacted) first
local hasfound = false
local theID
for idx, b in pairs(bombRange.collector) do
if b.weapon == weapon then
b.pos = target:getPoint()
bombRange.impacted(b, target) -- use this for impact
theID = b.ID
hasfound = true
-- trigger.action.outText("susHit: filtering COLLECTED b <" .. b.name .. ">", 30)
end
end
if hasfound then
bombRange.collector[theID] = nil -- remove from collector
return return
end end
-- look through the tracked weapons for a match -- look through the tracked weapons for a match next
if not bombRange.tracking then
return
end
local filtered = {} local filtered = {}
local hasfound = false
for idx, b in pairs (bombRange.bombs) do for idx, b in pairs (bombRange.bombs) do
if b.weapon == weapon then if b.weapon == weapon then
hasfound = true hasfound = true
@ -264,6 +305,8 @@ function bombRange.suspectedHit(weapon, target)
b.pos = weapon:getPoint() b.pos = weapon:getPoint()
b.v = weapon:getVelocity() b.v = weapon:getVelocity()
bombRange.impacted(b, target) bombRange.impacted(b, target)
-- trigger.action.outText("susHit: filtering live b <" .. b.name .. ">", 30)
else else
table.insert(filtered, b) table.insert(filtered, b)
end end
@ -273,16 +316,106 @@ function bombRange.suspectedHit(weapon, target)
end end
end end
function bombRange.suspectedKill(target)
-- some unit got killed, let's see if our munitions in the collector
-- phase are close by, i.e. they have disappeared
if not target then return end
local theDesc = target:getDesc()
local theType = theDesc.typeName -- getTypeName gets display name
-- filter statics that we want to ignore
for idx, aType in pairs(bombRange.filterTypes) do
if theType == aType then return end
end
local hasfound = nil
local theID
local pk = target:getPoint()
local now = timer.getTime()
-- first, search all currently running projectiles, and check for proximity
local filtered = {}
for idx, b in pairs(bombRange.bombs) do
local wp
if Weapon.isExist(b.weapon) then
wp = b.weapon:getPoint()
else
local td = now - b.t -- time delta
-- calculate current loc from last velocity and
-- time
local moveV = dcsCommon.vMultScalar(b.v, td)
wp = dcsCommon.vAdd(b.pos, moveV)
end
local delta = dcsCommon.dist(wp, pk)
-- now use the line wp-wp+v and calculate distance
-- of pk to that line.
local wp2 = dcsCommon.vAdd(b.pos, b.v)
local delta2 = dcsCommon.distanceOfPointPToLineXZ(pk, b.pos, wp2)
if delta < bombRange.killDist or delta2 < bombRange.killDist then
b.pos = pk
bombRange.impacted(b, target)
hasfound = true
-- trigger.action.outText("filtering b: <" .. b.name .. ">", 30)
else
table.insert(filtered, b)
end
end
bombRange.bombs = filtered
if hasfound then
-- trigger.action.outText("protocol: removed LIVING weapon from roster after impacted() invocation for non-nil target in suspectedKill", 30)
return
end
-- now check the projectiles that have already impacted
for idx, b in pairs(bombRange.collector) do
local dist = dcsCommon.dist(b.pos, pk)
local wp2 = dcsCommon.vAdd(b.pos, b.v)
local delta2 = dcsCommon.distanceOfPointPToLineXZ(pk, b.pos, wp2)
if dist < bombRange.killDist or delta2 < bombRange.killDist then
-- yeah, *you* killed them!
b.pos = pk
bombRange.impacted(b, target) -- use this for impact
theID = b.ID
hasfound = true
end
end
if hasfound then -- remove from collector, hit attributed
bombRange.collector[theID] = nil -- remove from collector
-- trigger.action.outText("protocol: removed COLL weapon from roster after impacted() invocation for non-nil target in suspectedKill", 30)
return
end
end
function bombRange:onEvent(event) function bombRange:onEvent(event)
if not event.initiator then return end if not event.initiator then return end
local theUnit = event.initiator local theUnit = event.initiator
if event.id == 2 then -- hit if event.id == 2 then -- hit: weapon still exists
if not event.weapon then return end if not event.weapon then return end
bombRange.suspectedHit(event.weapon, event.target) bombRange.suspectedHit(event.weapon, event.target)
return return
end end
if event.id == 28 then -- kill: similar to hit, but due to new mechanics not reliable
if not event.weapon then return end
bombRange.suspectedHit(event.weapon, event.target)
return
end
if event.id == 8 then -- dead
-- these events can come *before* weapon disappears
local killDat = {}
killDat.victim = event.initiator
killDat.p = event.initiator:getPoint()
killDat.when = timer.getTime()
killDat.name = dcsCommon.uuid("vic")
bombRange.freshKills[killDat.name] = killDat
bombRange.suspectedKill(event.initiator)
end
local uName = nil local uName = nil
local pName = nil local pName = nil
if theUnit.getPlayerName and theUnit:getPlayerName() ~= nil then if theUnit.getPlayerName and theUnit:getPlayerName() ~= nil then
@ -314,6 +447,7 @@ function bombRange:onEvent(event)
b.weapon = w b.weapon = w
b.released = timer.getTime() b.released = timer.getTime()
b.relPos = b.pos b.relPos = b.pos
b.ID = dcsCommon.uuid("bomb")
table.insert(bombRange.bombs, b) table.insert(bombRange.bombs, b)
if not bombRange.tracking then if not bombRange.tracking then
timer.scheduleFunction(bombRange.updateBombs, {}, timer.getTime() + 1/bombRange.ups) timer.scheduleFunction(bombRange.updateBombs, {}, timer.getTime() + 1/bombRange.ups)
@ -336,14 +470,25 @@ end
-- --
-- Update -- Update
-- --
function bombRange.impacted(weapon, target) function bombRange.impacted(weapon, target, finalPass)
local targetName = nil local targetName = nil
local ipos = weapon.pos -- default to weapon location
if target then if target then
ipos = target:getPoint()
targetName = target:getDesc() targetName = target:getDesc()
if targetName then targetName = targetName.displayName end if targetName then targetName = targetName.displayName end
if not targetName then targetName = target:getTypeName() end if not targetName then targetName = target:getTypeName() end
end
-- local s = "Entering impacted() with weapon = <" .. weapon.name .. ">"
-- if target then
-- s = s .. " AND target = <" .. targetName .. ">"
-- end
-- when we enter, weapon has ipacted target - if target is non-nil
-- what we need to determine is if that target is inside a zone
local ipos = weapon.pos -- default to weapon location
if target then
ipos = target:getPoint() -- we make the target loc the impact point
else else
-- not an object hit, interpolate the impact point on ground: -- not an object hit, interpolate the impact point on ground:
-- calculate impact point. we use the linear equation -- calculate impact point. we use the linear equation
@ -375,6 +520,7 @@ function bombRange.impacted(weapon, target)
trigger.action.outText("+++bRng: nil <theRange> on eval. skipping.", 30) trigger.action.outText("+++bRng: nil <theRange> on eval. skipping.", 30)
return return
end end
if minDist > theRange.clipDist then if minDist > theRange.clipDist then
-- no taget zone inside clip dist. disregard this one, too far off -- no taget zone inside clip dist. disregard this one, too far off
if bombRange.reportLongMisses then if bombRange.reportLongMisses then
@ -383,11 +529,11 @@ function bombRange.impacted(weapon, target)
return return
end end
if theRange.smokeHits then if (not target) and theRange.smokeHits then
trigger.action.smoke(ipos, theRange.smokeColor) trigger.action.smoke(ipos, theRange.smokeColor)
end end
if (not target) and theRange.flagHits then -- only ground imparts are flagged if (not target) and theRange.flagHits then -- only ground impacts are flagged
local cty = dcsCommon.getACountryForCoalition(0) -- some neutral county local cty = dcsCommon.getACountryForCoalition(0) -- some neutral county
local p = {x=ipos.x, y=ipos.z} local p = {x=ipos.x, y=ipos.z}
local theStaticData = dcsCommon.createStaticObjectData(dcsCommon.uuid(weapon.type .. " impact"), theRange.flagType) local theStaticData = dcsCommon.createStaticObjectData(dcsCommon.uuid(weapon.type .. " impact"), theRange.flagType)
@ -395,8 +541,37 @@ function bombRange.impacted(weapon, target)
local theObject = coalition.addStaticObject(cty, theStaticData) local theObject = coalition.addStaticObject(cty, theStaticData)
end end
local impactInside = theRange:pointInZone(ipos)
--[[--
if target and (not impactInside) then
trigger.action.outText("Hit on target <" .. targetName .. "> outside of zone <" .. theRange.name .. ">. should exit unless final impact", 30)
-- find closest range to object that was hit
local closest = nil
local shortest = math.huge
local tp = target:getPoint()
for idx, aRange in pairs(bombRange.ranges) do
local zp = aRange:getPoint()
local zDist = dcsCommon.distFlat(zp, tp)
if zDist < shortest then
shortest = zDist
closest = aRange
end
end
trigger.action.outText("re-check: closest range to target now is <" .. closest.name ..">", 30)
if closest:pointInZone(tp) then
trigger.action.outText("target <" .. targetName .. "> is INSIDE this range, d = <" .. math.floor(shortest) .. ">", 30)
else
trigger.action.outText("targed indeed outside, d = <" .. math.floor(shortest) .. ">", 30)
end
if finalPass then trigger.action.outText("IS final pass.", 30) end
end
--]]--
if theRange.reporter and theRange.details then if theRange.reporter and theRange.details then
local t = math.floor((timer.getTime() - weapon.released) * 10) / 10 local ipc = weapon.impacted
if not ipc then ipc = timer.getTime() end
local t = math.floor((ipc - weapon.released) * 10) / 10
local v = math.floor(dcsCommon.vMag(weapon.v)) local v = math.floor(dcsCommon.vMag(weapon.v))
local tDist = dcsCommon.dist(ipos, weapon.relPos)/1000 local tDist = dcsCommon.dist(ipos, weapon.relPos)/1000
tDist = math.floor(tDist*100) /100 tDist = math.floor(tDist*100) /100
@ -404,7 +579,7 @@ function bombRange.impacted(weapon, target)
end end
local msg = "" local msg = ""
if theRange:pointInZone(ipos) then if impactInside then
local percentage = 0 local percentage = 0
if theRange.isPoly then if theRange.isPoly then
percentage = 100 percentage = 100
@ -430,29 +605,45 @@ function bombRange.impacted(weapon, target)
bombRange.addImpactForWeapon(weapon, true, percentage) bombRange.addImpactForWeapon(weapon, true, percentage)
else else
msg = "Outside target area" msg = "Outside target area"
-- if target then msg = msg .. " (EVEN THOUGH TGT = " .. target:getName() .. ")" end
if theRange.reportName then msg = msg .. " " .. theRange.name end if theRange.reportName then msg = msg .. " " .. theRange.name end
if theRange.details then msg = msg .. "(off-center by " .. math.floor(minDist *10)/10 .. " m)" end if theRange.details then msg = msg .. " (off-center by " .. math.floor(minDist *10)/10 .. " m)" end
msg = msg .. ", no hit." msg = msg .. ", no hit."
bombRange.addImpactForWeapon(weapon, false, 0) bombRange.addImpactForWeapon(weapon, false, 0)
end end
if theRange.reporter then if theRange.reporter then
trigger.action.outTextForGroup(weapon.gID,msg , 30) trigger.action.outTextForGroup(weapon.gID,msg , 30)
end end
end
function bombRange.uncollect(theID)
-- if this is still here, no hit was registered against the weapon
-- and we simply use the impact
local b = bombRange.collector[theID]
if b then
bombRange.collector[theID] = nil
bombRange.impacted(b, nil, true) -- final pass
-- trigger.action.outText("(final impact)", 30)
end
end end
function bombRange.updateBombs() function bombRange.updateBombs()
local now = timer.getTime()
local filtered = {} local filtered = {}
for idx, theWeapon in pairs(bombRange.bombs) do for idx, theWeapon in pairs(bombRange.bombs) do
if Weapon.isExist(theWeapon.weapon) then if Weapon.isExist(theWeapon.weapon) then
-- update pos and vel -- update pos and vel
theWeapon.pos = theWeapon.weapon:getPoint() theWeapon.pos = theWeapon.weapon:getPoint()
theWeapon.v = theWeapon.weapon:getVelocity() theWeapon.v = theWeapon.weapon:getVelocity()
theWeapon.t = now
table.insert(filtered, theWeapon) table.insert(filtered, theWeapon)
else else
-- interpolate the impact position from last position -- put on collector to time out in 1 seconds to allow
bombRange.impacted(theWeapon) -- asynch hits to still register for this weapon in MP
-- bombRange.impacted(theWeapon)
theWeapon.impacted = timer.getTime()
bombRange.collector[theWeapon.ID] = theWeapon --
timer.scheduleFunction(bombRange.uncollect, theWeapon.ID, timer.getTime() + 1)
end end
end end
@ -468,6 +659,19 @@ function bombRange.updateBombs()
end end
end end
function bombRange.GC()
local cutOff = timer.getTime()
local filtered = {}
for name, killDat in pairs(bombRange.freshKills) do
if killDat.when + 2 < cutOff then
-- keep in set for two seconds after kill.when
filtered[name] = killDat
end
end
bombRange.freshKills = filtered
timer.scheduleFunction(bombRange.GC, {}, timer.getTime() + 10)
end
-- --
-- load & save data -- load & save data
-- --
@ -508,7 +712,7 @@ function bombRange.readConfigZone()
bombRange.filterTypes = dcsCommon.trimArray(theSet) bombRange.filterTypes = dcsCommon.trimArray(theSet)
bombRange.reportLongMisses = theZone:getBoolFromZoneProperty("reportLongMisses", false) bombRange.reportLongMisses = theZone:getBoolFromZoneProperty("reportLongMisses", false)
bombRange.mustCheckIn = theZone:getBoolFromZoneProperty("mustCheckIn", false) bombRange.mustCheckIn = theZone:getBoolFromZoneProperty("mustCheckIn", false)
bombRange.ups = theZone:getNumberFromZoneProperty("ups", 20) bombRange.ups = theZone:getNumberFromZoneProperty("ups", 30)
bombRange.menuTitle = theZone:getStringFromZoneProperty("menuTitle","Contact BOMB RANGE") bombRange.menuTitle = theZone:getStringFromZoneProperty("menuTitle","Contact BOMB RANGE")
if theZone:hasProperty("signIn!") then if theZone:hasProperty("signIn!") then
bombRange.signIn = theZone:getStringFromZoneProperty("signIn!", 30) bombRange.signIn = theZone:getStringFromZoneProperty("signIn!", 30)
@ -551,6 +755,9 @@ function bombRange.start()
-- add event handler -- add event handler
world.addEventHandler(bombRange) world.addEventHandler(bombRange)
-- start GC
bombRange.GC()
return true return true
end end

View File

@ -1,5 +1,5 @@
cfxObjectDestructDetector = {} cfxObjectDestructDetector = {}
cfxObjectDestructDetector.version = "1.3.0" cfxObjectDestructDetector.version = "2.0.0"
cfxObjectDestructDetector.verbose = false cfxObjectDestructDetector.verbose = false
cfxObjectDestructDetector.requiredLibs = { cfxObjectDestructDetector.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -12,11 +12,11 @@ cfxObjectDestructDetector.requiredLibs = {
1.1.0 added support for method, f! and destroyed! 1.1.0 added support for method, f! and destroyed!
1.2.0 DML / Watchflag support 1.2.0 DML / Watchflag support
1.3.0 Persistence support 1.3.0 Persistence support
2.0.0 dmlZone OOP support
clean-up
Detect when an object with OBJECT ID as assigned in ME dies re-wrote object determination to not be affected by
*** EXTENDS ZONES ID changes (happens with map updates)
fail addZone when name property is missing
--]]-- --]]--
cfxObjectDestructDetector.objectZones = {} cfxObjectDestructDetector.objectZones = {}
@ -31,7 +31,7 @@ end
function cfxObjectDestructDetector.invokeCallbacksFor(zone) function cfxObjectDestructDetector.invokeCallbacksFor(zone)
for idx, theCB in pairs (cfxObjectDestructDetector.callbacks) do for idx, theCB in pairs (cfxObjectDestructDetector.callbacks) do
theCB(zone, zone.ID, zone.name) theCB(zone, zone.ID, zone.name, zone.objName)
end end
end end
@ -55,104 +55,55 @@ end
-- processing of zones -- processing of zones
-- --
function cfxObjectDestructDetector.processObjectDestructZone(aZone) function cfxObjectDestructDetector.processObjectDestructZone(aZone)
aZone.name = cfxZones.getStringFromZoneProperty(aZone, "NAME", aZone.name) if aZone:hasProperty("name") then
-- aZone.coalition = cfxZones.getCoalitionFromZoneProperty(aZone, "coalition", 0) aZone.objName = string.upper(aZone:getStringFromZoneProperty("NAME", "default"))
aZone.ID = cfxZones.getNumberFromZoneProperty(aZone, "OBJECT ID", 1) -- THIS! else
trigger.action.outText("+++OOD: Zone <" .. aZone.name .. "> lacks name attribute, ignored for destruct detection.")
return false
end
-- persistence interface -- persistence interface
aZone.isDestroyed = false aZone.isDestroyed = false
--[[-- old code, to be decom'd --]]-- aZone.oddMethod = aZone:getStringFromZoneProperty("method", "inc")
if cfxZones.hasProperty(aZone, "setFlag") then if aZone:hasProperty("oddMethod") then
aZone.setFlag = cfxZones.getStringFromZoneProperty(aZone, "setFlag", "999") aZone.oddMethod = aZone:getStringFromZoneProperty("oddMethod", "inc")
end
if cfxZones.hasProperty(aZone, "f=1") then
aZone.setFlag = cfxZones.getStringFromZoneProperty(aZone, "f=1", "999")
end
if cfxZones.hasProperty(aZone, "clearFlag") then
aZone.clearFlag = cfxZones.getStringFromZoneProperty(aZone, "clearFlag", "999")
end
if cfxZones.hasProperty(aZone, "f=0") then
aZone.clearFlag = cfxZones.getStringFromZoneProperty(aZone, "f=0", "999")
end
if cfxZones.hasProperty(aZone, "increaseFlag") then
aZone.increaseFlag = cfxZones.getStringFromZoneProperty(aZone, "increaseFlag", "999")
end
if cfxZones.hasProperty(aZone, "f+1") then
aZone.increaseFlag = cfxZones.getStringFromZoneProperty(aZone, "f+1", "999")
end
if cfxZones.hasProperty(aZone, "decreaseFlag") then
aZone.decreaseFlag = cfxZones.getStringFromZoneProperty(aZone, "decreaseFlag", "999")
end
if cfxZones.hasProperty(aZone, "f-1") then
aZone.decreaseFlag = cfxZones.getStringFromZoneProperty(aZone, "f-1", "999")
end end
-- DML method support if aZone:hasProperty("f!") then
aZone.oddMethod = cfxZones.getStringFromZoneProperty(aZone, "method", "inc") aZone.outDestroyFlag = aZone:getStringFromZoneProperty("f!", "*none")
if cfxZones.hasProperty(aZone, "oddMethod") then elseif aZone:hasProperty("destroyed!") then
aZone.oddMethod = cfxZones.getStringFromZoneProperty(aZone, "oddMethod", "inc") aZone.outDestroyFlag = aZone:getStringFromZoneProperty("destroyed!", "*none")
end elseif aZone:hasProperty("objectDestroyed!") then
aZone.outDestroyFlag = aZone:getStringFromZoneProperty( "objectDestroyed!", "*none")
-- we now always have that property
aZone.outDestroyFlag = cfxZones.getStringFromZoneProperty(aZone, "f!", "*none")
if cfxZones.hasProperty(aZone, "destroyed!") then
aZone.outDestroyFlag = cfxZones.getStringFromZoneProperty(aZone, "destroyed!", "*none")
end
if cfxZones.hasProperty(aZone, "objectDestroyed!") then
aZone.outDestroyFlag = cfxZones.getStringFromZoneProperty(aZone, "objectDestroyed!", "*none")
end end
return true
end end
-- --
-- MAIN DETECTOR -- ON EVENT
-- --
-- invoke callbacks when an object was destroyed
function cfxObjectDestructDetector:onEvent(event) function cfxObjectDestructDetector:onEvent(event)
if event.id == world.event.S_EVENT_DEAD then if event.id == world.event.S_EVENT_DEAD then
if not event.initiator then return end if not event.initiator then return end
local id = event.initiator:getName() local theObject = event.initiator
if not id then return end local desc = theObject:getDesc()
if not desc then return end
local matchMe = desc.typeName -- we home in on object's typeName
if not matchMe then return end
matchMe = string.upper(matchMe)
for idx, aZone in pairs(cfxObjectDestructDetector.objectZones) do for idx, aZone in pairs(cfxObjectDestructDetector.objectZones) do
if (not aZone.isDestroyed) and aZone.ID == id then if (not aZone.isDestroyed) and aZone.objName == matchMe then
-- flag manipulation
-- OLD FLAG SUPPORT, SOON TO BE REMOVED
if aZone.setFlag then
trigger.action.setUserFlag(aZone.setFlag, 1)
end
if aZone.clearFlag then
trigger.action.setUserFlag(aZone.clearFlag, 0)
end
if aZone.increaseFlag then
local val = trigger.misc.getUserFlag(aZone.increaseFlag) + 1
trigger.action.setUserFlag(aZone.increaseFlag, val)
end
if aZone.decreaseFlag then
local val = trigger.misc.getUserFlag(aZone.decreaseFlag) - 1
trigger.action.setUserFlag(aZone.decreaseFlag, val)
end
-- END OF OLD CODE, TO BE REMOVED
-- support for banging
if aZone.outDestroyFlag then if aZone.outDestroyFlag then
cfxZones.pollFlag(aZone.outDestroyFlag, aZone.oddMethod, aZone) aZone:pollFlag(aZone.outDestroyFlag, aZone.oddMethod)
end end
-- invoke callbacks -- invoke callbacks
cfxObjectDestructDetector.invokeCallbacksFor(aZone) cfxObjectDestructDetector.invokeCallbacksFor(aZone)
if aZone.verbose or cfxObjectDestructDetector.verbose then if aZone.verbose or cfxObjectDestructDetector.verbose then
trigger.action.outText("OBJECT KILL: " .. id, 30) trigger.action.outText("OBJECT KILL: " .. id, 30)
end end
-- we could now remove the object from the list
-- for better performance since it cant
-- die twice
-- save state for persistence -- save state for persistence
aZone.isDestroyed = true aZone.isDestroyed = true
return return
end end
end end
@ -172,7 +123,7 @@ function cfxObjectDestructDetector.saveData() -- invoked by persistence
-- the isDestroyed and flag info info -- the isDestroyed and flag info info
info = {} info = {}
info.isDestroyed = aZone.isDestroyed info.isDestroyed = aZone.isDestroyed
info.outDestroyVal = cfxZones.getFlagValue(aZone.outDestroyFlag, aZone) info.outDestroyVal = aZone:getFlagValue(aZone.outDestroyFlag)
zoneInfo[aZone.name] = info zoneInfo[aZone.name] = info
end end
-- expasion proof: assign as own field -- expasion proof: assign as own field
@ -202,7 +153,7 @@ function cfxObjectDestructDetector.loadMission()
local theZone = cfxObjectDestructDetector.getObjectDetectZoneByName(zName) local theZone = cfxObjectDestructDetector.getObjectDetectZoneByName(zName)
if theZone then if theZone then
theZone.isDestroyed = info.isDestroyed theZone.isDestroyed = info.isDestroyed
cfxZones.setFlagValue(theZone.outDestroyFlag, info.outDestroyVal, theZone) theZone:setFlagValue(theZone.outDestroyFlag, info.outDestroyVal)
if cfxObjectDestructDetector.verbose or theZone.verbose then if cfxObjectDestructDetector.verbose or theZone.verbose then
trigger.action.outText("+++oDDet: persistence setting flag <" .. theZone.outDestroyFlag .. "> to <" .. info.outDestroyVal .. ">",30) trigger.action.outText("+++oDDet: persistence setting flag <" .. theZone.outDestroyFlag .. "> to <" .. info.outDestroyVal .. ">",30)
end end
@ -246,14 +197,14 @@ function cfxObjectDestructDetector.start()
return false return false
end end
-- collect all zones with 'OBJECT id' attribute -- collect all zones with 'OBJECT ID' attribute
-- collect all spawn zones
local attrZones = cfxZones.getZonesWithAttributeNamed("OBJECT ID") local attrZones = cfxZones.getZonesWithAttributeNamed("OBJECT ID")
for k, aZone in pairs(attrZones) do for k, aZone in pairs(attrZones) do
cfxObjectDestructDetector.processObjectDestructZone(aZone) -- process attribute and add to zone properties (extend zone) if cfxObjectDestructDetector.processObjectDestructZone(aZone) then
cfxObjectDestructDetector.addObjectDetectZone(aZone) cfxObjectDestructDetector.addObjectDetectZone(aZone)
end
end end
-- add myself as event handler -- add myself as event handler
@ -276,8 +227,6 @@ function cfxObjectDestructDetector.start()
end end
end end
-- say hi -- say hi
trigger.action.outText("cfx Object Destruct Zones v" .. cfxObjectDestructDetector.version .. " started.", 30) trigger.action.outText("cfx Object Destruct Zones v" .. cfxObjectDestructDetector.version .. " started.", 30)
return true return true

View File

@ -1,5 +1,5 @@
civAir = {} civAir = {}
civAir.version = "2.0.0" civAir.version = "3.0.0"
--[[-- --[[--
1.0.0 initial version 1.0.0 initial version
1.1.0 exclude list for airfields 1.1.0 exclude list for airfields
@ -32,6 +32,16 @@ civAir.version = "2.0.0"
strenghtened guard on testing against free slots for other units strenghtened guard on testing against free slots for other units
flights are now of random neutral countries flights are now of random neutral countries
maxFlights synonym for maxTraffic maxFlights synonym for maxTraffic
3.0.0 liveries support
default liveries for Yak-50 (main test case)
default liveries for C-130, c-17A, IL-76MD, An-30M, An-26B
default aircraft types dcs
support for CAM
default liveries for all CAM types
new DCS attribute
new CAM attribute
deafault to one Yak-40 if neither
support for 'civil_liveries' zone
--]]-- --]]--
@ -39,36 +49,44 @@ civAir.ups = 0.05 -- updates per second. 0.05 = once every 20 seconds
civAir.initialAirSpawns = true -- when true has population spawn in-air at start civAir.initialAirSpawns = true -- when true has population spawn in-air at start
civAir.verbose = false civAir.verbose = false
-- aircraftTypes contains the type names for the neutral air traffic civAir.aircraftTypes = {}
-- each entry has the same chance to be chose, so to make an civAir.dcsBuiltinTypes = {"Yak-40", "C-130", "C-17A", "IL-76MD", "An-30M", "An-26B"}
-- aircraft more probably to appear, add its type multiple times civAir.CAMTypes = { "A_320", "A_330", "A_380", "B_727", "B_737", "B_747", "B_757", "Cessna_210N", "DC_10",}
-- like here with the Yak-40
civAir.aircraftTypes = {"Yak-40", "Yak-40", "C-130", "C-17A", "IL-76MD", "An-30M", "An-26B"} -- civilian planes type strings as described here https://github.com/mrSkortch/DCS-miscScripts/tree/master/ObjectDB
-- maxTraffic is the number of neutral flights that are civAir.liveries = {
-- concurrently under way
-- definitions for plain vanilla DCS
["Yak-40"] = {"Aeroflot", "Algeria GLAM", "Olympic Airways", "Ukranian", "Georgian Airlines", }, --"Georgian Airlines",
["C-130"] = {"Air Algerie L-382 White", "Algerian AF Green", "Algerian AF H30 White", "Belgian Air Force", "Canada's Air Force", "French Air Force", "HAF gray", "IRIAF 5-8503", "IRIAF 5-8518", "Israel Defence Force", "Royal Air Force", "Royal Danish Air Force", "Royal Netherlands Air Force", "Royal Norwegian Air Force", "Spanish Air Force", "Turkish Air Force", "US Air Force", },
["C-17A"] = {"usaf standard", },
["IL-76MD"] = {"Algerian AF IL-76MD", "China Air Force New", "China Air Force Old", "FSB aeroflot", "MVD aeroflot", "RF Air Force", "Ukrainian AF", "Ukrainian AF aeroflot", },
["An-30M"] = {"15th Transport AB", "China CAAC", "RF Air Force"},
["An-26B"] = {"Abkhazian AF", "Aeroflot", "China PLAAF", "Georgian AF", "RF Air Force", "RF Navy", "Ukraine AF", },
-- definitions for CAM mod
["A_320"] = {"Aeroflot", "Aeroflot 1", "Air Asia", "Air Berlin", "Air Berlin FFO", "Air Berlin OLT", "Air Berlin retro", "Air France", "Air Moldova", "Airbus Neo", "Al Maha", "Alitalia", "American Airlines", "British Airways", "Cebu Pacific", "Clean", "Condor", "Delta Airlines", "Easy Jet", "Easy Jet Berlin", "Easy Jet w", "Edelweiss", "Emirates", "Etihad", "Eurowings", "Eurowings BVB09", "Eurowings Europa Park", "Fly Georgia", "Fly Niki", "Frontier", "German Wings", "Gulf Air", "Iberia", "Iran Air", "Jet Blue NY", "JetBlue", "jetBlue FDNY", "Kish Air", "Kuwait Airways", "Lufthansa", "Lufthansa New", "MEA", "MRTT Canada", "MRTT Luftwaffe", "Qatar", "RAF MPA", "RAF VIP", "S7", "SAS", "Saudi Gulf", "Saudia", "Small Planet", "Star Alliance", "SWISS", "Thomas Cook", "Tunis Air", "Turkish Airlines", "United", "Ural Airlines", "US Airways", "Vietnam Airlines", "Virgin", "WiZZ", "WiZZ Budapest", "WOW", },
["A_330"] = {"Aer Lingus", "Aeroflot", "Air Canada", "Air China", "Air Tahiti Nui", "AirAsia", "Airbus", "BOURKHAN", "Brussels Airline", "Cathay Pacific", "CEBU Pacific", "China Eastern", "Clean", "DELTA", "DragonAir", "Edelweiss", "Egypt Air", "Emirates", "ETIHAD", "EVA", "FIJI", "FinnAir", "FrenchBlue", "Garude Indunesia", "GulfAir", "Hainan Airlines", "Iberia", "IRoI", "KLM", "LAN Airways", "Lion Air PK-LEG", "LTU", "Lufthansa", "NWA", "nwaold", "Olympic", "OmanAir", "Orbit", "Philipines", "Qantas", "Qatar", "RAF Voyager", "Singapore", "Skyteam", "Srilankan", "Star Aliance", "Swiss", "Thomas Cook", "Turkish Airlines", "US Airways", "Virgin Atlantic", "WorldTrave", },
["A_380"] = {"Air France", "BA", "China Southern", "Clean", "Emirates", "KA", "LH", "LHF", "Qantas Airways", "QTR", "SA", "TA", },
["B_727"] = {"AEROFLOT", "Air France", "Alaska", "Alitalia", "American Airlines", "Clean", "Delta Airlines", "Delta Airlines OLD", "FedEx", "Hapag Lloyd", "Lufthansa", "Lufthansa Oberhausen Old", "Northwest", "Pan Am", "Singapore Airlines", "Southwest", "UNITED", "UNITED Old", "ZERO G", },
["B_737"] = {"Air Algerie", "Air Berlin", "Air France", "airBaltic", "Airzena", "AM", "American_Airlines", "British Airways", "C40s", "Clean", "Disney", "EA", "easyJet", "FINNAIR", "HARIBO", "JA", "Jet2", "kulula", "LH", "Lufthansa BA", "Lufthansa KR", "OLD_BA", "OMAN AIR", "P8 RAF", "P8 USN", "PAN AM", "Polskie Linie Lotnicze LOT", "QANTAS", "RYANAIR", "SouthWest Lone Star", "ThomsonFly", "TNT", "Ukraine Airlines", "UPS", },
["B_747"] = {"AF", "AF-One", "AI", "CP", "IM", "KLM", "LH", "NW", "PA", "QA", "TA", },
["B_757"] = {"AA", "BA", "C-32", "Delta", "DHL", "easyJet", "Swiss", "Thomson", },
["Cessna_210N"] = {"Blank", "D-EKVW", "HellenicAF", "Muster", "N9572H", "SEagle blue", "SEagle red", "USAF-Academy", "V5-BUG", "VH-JGA", },
["DC_10"] = {"SWISSAIR HB-IHL", "SWISSAIR HB-IMC", "SWISSAIR HB-IPF", }
}
civAir.maxTraffic = 10 -- number of flights at the same time civAir.maxTraffic = 10 -- number of flights at the same time
civAir.maxIdle = 8 * 60 -- seconds of ide time before it is removed after landing civAir.maxIdle = 8 * 60 -- seconds of ide time before it is removed after landing
civAir.trafficCenters = {} civAir.trafficCenters = {}
-- place zones on the map and add a "civAir" attribute.
-- If the attribute's value is anything
-- but "exclude", the closest airfield to the zone
-- is added to trafficCenters
-- if you leave this list empty, and do not add airfields
-- by zones, the list is automatically populated with all
-- airfields in the map
-- if name starts with "***" then it is not an airfield, but zone
civAir.excludeAirfields = {} civAir.excludeAirfields = {}
-- list all airfields that must NOT be included in
-- civilian activities. Will be used for neither landing
-- nor departure. overrides any airfield that was included
-- in trafficCenters.
-- can be populated by zone on the map that have the
-- 'civAir' attribute with value "exclude"
civAir.departOnly = {} -- use only to start from civAir.departOnly = {} -- use only to start from
civAir.landingOnly = {} -- use only to land at civAir.landingOnly = {} -- use only to land at
civAir.inoutZones = {} -- off-map connector zones civAir.inoutZones = {} -- off-map connector zones
@ -86,40 +104,106 @@ function civAir.readConfigZone()
-- note: must match exactly!!!! -- note: must match exactly!!!!
local theZone = cfxZones.getZoneByName("civAirConfig") local theZone = cfxZones.getZoneByName("civAirConfig")
if not theZone then if not theZone then
trigger.action.outText("***civA: NO config zone!", 30)
theZone = cfxZones.createSimpleZone("civAirConfig") theZone = cfxZones.createSimpleZone("civAirConfig")
end end
civAir.verbose = theZone.verbose
civAir.ups = theZone:getNumberFromZoneProperty("ups", 0.05)
if civAir.ups < .0001 then civAir.ups = 0.05 end
-- ok, for each property, load it if it exists
if theZone:hasProperty("aircraftTypes") then
local theTypes = theZone:getStringFromZoneProperty( "aircraftTypes", civAir.aircraftTypes) -- "Yak-40")
local typeArray = dcsCommon.splitString(theTypes, ",")
typeArray = dcsCommon.trimArray(typeArray)
civAir.aircraftTypes = typeArray
end
-- if theZone:hasProperty("ups") then
civAir.ups = theZone:getNumberFromZoneProperty("ups", 0.05)
if civAir.ups < .0001 then civAir.ups = 0.05 end
-- end
if theZone:hasProperty("maxTraffic") then if theZone:hasProperty("maxTraffic") then
civAir.maxTraffic = theZone:getNumberFromZoneProperty( "maxTraffic", 10) civAir.maxTraffic = theZone:getNumberFromZoneProperty( "maxTraffic", 10)
elseif theZone:hasProperty("maxFlights") then else --if theZone:hasProperty("maxFlights") then
civAir.maxTraffic = theZone:getNumberFromZoneProperty( "maxFlights", 10) civAir.maxTraffic = theZone:getNumberFromZoneProperty( "maxFlights", 10)
end end
-- if theZone:hasProperty("maxIdle") then civAir.maxIdle = theZone:getNumberFromZoneProperty("maxIdle", 8 * 60)
civAir.maxIdle = theZone:getNumberFromZoneProperty("maxIdle", 8 * 60)
-- end
-- if theZone:hasProperty("initialAirSpawns") then civAir.initialAirSpawns = theZone:getBoolFromZoneProperty( "initialAirSpawns", true)
civAir.initialAirSpawns = theZone:getBoolFromZoneProperty( "initialAirSpawns", true)
-- end civAir.owner = theZone:getNumberFromZoneProperty("owner", 82) -- default to UN peacekeepers
-- build my aircraft types list
local hasDCS = theZone:getBoolFromZoneProperty("dcs", true)
if hasDCS then
if civAir.verbose then trigger.action.outText("+++civA: adding DCS standard types", 30) end
for idx, aType in pairs(civAir.dcsBuiltinTypes) do
table.insert(civAir.aircraftTypes, aType)
end
end
local hasCAM = theZone:getBoolFromZoneProperty("cam", false)
if hasCAM then
if civAir.verbose then trigger.action.outText("+++civA: adding CAM add-on types", 30) end
for idx, aType in pairs(civAir.CAMTypes) do
table.insert(civAir.aircraftTypes, aType)
end
end
-- now get types and liveries from 'civil_liveries' if present
local livZone = cfxZones.getZoneByName("civil_liveries")
if livZone then
if civAir.verbose then
trigger.action.outText("civA: found and processing 'civil_liveries' zone data.", 30)
end
-- read all into my types registry, replacing whatever is there
local rawLiver = cfxZones.getAllZoneProperties(livZone)
local newTypes, newLiveries = civAir.addTypesAndLiveries(rawLiver)
-- now types to existing types if not already there
for idx, aType in pairs(newTypes) do
dcsCommon.addToTableIfNew(civAir.aircraftTypes, aType)
if civAir.verbose then
trigger.action.outText("+++civA: processed and added aircraft <" .. aType .. "> to civAir", 30)
end
end
-- now replace liveries or add if not already there
for aType, liveries in pairs(newLiveries) do
civAir.liveries[aType] = liveries
if civAir.verbose then
trigger.action.outText("+++civA: replaced/added liveries for aircraft <" .. aType .. ">", 30)
end
end
end
if #civAir.aircraftTypes < 1 then
table.insert(civAir.aircraftTypes, "Yak-40")
if civAir.verbose then
trigger.action.outText("+++civA: adding singular Yak-40", 30)
end
end
-- selective types, overwrites existing types when present
-- also provides legacy support
if theZone:hasProperty("aircraftTypes") then
local theTypes = theZone:getStringFromZoneProperty( "aircraftTypes", civAir.aircraftTypes)
local typeArray = dcsCommon.splitString(theTypes, ",")
typeArray = dcsCommon.trimArray(typeArray)
civAir.aircraftTypes = typeArray
if civAir.verbose then
trigger.action.outText("+++civA: setting aircraft types to <" .. theTypes .. ">", 30)
end
end
civAir.verbose = theZone.verbose
end end
function civAir.addTypesAndLiveries(rawIn)
local newTypes = {}
local newLiveries = {}
-- now iterate the input table, and generate new types and
-- liveries from it
for theType, liveries in pairs (rawIn) do
if civAir.verbose then
trigger.action.outText("+++civA: processing type <" .. theType .. ">:<" .. liveries .. ">", 30)
end
local livA = dcsCommon.splitString(liveries, ',')
livA = dcsCommon.trimArray(livA)
table.insert(newTypes, theType)
newLiveries[theType] = livA
end
return newTypes, newLiveries
end
function civAir.processZone(theZone) function civAir.processZone(theZone)
local value = theZone:getStringFromZoneProperty("civAir", "") local value = theZone:getStringFromZoneProperty("civAir", "")
local af = dcsCommon.getClosestAirbaseTo(theZone.point, 0) -- 0 = only airfields, not farp or ships local af = dcsCommon.getClosestAirbaseTo(theZone.point, 0) -- 0 = only airfields, not farp or ships
@ -137,16 +221,12 @@ function civAir.processZone(theZone)
elseif dcsCommon.stringStartsWith(value, "inb") then elseif dcsCommon.stringStartsWith(value, "inb") then
table.insert(civAir.departOnly, inoutName) -- start in inbound zone table.insert(civAir.departOnly, inoutName) -- start in inbound zone
civAir.inoutZones[inoutName] = theZone civAir.inoutZones[inoutName] = theZone
-- theZone.inbound = true
elseif dcsCommon.stringStartsWith(value, "outb") then elseif dcsCommon.stringStartsWith(value, "outb") then
table.insert(civAir.landingOnly, inoutName) table.insert(civAir.landingOnly, inoutName)
civAir.inoutZones[inoutName] = theZone civAir.inoutZones[inoutName] = theZone
-- theZone.outbound = true
elseif dcsCommon.stringStartsWith(value, "in/out") then elseif dcsCommon.stringStartsWith(value, "in/out") then
table.insert(civAir.trafficCenters, inoutName) table.insert(civAir.trafficCenters, inoutName)
civAir.inoutZones[inoutName] = theZone civAir.inoutZones[inoutName] = theZone
-- theZone.inbound = true
-- theZone.outbound = true
else else
table.insert(civAir.trafficCenters, afName) -- note that adding the same twice makes it more likely to be picked table.insert(civAir.trafficCenters, afName) -- note that adding the same twice makes it more likely to be picked
end end
@ -232,7 +312,6 @@ function civAir.getTwoAirbases()
tries = tries + 1 -- only try 10 times tries = tries + 1 -- only try 10 times
until fAB ~= sAB or tries > 10 until fAB ~= sAB or tries > 10
local civA = {} local civA = {}
if not (dcsCommon.stringStartsWith(fAB, '***')) then if not (dcsCommon.stringStartsWith(fAB, '***')) then
civA.AB = dcsCommon.getFirstAirbaseWhoseNameContains(fAB, 0) civA.AB = dcsCommon.getFirstAirbaseWhoseNameContains(fAB, 0)
@ -295,6 +374,12 @@ function civAir.createFlight(name, theTypeString, fromAirfield, toAirfield, inAi
local theGroup = dcsCommon.createEmptyAircraftGroupData (name) local theGroup = dcsCommon.createEmptyAircraftGroupData (name)
local theAUnit = dcsCommon.createAircraftUnitData(name .. "-GA", theTypeString, false) local theAUnit = dcsCommon.createAircraftUnitData(name .. "-GA", theTypeString, false)
-- add livery capability for this aircraft
civAir.processLiveriesFor(theAUnit, theTypeString)
-- enforce civ attribute
theAUnit.civil_plane = true
theAUnit.payload.fuel = 100000 theAUnit.payload.fuel = 100000
dcsCommon.addUnitToGroupData(theAUnit, theGroup) dcsCommon.addUnitToGroupData(theAUnit, theGroup)
@ -384,13 +469,7 @@ function civAir.createFlight(name, theTypeString, fromAirfield, toAirfield, inAi
dcsCommon.addRoutePointForGroupData(theGroup, toWP) dcsCommon.addRoutePointForGroupData(theGroup, toWP)
-- spawn -- spawn
local groupCat = Group.Category.AIRPLANE local theSpawnedGroup = coalition.addGroup(civAir.owner, groupCat, theGroup) -- 82 is UN peacekeepers
local allNeutral = dcsCommon.getCountriesForCoalition(0)
local aRandomNeutral = dcsCommon.pickRandom(allNeutral)
if not aRandomNeutral then
trigger.action.outText("+++civA: WARNING: no neutral countries exist, flight is not neutral.", 30)
end
local theSpawnedGroup = coalition.addGroup(aRandomNeutral, groupCat, theGroup) -- 82 is UN peacekeepers
if zoneApproach then if zoneApproach then
-- track this flight to target zone -- track this flight to target zone
civAir.outboundFlights[name] = zoneApproach civAir.outboundFlights[name] = zoneApproach
@ -436,6 +515,20 @@ function civAir.airStartPopulation()
civAir.airStartSeparation = civAir.airStartSeparation + 200 civAir.airStartSeparation = civAir.airStartSeparation + 200
civAir.createNewFlight(true) civAir.createNewFlight(true)
end end
-- start update in 15 seconds
timer.scheduleFunction(civAir.update, {}, timer.getTime() + 15)
end
--
-- Livery handling
--
function civAir.processLiveriesFor(theData, theType)
if civAir.liveries[theType] then
local available = civAir.liveries[theType]
local chosen = dcsCommon.pickRandom(available)
theData.livery_id = chosen
end
end end
-- --
@ -632,12 +725,15 @@ function civAir.start()
end end
-- air-start half population if allowed -- air-start half population if allowed
-- allow mission 15 seconds to settle before we start populating to
-- allow better access to liveries
if civAir.initialAirSpawns then if civAir.initialAirSpawns then
civAir.airStartPopulation() timer.scheduleFunction(civAir.airStartPopulation, {}, timer.getTime() + 5)
else
-- start update in 15 seconds
timer.scheduleFunction(civAir.update, {}, timer.getTime() + 15)
end end
-- start the update loop
civAir.update()
-- start outbound tracking -- start outbound tracking
civAir.trackOutbound() civAir.trackOutbound()

View File

@ -1,5 +1,5 @@
cloneZones = {} cloneZones = {}
cloneZones.version = "1.9.0" cloneZones.version = "1.9.1"
cloneZones.verbose = false cloneZones.verbose = false
cloneZones.requiredLibs = { cloneZones.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -106,6 +106,7 @@ cloneZones.respawnOnGroupID = true
- cooldown attribute - cooldown attribute
- cloner collects all types used - cloner collects all types used
- groupScheme attribute - groupScheme attribute
1.9.1 - useAI attribute
--]]-- --]]--
-- --
@ -404,6 +405,8 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
theZone.nameScheme = nil theZone.nameScheme = nil
theZone.groupScheme = nil theZone.groupScheme = nil
end end
theZone.useAI = theZone:getBoolFromZoneProperty("useAI", true)
-- we end with clear plate -- we end with clear plate
end end
@ -1256,6 +1259,8 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
-- see what country we spawn for -- see what country we spawn for
ctry = cloneZones.resolveOwnership(spawnZone, ctry) ctry = cloneZones.resolveOwnership(spawnZone, ctry)
rawData.CZctry = ctry -- save ctry rawData.CZctry = ctry -- save ctry
-- set AI on or off
rawData.useAI = spawnZone.useAI
table.insert(dataToSpawn, rawData) table.insert(dataToSpawn, rawData)
end end
@ -1295,6 +1300,11 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
theGroup = coalition.addGroup(rawData.CZctry, rawData.CZtheCat, rawData) theGroup = coalition.addGroup(rawData.CZctry, rawData.CZtheCat, rawData)
table.insert(spawnedGroups, theGroup) table.insert(spawnedGroups, theGroup)
-- turn off AI if disabled
if not rawData.useAI then
cloneZones.turnOffAI({theGroup})
end
-- update groupXlate table from spawned group -- update groupXlate table from spawned group
-- so we can later reference them with other clones -- so we can later reference them with other clones
local newGroupID = theGroup:getID() -- new ID assigned by DCS local newGroupID = theGroup:getID() -- new ID assigned by DCS
@ -1515,6 +1525,13 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
return spawnedGroups, spawnedStatics return spawnedGroups, spawnedStatics
end end
function cloneZones.turnOffAI(args)
local theGroup = args[1]
local theController = theGroup:getController()
theController:setOnOff(false)
-- trigger.action.outText("turned off AI for group <" .. theGroup:getName() .. "> ", 30)
end
-- retro-fit for helo troops and others to provide 'requestable' support -- retro-fit for helo troops and others to provide 'requestable' support
function cloneZones.spawnWithSpawner(theZone) function cloneZones.spawnWithSpawner(theZone)
-- analog to cfxSpawnZones.spawnWithSpawner(theSpawner) -- analog to cfxSpawnZones.spawnWithSpawner(theSpawner)
@ -1950,6 +1967,10 @@ function cloneZones.loadData()
local gdClone = dcsCommon.clone(gData) local gdClone = dcsCommon.clone(gData)
cloneZones.allClones[gName] = gdClone cloneZones.allClones[gName] = gdClone
local theGroup = coalition.addGroup(cty, cat, gData) local theGroup = coalition.addGroup(cty, cat, gData)
-- turn off AI if disabled
if not gData.useAI then
cloneZones.turnOffAI({theGroup})
end
end end
-- spawn all static objects -- spawn all static objects

View File

@ -1,5 +1,5 @@
dcsCommon = {} dcsCommon = {}
dcsCommon.version = "2.9.5" dcsCommon.version = "2.9.6"
--[[-- VERSION HISTORY --[[-- VERSION HISTORY
2.2.6 - compassPositionOfARelativeToB 2.2.6 - compassPositionOfARelativeToB
- clockPositionOfARelativeToB - clockPositionOfARelativeToB
@ -175,6 +175,7 @@ dcsCommon.version = "2.9.5"
2.9.3 - getAirbasesWhoseNameContains now supports category tables for filtering 2.9.3 - getAirbasesWhoseNameContains now supports category tables for filtering
2.9.4 - new bearing2degrees() 2.9.4 - new bearing2degrees()
2.9.5 - distanceOfPointPToLineXZ(p, p1, p2) 2.9.5 - distanceOfPointPToLineXZ(p, p1, p2)
2.9.6 - new addToTableIfNew()
--]]-- --]]--
@ -402,6 +403,13 @@ dcsCommon.version = "2.9.5"
end end
return outTable return outTable
end end
function dcsCommon.addToTableIfNew(theTable, theElement)
for idx, anElement in pairs(theTable) do
if anElement == theElement then return end
end
table.insert(theTable, theElement)
end
-- --
-- A I R F I E L D S A N D F A R P S -- A I R F I E L D S A N D F A R P S
-- --
@ -2404,38 +2412,9 @@ end
theString = string.upper(theString) theString = string.upper(theString)
thePrefix = string.upper(theString) thePrefix = string.upper(theString)
end end
-- new code because old 'string.find' had some really
-- strange results with aircraft types. Prefix "A-10" did not
-- match string "A-10A" etc.
-- superseded: string.find (s, pattern [, init [, plain]]) solves the problem -- superseded: string.find (s, pattern [, init [, plain]]) solves the problem
--[[
local pl = string.len(thePrefix)
if pl > string.len(theString) then return false end
if pl < 1 then return false end
for i=1, pl do
local left = string.sub(theString, i, i)
local right = string.sub(thePrefix, i, i)
if left ~= right then
return false
end
end
return true
--]]-- trigger.action.outText("---- OK???", 30)
-- strange stuff happening with some strings, let's investigate
local i, j = string.find(theString, thePrefix, 1, true) local i, j = string.find(theString, thePrefix, 1, true)
return (i == 1) return (i == 1)
--[[--
if res then
trigger.action.outText("startswith: <" .. theString .. "> pre <" .. thePrefix .. "> --> YES", 30)
else
trigger.action.outText("startswith: <" .. theString .. "> nojoy pre <" .. thePrefix .. ">", 30)
end
return res
--]]--
end end
function dcsCommon.removePrefix(theString, thePrefix) function dcsCommon.removePrefix(theString, thePrefix)

View File

@ -13,6 +13,8 @@ fireFX.fx = {}
1.0.0 - Initial version 1.0.0 - Initial version
1.1.0 - persistence 1.1.0 - persistence
1.1.1 - agl attribute 1.1.1 - agl attribute
2.0.0 - dmlZones OOP
- rndLoc
--]]-- --]]--
@ -35,7 +37,7 @@ end
-- --
function fireFX.createFXWithZone(theZone) function fireFX.createFXWithZone(theZone)
-- decode size and fire -- decode size and fire
local theSize = cfxZones.getStringFromZoneProperty(theZone, "fireFX", "none") local theSize = theZone:getStringFromZoneProperty("fireFX", "none")
theSize = dcsCommon.trim(theSize) theSize = dcsCommon.trim(theSize)
theSize = string.upper(theSize) theSize = string.upper(theSize)
local fxCode = 1 local fxCode = 1
@ -59,22 +61,22 @@ function fireFX.createFXWithZone(theZone)
trigger.action.outText("+++ffx: new FX with code = <" .. fxCode .. ">", 30) trigger.action.outText("+++ffx: new FX with code = <" .. fxCode .. ">", 30)
end end
theZone.density = cfxZones.getNumberFromZoneProperty(theZone, "density", 0.5) theZone.density = theZone:getNumberFromZoneProperty("density", 0.5)
theZone.agl = cfxZones.getNumberFromZoneProperty(theZone, "AGL", 0) theZone.agl = theZone:getNumberFromZoneProperty("AGL", 0)
theZone.min, theZone.max = theZone:getPositiveRangeFromZoneProperty("num", 1, 1)
if theZone:hasProperty("start?") then
if cfxZones.hasProperty(theZone, "start?") then theZone.fxStart = theZone:getStringFromZoneProperty("start?", "*<none>")
theZone.fxStart = cfxZones.getStringFromZoneProperty(theZone, "start?", "*<none>") theZone.fxLastStart = theZone:getFlagValue(theZone.fxStart)
theZone.fxLastStart = cfxZones.getFlagValue(theZone.fxStart, theZone)
end end
if cfxZones.hasProperty(theZone, "stop?") then if theZone:hasProperty("stop?") then
theZone.fxStop = cfxZones.getStringFromZoneProperty(theZone, "stop?", "*<none>") theZone.fxStop = theZone:getStringFromZoneProperty("stop?", "*<none>")
theZone.fxLastStop = cfxZones.getFlagValue(theZone.fxStop, theZone) theZone.fxLastStop = theZone:getFlagValue(theZone.fxStop)
end end
theZone.fxOnStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", false) theZone.fxOnStart = theZone:getBoolFromZoneProperty("onStart", false)
theZone.burning = false theZone.burning = false
if not theZone.fxOnStart and not theZone.fxStart then if not theZone.fxOnStart and not theZone.fxStart then
@ -84,14 +86,23 @@ function fireFX.createFXWithZone(theZone)
-- output method (not needed) -- output method (not needed)
-- trigger method -- trigger method
theZone.fxTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "fxTriggerMethod", "change") theZone.fxTriggerMethod = theZone:getStringFromZoneProperty( "fxTriggerMethod", "change")
if cfxZones.hasProperty(theZone, "triggerMethod") then if theZone:hasProperty("triggerMethod") then
theZone.fxTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change") theZone.fxTriggerMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
end
theZone.rndLoc = theZone:getBoolFromZoneProperty("rndLoc", false)
if theZone.max + 1 and (not theZone.rndLoc) then
if theZone.verbose or fireFX.verbose then
trigger.action.outText("+++ffx: more than 1 fires, will set to random loc")
end
theZone.rndLoc = true
end end
if fireFX.verbose or theZone.verbose then if fireFX.verbose or theZone.verbose then
trigger.action.outText("+++ffx: new FX <".. theZone.name ..">", 30) trigger.action.outText("+++ffx: new FX <".. theZone.name ..">", 30)
end end
end end
-- --
@ -99,18 +110,29 @@ end
-- --
function fireFX.startTheFire(theZone) function fireFX.startTheFire(theZone)
if not theZone.burning then if not theZone.burning then
local p = cfxZones.getPoint(theZone) theZone.fireNames = {}
p.y = land.getHeight({x = p.x, y = p.z}) + theZone.agl local num = cfxZones.randomInRange(theZone.min, theZone.max)
local preset = theZone.fxCode for i = 1, num do
local density = theZone.density local p = cfxZones.getPoint(theZone)
trigger.action.effectSmokeBig(p, preset, density, theZone.name) if theZone.rndLoc then
p = theZone:randomPointInZone()
end
p.y = land.getHeight({x = p.x, y = p.z}) + theZone.agl
local preset = theZone.fxCode
local density = theZone.density
local fireName = dcsCommon.uuid(theZone.name)
trigger.action.effectSmokeBig(p, preset, density, fireName)
theZone.fireNames[i] = fireName
end
theZone.burning = true theZone.burning = true
end end
end end
function fireFX.extinguishFire(theZone) function fireFX.extinguishFire(theZone)
if theZone.burning then if theZone.burning then
trigger.action.effectSmokeStop(theZone.name) for idx, aFireName in pairs(theZone.fireNames) do
trigger.action.effectSmokeStop(aFireName)
end
theZone.burning = false theZone.burning = false
end end
end end

105
modules/groundExplosion.lua Normal file
View File

@ -0,0 +1,105 @@
groundExplosion = {}
groundExplosion.version = "1.0.0"
groundExplosion.requiredLibs = {
"dcsCommon",
"cfxZones",
}
groundExplosion.zones = {}
--[[--
Version History
1.0.0 - Initial version
--]]--
function groundExplosion.addExplosion(theZone)
theZone.powerMin, theZone.powerMax = theZone:getPositiveRangeFromZoneProperty("explosion", 1, 1)
theZone.triggerMethod = theZone:getStringFromZoneProperty("tiggerMethod", "change")
if theZone:hasProperty("boom?") then
theZone.boom = theZone:getStringFromZoneProperty("boom?", "none")
theZone.lastBoom = theZone:getFlagValue(theZone.boom)
end
theZone.numMin, theZone.numMax = theZone:getPositiveRangeFromZoneProperty("num", 1, 1)
theZone.rndLoc = theZone:getBoolFromZoneProperty("rndLoc", false)
if (theZone.numMax > 1) then
theZone.rndLoc = true
theZone.multi = true
end
theZone.duration = theZone:getNumberFromZoneProperty("duration", 0)
theZone.aglMin, theZone.aglMax = theZone:getPositiveRangeFromZoneProperty("AGL", 1,1)
end
--
-- go boom
--
function groundExplosion.doBoom(args)
local loc = args[1]
local power = args[2]
local theZone = args[3]
trigger.action.explosion(loc, power)
end
function groundExplosion.startBoom(theZone)
local now = timer.getTime()
local num = cfxZones.randomInRange(theZone.numMin, theZone.numMax)
local i = 1
while i <= num do
local loc
if theZone.rndLoc then
loc = theZone:randomPointInZone()
else
loc = theZone:getPoint()
end
local h = land.getHeight({x = loc.x, y = loc.z})
local agl = cfxZones.randomInRange(theZone.aglMin, theZone.aglMax)
loc.y = h + agl
local power = cfxZones.randomInRange(theZone.powerMin, theZone.powerMax)
if theZone.duration > 0 then -- deferred
local tplus = (i-1) * theZone.duration / num
timer.scheduleFunction(groundExplosion.doBoom, {loc, power, theZone}, now + tplus + 0.1)
else -- immediate
trigger.action.explosion(loc, power)
end
i = i + 1
end
end
--
-- Update
--
function groundExplosion.update()
for idx, theZone in pairs(groundExplosion.zones) do
if theZone.boom then
if theZone:testZoneFlag(theZone.boom, theZone.triggerMethod, "lastBoom") then
groundExplosion.startBoom(theZone)
end
end
end
timer.scheduleFunction(groundExplosion.update, {}, timer.getTime() + 1)
end
function groundExplosion.start()
if not dcsCommon.libCheck("cfx groundExplosion",
cfxObjectDestructDetector.requiredLibs) then
return false
end
-- collect all zones with 'OBJECT ID' attribute
local attrZones = cfxZones.getZonesWithAttributeNamed("explosion")
for k, aZone in pairs(attrZones) do
groundExplosion.addExplosion(aZone)
table.insert(groundExplosion.zones, aZone)
end
-- start update
timer.scheduleFunction(groundExplosion.update, {}, timer.getTime() + 1)
return true
end
-- let's go
if not groundExplosion.start() then
trigger.action.outText("cf/x groundExplosion aborted: missing libraries", 30)
groundExplosion = nil
end

View File

@ -1,5 +1,5 @@
pulseFlags = {} pulseFlags = {}
pulseFlags.version = "1.3.3" pulseFlags.version = "2.0.0"
pulseFlags.verbose = false pulseFlags.verbose = false
pulseFlags.requiredLibs = { pulseFlags.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -39,6 +39,9 @@ pulseFlags.requiredLibs = {
- 1.3.1 typos corrected - 1.3.1 typos corrected
- 1.3.2 removed last pulse's timeID upon entry in doPulse - 1.3.2 removed last pulse's timeID upon entry in doPulse
- 1.3.3 removed 'pulsing' when pausing, so we can restart - 1.3.3 removed 'pulsing' when pausing, so we can restart
- 2.0.0 dmlZones / OOP
using method on all outputs
--]]-- --]]--
@ -59,106 +62,86 @@ end
-- --
function pulseFlags.createPulseWithZone(theZone) function pulseFlags.createPulseWithZone(theZone)
if cfxZones.hasProperty(theZone, "pulse") then if theZone:hasProperty("pulse") then
theZone.pulseFlag = cfxZones.getStringFromZoneProperty(theZone, "pulse", "*none") -- the flag to pulse theZone.pulseFlag = theZone:getStringFromZoneProperty("pulse", "*none") -- the flag to pulse
end trigger.action.outText("Warning: pulser in zone <" .. theZone.name .. "> uses deprecated attribuet 'pulse'.", 30)
elseif theZone:hasProperty("pulse!") then
if cfxZones.hasProperty(theZone, "pulse!") then theZone.pulseFlag = theZone:getStringFromZoneProperty("pulse!", "*none") -- the flag to pulse
theZone.pulseFlag = cfxZones.getStringFromZoneProperty(theZone, "pulse!", "*none") -- the flag to pulse
end end
-- time can be number, or number-number range -- time can be number, or number-number range
theZone.minTime, theZone.time = cfxZones.getPositiveRangeFromZoneProperty(theZone, "time", 1) theZone.minTime = 1
if cfxZones.hasProperty(theZone, "pulseInterval") then theZone.time = 1
theZone.minTime, theZone.time = cfxZones.getPositiveRangeFromZoneProperty(theZone, "pulseInterval", 1) if theZone:hasProperty("time") then
theZone.minTime, theZone.time = theZone:getPositiveRangeFromZoneProperty("time", 1)
elseif theZone:hasProperty("pulseInterval") then
theZone.minTime, theZone.time = theZone:getPositiveRangeFromZoneProperty("pulseInterval", 1)
end end
if pulseFlags.verbose or theZone.verbose then if pulseFlags.verbose or theZone.verbose then
trigger.action.outText("+++pulF: zone <" .. theZone.name .. "> time is <".. theZone.minTime ..", " .. theZone.time .. "!", 30) trigger.action.outText("+++pulF: zone <" .. theZone.name .. "> time is <".. theZone.minTime ..", " .. theZone.time .. "!", 30)
end end
theZone.pulses = -1 -- set to infinite theZone.pulses = -1 -- set to infinite
if cfxZones.hasProperty(theZone, "pulses") then if theZone:hasProperty("pulses") then
local minP local minP, maxP = theZone:getPositiveRangeFromZoneProperty("pulses", 1)
local maxP
minP, maxP = cfxZones.getPositiveRangeFromZoneProperty(theZone, "pulses", 1)
if minP == maxP then theZone.pulses = minP if minP == maxP then theZone.pulses = minP
else else
theZone.pulses = cfxZones.randomInRange(minP, maxP) theZone.pulses = cfxZones.randomInRange(minP, maxP)
end end
end end
if pulseFlags.verbose or theZone.verbose then if pulseFlags.verbose or theZone.verbose then
trigger.action.outText("+++pulF: zone <" .. theZone.name .. "> set to <" .. theZone.pulses .. "> pulses", 30) trigger.action.outText("+++pulF: zone <" .. theZone.name .. "> set to <" .. theZone.pulses .. "> pulses", 30)
end end
theZone.pulsesLeft = 0 -- will start new cycle theZone.pulsesLeft = 0 -- will start new cycle
-- watchflag: theZone.pulseTriggerMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
-- triggerMethod
theZone.pulseTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
if cfxZones.hasProperty(theZone, "pulseTriggerMethod") then if theZone:hasProperty("pulseTriggerMethod") then
theZone.pulseTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "pulseTriggerMethod", "change") theZone.pulseTriggerMethod = theZone:getStringFromZoneProperty("pulseTriggerMethod", "change")
end end
-- trigger flags -- trigger flags
if cfxZones.hasProperty(theZone, "activate?") then if theZone:hasProperty("activate?") then
theZone.activatePulseFlag = cfxZones.getStringFromZoneProperty(theZone, "activate?", "none") theZone.activatePulseFlag = theZone:getStringFromZoneProperty("activate?", "none")
theZone.lastActivateValue = cfxZones.getFlagValue(theZone.activatePulseFlag, theZone) -- trigger.misc.getUserFlag(theZone.activatePulseFlag) -- save last value theZone.lastActivateValue = theZone:getFlagValue(theZone.activatePulseFlag)
end end
if cfxZones.hasProperty(theZone, "startPulse?") then if theZone:hasProperty("startPulse?") then
theZone.activatePulseFlag = cfxZones.getStringFromZoneProperty(theZone, "startPulse?", "none") theZone.activatePulseFlag = theZone:getStringFromZoneProperty("startPulse?", "none")
theZone.lastActivateValue = cfxZones.getFlagValue(theZone.activatePulseFlag, theZone) -- trigger.misc.getUserFlag(theZone.activatePulseFlag) -- save last value theZone.lastActivateValue = theZone:getFlagValue(theZone.activatePulseFlag)
end end
if cfxZones.hasProperty(theZone, "pause?") then if theZone:hasProperty("pause?") then
theZone.pausePulseFlag = cfxZones.getStringFromZoneProperty(theZone, "pause?", "*none") theZone.pausePulseFlag = theZone:getStringFromZoneProperty("pause?", "*none")
theZone.lastPauseValue = cfxZones.getFlagValue(theZone.pausePulseFlag, theZone)-- trigger.misc.getUserFlag(theZone.pausePulseFlag) -- save last value theZone.lastPauseValue = theZone:getFlagValue(theZone.pausePulseFlag)
end end
if cfxZones.hasProperty(theZone, "pausePulse?") then if theZone:hasProperty("pausePulse?") then
theZone.pausePulseFlag = cfxZones.getStringFromZoneProperty(theZone, "pausePulse?", "*none") theZone.pausePulseFlag = theZone:getStringFromZoneProperty( "pausePulse?", "*none")
theZone.lastPauseValue = cfxZones.getFlagValue(theZone.pausePulseFlag, theZone)-- trigger.misc.getUserFlag(theZone.pausePulseFlag) -- save last value theZone.lastPauseValue = theZone:getFlagValue(theZone.pausePulseFlag)
end end
-- harmonizing on onStart, and converting to old pulsePaused -- harmonizing on onStart, and converting to old pulsePaused
local onStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", true) local onStart = theZone:getBoolFromZoneProperty("onStart", true)
theZone.pulsePaused = not (onStart) theZone.pulsePaused = not (onStart)
-- old code, to be deprecated
if cfxZones.hasProperty(theZone, "paused") then
theZone.pulsePaused = cfxZones.getBoolFromZoneProperty(theZone, "paused", false)
elseif cfxZones.hasProperty(theZone, "pulseStopped") then theZone.pulseMethod = theZone:getStringFromZoneProperty("method", "inc")
theZone.pulsePaused = cfxZones.getBoolFromZoneProperty(theZone, "pulseStopped", false)
end
--]]--
theZone.pulseMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "flip") if theZone:hasProperty("outputMethod") then
theZone.pulseMethod = theZone:getStringFromZoneProperty( "outputMethod", "inc")
if cfxZones.hasProperty(theZone, "pulseMethod") then
theZone.pulseMethod = cfxZones.getStringFromZoneProperty(theZone, "pulseMethod", "flip")
end
if cfxZones.hasProperty(theZone, "outputMethod") then
theZone.pulseMethod = cfxZones.getStringFromZoneProperty(theZone, "outputMethod", "flip")
end end
-- done flag -- done flag
if cfxZones.hasProperty(theZone, "done+1") then if theZone:hasProperty("pulsesDone!") then
theZone.pulseDoneFlag = cfxZones.getStringFromZoneProperty(theZone, "done+1", "*none") theZone.pulseDoneFlag = theZone:getStringFromZoneProperty("pulsesDone!", "*none")
end end
if cfxZones.hasProperty(theZone, "pulsesDone!") then if theZone:hasProperty("done!") then
theZone.pulseDoneFlag = cfxZones.getStringFromZoneProperty(theZone, "pulsesDone!", "*none") theZone.pulseDoneFlag = theZone:getStringFromZoneProperty("done!", "*none")
end end
if cfxZones.hasProperty(theZone, "done!") then
theZone.pulseDoneFlag = cfxZones.getStringFromZoneProperty(theZone, "done!", "*none")
end
theZone.pulsing = false -- not running theZone.pulsing = false -- not running
theZone.hasPulsed = false theZone.hasPulsed = false
theZone.zeroPulse = cfxZones.getBoolFromZoneProperty(theZone, "zeroPulse", true) theZone.zeroPulse = theZone:getBoolFromZoneProperty("zeroPulse", true)
end end
-- --
@ -185,8 +168,7 @@ function pulseFlags.doPulse(args)
trigger.action.outText("+++pulF: will bang " .. theZone.pulseFlag, 30); trigger.action.outText("+++pulF: will bang " .. theZone.pulseFlag, 30);
end end
cfxZones.pollFlag(theZone.pulseFlag, theZone.pulseMethod, theZone) theZone:pollFlag(theZone.pulseFlag, theZone.pulseMethod)
-- decrease count -- decrease count
if theZone.pulses > 0 then if theZone.pulses > 0 then
-- only do this if ending -- only do this if ending
@ -196,11 +178,10 @@ function pulseFlags.doPulse(args)
if theZone.pulsesLeft < 1 then if theZone.pulsesLeft < 1 then
-- increment done flag if set -- increment done flag if set
if theZone.pulseDoneFlag then if theZone.pulseDoneFlag then
--local currVal = cfxZones.getFlagValue(theZone.pulseDoneFlag, theZone)-- trigger.misc.getUserFlag(theZone.pulseDoneFlag) theZone:pollFlag(theZone.pulseDoneFlag, theZone.pulseMethod)
cfxZones.pollFlag(theZone.pulseDoneFlag, "inc", theZone) -- trigger.action.setUserFlag(theZone.pulseDoneFlag, currVal + 1)
end end
if pulseFlags.verbose or theZone.verbose then if pulseFlags.verbose or theZone.verbose then
trigger.action.outText("+++pulF: pulse <" .. theZone.name .. "> ended!", 30) trigger.action.outText("+++pulF: pulse <" .. theZone.name .. "> ended.", 30)
end end
theZone.pulsing = false theZone.pulsing = false
theZone.pulsePaused = true theZone.pulsePaused = true
@ -218,7 +199,6 @@ function pulseFlags.doPulse(args)
-- if we get here, schedule next pulse -- if we get here, schedule next pulse
local delay = cfxZones.randomDelayFromPositiveRange(theZone.minTime, theZone.time) local delay = cfxZones.randomDelayFromPositiveRange(theZone.minTime, theZone.time)
-- schedule in delay time -- schedule in delay time
theZone.scheduledTime = timer.getTime() + delay theZone.scheduledTime = timer.getTime() + delay
theZone.timerID = timer.scheduleFunction(pulseFlags.doPulse, args, theZone.scheduledTime) theZone.timerID = timer.scheduleFunction(pulseFlags.doPulse, args, theZone.scheduledTime)
@ -228,7 +208,6 @@ function pulseFlags.doPulse(args)
end end
end end
-- start new pulse, will reset -- start new pulse, will reset
function pulseFlags.startNewPulse(theZone) function pulseFlags.startNewPulse(theZone)
theZone.pulsesLeft = theZone.pulses theZone.pulsesLeft = theZone.pulses
@ -241,7 +220,6 @@ function pulseFlags.startNewPulse(theZone)
end end
function pulseFlags.update() function pulseFlags.update()
-- call me in a second to poll triggers
timer.scheduleFunction(pulseFlags.update, {}, timer.getTime() + 1) timer.scheduleFunction(pulseFlags.update, {}, timer.getTime() + 1)
for idx, aZone in pairs(pulseFlags.pulses) do for idx, aZone in pairs(pulseFlags.pulses) do
@ -249,10 +227,7 @@ function pulseFlags.update()
if aZone.pulsing then if aZone.pulsing then
-- this zone has a pulse and has scheduled -- this zone has a pulse and has scheduled
-- a new pulse, nothing to do -- a new pulse, nothing to do
else else
-- this zone has not scheduled a new pulse
-- let's see why
if aZone.pulsePaused then if aZone.pulsePaused then
-- ok, zone is paused. all clear -- ok, zone is paused. all clear
else else
@ -263,7 +238,7 @@ function pulseFlags.update()
-- see if we got a pause or activate command -- see if we got a pause or activate command
-- activatePulseFlag -- activatePulseFlag
if cfxZones.testZoneFlag(aZone, aZone.activatePulseFlag, aZone.pulseTriggerMethod, "lastActivateValue") then if aZone:testZoneFlag(activatePulseFlag, aZone.pulseTriggerMethod, "lastActivateValue") then
if pulseFlags.verbose or aZone.verbose then if pulseFlags.verbose or aZone.verbose then
trigger.action.outText("+++pulF: activating <" .. aZone.name .. ">", 30) trigger.action.outText("+++pulF: activating <" .. aZone.name .. ">", 30)
end end
@ -271,7 +246,7 @@ function pulseFlags.update()
end end
-- pausePulseFlag -- pausePulseFlag
if cfxZones.testZoneFlag(aZone, aZone.pausePulseFlag, aZone.pulseTriggerMethod, "lastPauseValue") then if aZone:testZoneFlag(aZone.pausePulseFlag, aZone.pulseTriggerMethod, "lastPauseValue") then
if pulseFlags.verbose or aZone.verbose then if pulseFlags.verbose or aZone.verbose then
trigger.action.outText("+++pulF: pausing <" .. aZone.name .. ">", 30) trigger.action.outText("+++pulF: pausing <" .. aZone.name .. ">", 30)
end end
@ -296,11 +271,9 @@ function pulseFlags.readConfigZone()
if pulseFlags.verbose then if pulseFlags.verbose then
trigger.action.outText("+++pulF: NO config zone!", 30) trigger.action.outText("+++pulF: NO config zone!", 30)
end end
return theZone = cfxZones.createSimpleZone("pulseFlagsConfig")
end end
pulseFlags.verbose = theZone.verbose
pulseFlags.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
if pulseFlags.verbose then if pulseFlags.verbose then
trigger.action.outText("+++pulF: read config", 30) trigger.action.outText("+++pulF: read config", 30)
end end
@ -385,25 +358,19 @@ function pulseFlags.start()
-- read config -- read config
pulseFlags.readConfigZone() pulseFlags.readConfigZone()
-- process RND Zones -- process "pulse" Zones - deprecated!!
local attrZones = cfxZones.getZonesWithAttributeNamed("pulse") local attrZones = cfxZones.getZonesWithAttributeNamed("pulse")
-- local a = dcsCommon.getSizeOfTable(attrZones)
-- trigger.action.outText("pulse zones: " .. a, 30)
-- now create a pulse gen for each one and add them
-- to our watchlist
for k, aZone in pairs(attrZones) do for k, aZone in pairs(attrZones) do
pulseFlags.createPulseWithZone(aZone) -- process attribute and add to zone pulseFlags.createPulseWithZone(aZone)
pulseFlags.addPulse(aZone) -- remember it so we can pulse it pulseFlags.addPulse(aZone)
end end
attrZones = cfxZones.getZonesWithAttributeNamed("pulse!") attrZones = cfxZones.getZonesWithAttributeNamed("pulse!")
a = dcsCommon.getSizeOfTable(attrZones) a = dcsCommon.getSizeOfTable(attrZones)
trigger.action.outText("pulse! zones: " .. a, 30) trigger.action.outText("pulse! zones: " .. a, 30)
-- now create a pulse gen for each one and add them
-- to our watchlist
for k, aZone in pairs(attrZones) do for k, aZone in pairs(attrZones) do
pulseFlags.createPulseWithZone(aZone) -- process attribute and add to zone pulseFlags.createPulseWithZone(aZone)
pulseFlags.addPulse(aZone) -- remember it so we can pulse it pulseFlags.addPulse(aZone)
end end
-- load any saved data -- load any saved data
@ -417,7 +384,6 @@ function pulseFlags.start()
end end
-- start update in 1 second -- start update in 1 second
--pulseFlags.update()
timer.scheduleFunction(pulseFlags.update, {}, timer.getTime() + 1) timer.scheduleFunction(pulseFlags.update, {}, timer.getTime() + 1)
trigger.action.outText("cfx Pulse Flags v" .. pulseFlags.version .. " started.", 30) trigger.action.outText("cfx Pulse Flags v" .. pulseFlags.version .. " started.", 30)

View File

@ -1,5 +1,5 @@
raiseFlag = {} raiseFlag = {}
raiseFlag.version = "1.2.1" raiseFlag.version = "2.0.0"
raiseFlag.verbose = false raiseFlag.verbose = false
raiseFlag.requiredLibs = { raiseFlag.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -7,19 +7,18 @@ raiseFlag.requiredLibs = {
} }
raiseFlag.flags = {} raiseFlag.flags = {}
--[[-- --[[--
Raise A Flag module -- (c) 2022 by Christian Franz and cf/x AG Raise A Flag module -- (c) 2022-23 by Christian Franz and cf/x AG
Version History
1.0.0 - initial release
1.0.1 - synonym "raiseFlag!"
1.1.0 - DML update
1.2.0 - Watchflag update
1.2.1 - support for 'inc', 'dec', 'flip'
2.0.0 - dmlZones
- full method support
- full DML upgrade
- method attribute (synonym to 'value'
Version History
1.0.0 - initial release
1.0.1 - synonym "raiseFlag!"
1.1.0 - DML update
1.2.0 - Watchflag update
1.2.1 - support for 'inc', 'dec', 'flip'
2.0.0 - dmlZones
- full method support
- full DML upgrade
- method attribute (synonym to 'value')
--]]-- --]]--
function raiseFlag.addRaiseFlag(theZone) function raiseFlag.addRaiseFlag(theZone)
table.insert(raiseFlag.flags, theZone) table.insert(raiseFlag.flags, theZone)
@ -32,7 +31,6 @@ function raiseFlag.getRaiseFlagByName(aName)
if raiseFlag.verbose then if raiseFlag.verbose then
trigger.action.outText("+++rFlg: no raiseFlag with name <" .. aName ..">", 30) trigger.action.outText("+++rFlg: no raiseFlag with name <" .. aName ..">", 30)
end end
return nil return nil
end end
@ -41,10 +39,10 @@ end
-- --
function raiseFlag.createRaiseFlagWithZone(theZone) function raiseFlag.createRaiseFlagWithZone(theZone)
-- get flag from faiseFlag itself -- get flag from faiseFlag itself
if cfxZones.hasProperty(theZone, "raiseFlag") then if theZone:hasProperty("raiseFlag") then
theZone.raiseFlag = cfxZones.getStringFromZoneProperty(theZone, "raiseFlag", "<none>") -- the flag to raise theZone.raiseFlag = theZone:getStringFromZoneProperty("raiseFlag", "<none>") -- the flag to raise
else else
theZone.raiseFlag = cfxZones.getStringFromZoneProperty(theZone, "raiseFlag!", "<none>") -- the flag to raise theZone.raiseFlag = theZone:getStringFromZoneProperty("raiseFlag!", "<none>") -- the flag to raise
end end
-- pre-method DML raiseFlag is now upgraded to method. -- pre-method DML raiseFlag is now upgraded to method.
@ -55,12 +53,7 @@ function raiseFlag.createRaiseFlagWithZone(theZone)
theZone.flagValue = theZone:getStringFromZoneProperty("method", "inc") theZone.flagValue = theZone:getStringFromZoneProperty("method", "inc")
end end
theZone.flagValue = theZone.flagValue:lower() theZone.flagValue = theZone.flagValue:lower()
theZone.minAfterTime, theZone.maxAfterTime = theZone:getPositiveRangeFromZoneProperty("afterTime", -1) theZone.minAfterTime, theZone.maxAfterTime = theZone:getPositiveRangeFromZoneProperty("afterTime", -1)
-- method for triggering
-- watchflag:
-- triggerMethod
theZone.raiseTriggerMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change") theZone.raiseTriggerMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
if theZone:hasProperty("raiseTriggerMethod") then if theZone:hasProperty("raiseTriggerMethod") then
theZone.raiseTriggerMethod = theZone:getStringFromZoneProperty("raiseTriggerMethod", "change") theZone.raiseTriggerMethod = theZone:getStringFromZoneProperty("raiseTriggerMethod", "change")
@ -70,7 +63,6 @@ function raiseFlag.createRaiseFlagWithZone(theZone)
theZone.triggerStopFlag = theZone:getStringFromZoneProperty( "stopFlag?", "none") theZone.triggerStopFlag = theZone:getStringFromZoneProperty( "stopFlag?", "none")
theZone.lastTriggerStopValue = theZone:getFlagValue(theZone.triggerStopFlag) -- save last value theZone.lastTriggerStopValue = theZone:getFlagValue(theZone.triggerStopFlag) -- save last value
end end
theZone.scheduleID = nil theZone.scheduleID = nil
theZone.raiseStopped = false theZone.raiseStopped = false
@ -94,21 +86,6 @@ function raiseFlag.triggered(args)
if raiseFlag.verbose or theZone.verbose then if raiseFlag.verbose or theZone.verbose then
trigger.action.outText("+++rFlg - raising <" .. theZone.raiseFlag .. "> with method '" .. command .. "'" ,30) trigger.action.outText("+++rFlg - raising <" .. theZone.raiseFlag .. "> with method '" .. command .. "'" ,30)
end end
--[[--
command = dcsCommon.trim(command)
if command == "inc" or command == "dec" or command == "flip" then
cfxZones.pollFlag(theZone.raiseFlag, command, theZone)
if raiseFlag.verbose or theZone.verbose then
trigger.action.outText("+++rFlg - raising <" .. theZone.raiseFlag .. "> with method " .. command ,30)
end
else
cfxZones.setFlagValue(theZone.raiseFlag, theZone.flagValue, theZone)
if raiseFlag.verbose or theZone.verbose then
trigger.action.outText("+++rFlg - raising <" .. theZone.raiseFlag .. "> to value: " .. theZone.flagValue ,30)
end
end
--]]--
end end
-- --
@ -117,28 +94,23 @@ end
function raiseFlag.update() function raiseFlag.update()
-- call me in a second to poll triggers -- call me in a second to poll triggers
timer.scheduleFunction(raiseFlag.update, {}, timer.getTime() + 1) timer.scheduleFunction(raiseFlag.update, {}, timer.getTime() + 1)
for idx, aZone in pairs(raiseFlag.flags) do for idx, aZone in pairs(raiseFlag.flags) do
-- make sure to re-start before reading time limit -- make sure to re-start before reading time limit
if aZone:testZoneFlag(aZone.triggerStopFlag, aZone.raiseTriggerMethod, "lastTriggerStopValue") then if aZone:testZoneFlag(aZone.triggerStopFlag, aZone.raiseTriggerMethod, "lastTriggerStopValue") then
theZone.raiseStopped = true -- we are done, no flag! theZone.raiseStopped = true -- we are done, no flag!
end end
end end
end end
-- --
-- config & go! -- config & go!
-- --
function raiseFlag.readConfigZone() function raiseFlag.readConfigZone()
local theZone = cfxZones.getZoneByName("raiseFlagConfig") local theZone = cfxZones.getZoneByName("raiseFlagConfig")
if not theZone then if not theZone then
theZone = cfxZones.createSimpleZone("raiseFlagConfig") theZone = cfxZones.createSimpleZone("raiseFlagConfig")
end end
raiseFlag.verbose = theZone.verbose raiseFlag.verbose = theZone.verbose
if raiseFlag.verbose then if raiseFlag.verbose then
trigger.action.outText("+++rFlg: read config", 30) trigger.action.outText("+++rFlg: read config", 30)
end end
@ -157,7 +129,7 @@ function raiseFlag.start()
-- read config -- read config
raiseFlag.readConfigZone() raiseFlag.readConfigZone()
-- process cloner Zones -- process raise Flags Zones
local attrZones = cfxZones.getZonesWithAttributeNamed("raiseFlag") local attrZones = cfxZones.getZonesWithAttributeNamed("raiseFlag")
for k, aZone in pairs(attrZones) do for k, aZone in pairs(attrZones) do
raiseFlag.createRaiseFlagWithZone(aZone) -- process attributes raiseFlag.createRaiseFlagWithZone(aZone) -- process attributes

View File

@ -1,5 +1,5 @@
stopGap = {} stopGap = {}
stopGap.version = "1.0.9" stopGap.version = "1.0.10"
stopGap.verbose = false stopGap.verbose = false
stopGap.ssbEnabled = true stopGap.ssbEnabled = true
stopGap.ignoreMe = "-sg" stopGap.ignoreMe = "-sg"
@ -48,6 +48,7 @@ stopGap.requiredLibs = {
1.0.8 - added refreshInterval option as requested 1.0.8 - added refreshInterval option as requested
- refresh attribute config zone - refresh attribute config zone
1.0.9 - in line with standalone (optimization not required for DML) 1.0.9 - in line with standalone (optimization not required for DML)
1.0.10 - some more verbosity for spIgnore and sgIgnore zones (DML only)
--]]-- --]]--
@ -356,12 +357,22 @@ end
-- --
function stopGap.createStopGapZone(theZone) function stopGap.createStopGapZone(theZone)
local sg = theZone:getBoolFromZoneProperty("stopGap", true) local sg = theZone:getBoolFromZoneProperty("stopGap", true)
if sg then theZone.sgIgnore = false else theZone.sgIgnore = true end if sg then theZone.sgIgnore = false else
if theZone.verbose or stopGap.verbose then
trigger.action.outText("++sg: Ignoring player craft in zone <" ..theZone.name .."> for all modes", 30)
end
theZone.sgIgnore = true
end
end end
function stopGap.createStopGapSPZone(theZone) function stopGap.createStopGapSPZone(theZone)
local sp = theZone:getBoolFromZoneProperty("stopGapSP", true) local sp = theZone:getBoolFromZoneProperty("stopGapSP", true)
if sp then theZone.spIgnore = false else theZone.spIgnore = true end if sp then theZone.spIgnore = false else
if theZone.verbose or stopGap.verbose then
trigger.action.outText("++sg: Ignoring player craft in zone <" ..theZone.name .."> for single-player mode", 30)
end
theZone.spIgnore = true
end
end end
-- --

Binary file not shown.