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

View File

@ -1,9 +1,15 @@
tdz = {}
tdz.version = "0.9.0dev"
tdz.version = "1.0.0"
tdz.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
}
--[[--
VERSION HISTORY
1.0.0 - Initial version
--]]--
tdz.allTdz = {}
tdz.watchlist = {}
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
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)
if not a then a = 0 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)
-- make it a dml zone
local theNewZone = cfxZones.createSimplePolyZone(name, center, poly)
return theNewZone--, left, right
return theNewZone
end
--
@ -181,7 +163,6 @@ function tdz.playerLanded(theUnit, playerName)
-- make sure unit names match?
local entry = tdz.watchlist[playerName]
entry.hops = entry.hops + 1 -- uh oh.
-- trigger.action.outText("Bump!")
end
-- we may want to filter helicopters
@ -226,7 +207,6 @@ function tdz.playerLanded(theUnit, playerName)
if dOpHdg < dHdg then
opposite = true
dHdg = dOpHdg
trigger.action.outText("opposite rwy detected", 30)
end
if dHdg > math.pi * 1.5 then -- > 270+
dHdg = dHdg - math.pi * 1.5

View File

@ -1,18 +1,34 @@
bombRange = {}
bombRange.version = "1.0.0"
bombRange.version = "1.1.0"
bombRange.dh = 1 -- meters above ground level burst
bombRange.requiredLibs = {
"dcsCommon", -- always
"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.collector = {} -- post-impact collections for 0.5 secs
bombRange.ranges = {} -- all bomb ranges
bombRange.playerData = {} -- player accumulated data
bombRange.unitComms = {} -- command interface per unit
bombRange.tracking = false -- if true, we are tracking projectiles
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)
table.insert(bombRange.bombs, theBomb)
@ -44,7 +60,7 @@ function bombRange.createRange(theZone) -- has bombRange attribte to mark it
end
theZone.details = theZone:getBoolFromZoneProperty("details", false)
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.smokeColor = theZone:getSmokeColorStringFromZoneProperty("smokeColor", "blue")
theZone.flagHits = theZone:getBoolFromZoneProperty("flagHits", false)
@ -237,26 +253,51 @@ end
-- Event Proccing
--
function bombRange.suspectedHit(weapon, target)
if not bombRange.tracking then
return
end
local wType = weapon:getTypeName()
if not target then return end
local theType = target:getTypeName()
if target:getCategory() == 5 then -- scenery
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
if theType == aType then
return
end
end
-- try and match target to my known statics, exit if match
if not target.getID then return end -- units have no getID!
local theID = tonumber(target:getID())
if bombRange.myStatics[theID] then
return
if target.getID then -- units have no getID, so skip for those
local theID = tonumber(target:getID())
if bombRange.myStatics[theID] then
return
end
end
-- look through the tracked weapons for a match
local filtered = {}
-- 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
end
-- look through the tracked weapons for a match next
if not bombRange.tracking then
return
end
local filtered = {}
for idx, b in pairs (bombRange.bombs) do
if b.weapon == weapon then
hasfound = true
@ -264,6 +305,8 @@ function bombRange.suspectedHit(weapon, target)
b.pos = weapon:getPoint()
b.v = weapon:getVelocity()
bombRange.impacted(b, target)
-- trigger.action.outText("susHit: filtering live b <" .. b.name .. ">", 30)
else
table.insert(filtered, b)
end
@ -273,16 +316,106 @@ function bombRange.suspectedHit(weapon, target)
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)
if not event.initiator then return end
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
bombRange.suspectedHit(event.weapon, event.target)
return
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 pName = nil
if theUnit.getPlayerName and theUnit:getPlayerName() ~= nil then
@ -314,6 +447,7 @@ function bombRange:onEvent(event)
b.weapon = w
b.released = timer.getTime()
b.relPos = b.pos
b.ID = dcsCommon.uuid("bomb")
table.insert(bombRange.bombs, b)
if not bombRange.tracking then
timer.scheduleFunction(bombRange.updateBombs, {}, timer.getTime() + 1/bombRange.ups)
@ -336,14 +470,25 @@ end
--
-- Update
--
function bombRange.impacted(weapon, target)
function bombRange.impacted(weapon, target, finalPass)
local targetName = nil
local ipos = weapon.pos -- default to weapon location
if target then
ipos = target:getPoint()
if target then
targetName = target:getDesc()
if targetName then targetName = targetName.displayName 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
-- not an object hit, interpolate the impact point on ground:
-- 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)
return
end
if minDist > theRange.clipDist then
-- no taget zone inside clip dist. disregard this one, too far off
if bombRange.reportLongMisses then
@ -383,11 +529,11 @@ function bombRange.impacted(weapon, target)
return
end
if theRange.smokeHits then
if (not target) and theRange.smokeHits then
trigger.action.smoke(ipos, theRange.smokeColor)
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 p = {x=ipos.x, y=ipos.z}
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)
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
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 tDist = dcsCommon.dist(ipos, weapon.relPos)/1000
tDist = math.floor(tDist*100) /100
@ -404,7 +579,7 @@ function bombRange.impacted(weapon, target)
end
local msg = ""
if theRange:pointInZone(ipos) then
if impactInside then
local percentage = 0
if theRange.isPoly then
percentage = 100
@ -430,29 +605,45 @@ function bombRange.impacted(weapon, target)
bombRange.addImpactForWeapon(weapon, true, percentage)
else
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.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."
bombRange.addImpactForWeapon(weapon, false, 0)
end
if theRange.reporter then
trigger.action.outTextForGroup(weapon.gID,msg , 30)
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
function bombRange.updateBombs()
local now = timer.getTime()
local filtered = {}
for idx, theWeapon in pairs(bombRange.bombs) do
if Weapon.isExist(theWeapon.weapon) then
-- update pos and vel
theWeapon.pos = theWeapon.weapon:getPoint()
theWeapon.v = theWeapon.weapon:getVelocity()
theWeapon.t = now
table.insert(filtered, theWeapon)
else
-- interpolate the impact position from last position
bombRange.impacted(theWeapon)
-- put on collector to time out in 1 seconds to allow
-- 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
@ -468,6 +659,19 @@ function bombRange.updateBombs()
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
--
@ -508,7 +712,7 @@ function bombRange.readConfigZone()
bombRange.filterTypes = dcsCommon.trimArray(theSet)
bombRange.reportLongMisses = theZone:getBoolFromZoneProperty("reportLongMisses", 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")
if theZone:hasProperty("signIn!") then
bombRange.signIn = theZone:getStringFromZoneProperty("signIn!", 30)
@ -551,6 +755,9 @@ function bombRange.start()
-- add event handler
world.addEventHandler(bombRange)
-- start GC
bombRange.GC()
return true
end

View File

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

View File

@ -1,5 +1,5 @@
civAir = {}
civAir.version = "2.0.0"
civAir.version = "3.0.0"
--[[--
1.0.0 initial version
1.1.0 exclude list for airfields
@ -32,43 +32,61 @@ civAir.version = "2.0.0"
strenghtened guard on testing against free slots for other units
flights are now of random neutral countries
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
--]]--
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.verbose = false
-- aircraftTypes contains the type names for the neutral air traffic
-- each entry has the same chance to be chose, so to make an
-- aircraft more probably to appear, add its type multiple times
-- 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
civAir.aircraftTypes = {}
civAir.dcsBuiltinTypes = {"Yak-40", "C-130", "C-17A", "IL-76MD", "An-30M", "An-26B"}
civAir.CAMTypes = { "A_320", "A_330", "A_380", "B_727", "B_737", "B_747", "B_757", "Cessna_210N", "DC_10",}
-- maxTraffic is the number of neutral flights that are
-- concurrently under way
civAir.liveries = {
-- 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.maxIdle = 8 * 60 -- seconds of ide time before it is removed after landing
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 = {}
-- 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.landingOnly = {} -- use only to land at
civAir.inoutZones = {} -- off-map connector zones
@ -86,40 +104,106 @@ function civAir.readConfigZone()
-- note: must match exactly!!!!
local theZone = cfxZones.getZoneByName("civAirConfig")
if not theZone then
trigger.action.outText("***civA: NO config zone!", 30)
theZone = cfxZones.createSimpleZone("civAirConfig")
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
civAir.verbose = theZone.verbose
civAir.ups = theZone:getNumberFromZoneProperty("ups", 0.05)
if civAir.ups < .0001 then civAir.ups = 0.05 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
civAir.maxTraffic = theZone:getNumberFromZoneProperty( "maxTraffic", 10)
elseif theZone:hasProperty("maxFlights") then
else --if theZone:hasProperty("maxFlights") then
civAir.maxTraffic = theZone:getNumberFromZoneProperty( "maxFlights", 10)
end
-- if theZone:hasProperty("maxIdle") then
civAir.maxIdle = theZone:getNumberFromZoneProperty("maxIdle", 8 * 60)
-- end
civAir.maxIdle = theZone:getNumberFromZoneProperty("maxIdle", 8 * 60)
-- if theZone:hasProperty("initialAirSpawns") then
civAir.initialAirSpawns = theZone:getBoolFromZoneProperty( "initialAirSpawns", true)
-- end
civAir.initialAirSpawns = theZone:getBoolFromZoneProperty( "initialAirSpawns", true)
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
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)
local value = theZone:getStringFromZoneProperty("civAir", "")
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
table.insert(civAir.departOnly, inoutName) -- start in inbound zone
civAir.inoutZones[inoutName] = theZone
-- theZone.inbound = true
elseif dcsCommon.stringStartsWith(value, "outb") then
table.insert(civAir.landingOnly, inoutName)
civAir.inoutZones[inoutName] = theZone
-- theZone.outbound = true
elseif dcsCommon.stringStartsWith(value, "in/out") then
table.insert(civAir.trafficCenters, inoutName)
civAir.inoutZones[inoutName] = theZone
-- theZone.inbound = true
-- theZone.outbound = true
else
table.insert(civAir.trafficCenters, afName) -- note that adding the same twice makes it more likely to be picked
end
@ -231,8 +311,7 @@ function civAir.getTwoAirbases()
sAB = dcsCommon.pickRandom(filteredAB)
tries = tries + 1 -- only try 10 times
until fAB ~= sAB or tries > 10
local civA = {}
if not (dcsCommon.stringStartsWith(fAB, '***')) then
civA.AB = dcsCommon.getFirstAirbaseWhoseNameContains(fAB, 0)
@ -295,9 +374,15 @@ function civAir.createFlight(name, theTypeString, fromAirfield, toAirfield, inAi
local theGroup = dcsCommon.createEmptyAircraftGroupData (name)
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
dcsCommon.addUnitToGroupData(theAUnit, theGroup)
local fromWP
if fromAirfield.AB then
fromWP = dcsCommon.createTakeOffFromParkingRoutePointData(fromAirfield.AB)
@ -384,13 +469,7 @@ function civAir.createFlight(name, theTypeString, fromAirfield, toAirfield, inAi
dcsCommon.addRoutePointForGroupData(theGroup, toWP)
-- spawn
local groupCat = Group.Category.AIRPLANE
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
local theSpawnedGroup = coalition.addGroup(civAir.owner, groupCat, theGroup) -- 82 is UN peacekeepers
if zoneApproach then
-- track this flight to target zone
civAir.outboundFlights[name] = zoneApproach
@ -436,6 +515,20 @@ function civAir.airStartPopulation()
civAir.airStartSeparation = civAir.airStartSeparation + 200
civAir.createNewFlight(true)
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
--
@ -609,7 +702,7 @@ function civAir.start()
-- see if there is a config zone and load it
civAir.readConfigZone()
-- look for zones to add to air fields list
civAir.collectHubs()
@ -632,12 +725,15 @@ function civAir.start()
end
-- 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
civAir.airStartPopulation()
timer.scheduleFunction(civAir.airStartPopulation, {}, timer.getTime() + 5)
else
-- start update in 15 seconds
timer.scheduleFunction(civAir.update, {}, timer.getTime() + 15)
end
-- start the update loop
civAir.update()
-- start outbound tracking
civAir.trackOutbound()

View File

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

View File

@ -1,5 +1,5 @@
dcsCommon = {}
dcsCommon.version = "2.9.5"
dcsCommon.version = "2.9.6"
--[[-- VERSION HISTORY
2.2.6 - compassPositionOfARelativeToB
- clockPositionOfARelativeToB
@ -175,6 +175,7 @@ dcsCommon.version = "2.9.5"
2.9.3 - getAirbasesWhoseNameContains now supports category tables for filtering
2.9.4 - new bearing2degrees()
2.9.5 - distanceOfPointPToLineXZ(p, p1, p2)
2.9.6 - new addToTableIfNew()
--]]--
@ -402,6 +403,13 @@ dcsCommon.version = "2.9.5"
end
return outTable
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
--
@ -2404,38 +2412,9 @@ end
theString = string.upper(theString)
thePrefix = string.upper(theString)
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
--[[
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
-- superseded: string.find (s, pattern [, init [, plain]]) solves the problem
local i, j = string.find(theString, thePrefix, 1, true)
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
function dcsCommon.removePrefix(theString, thePrefix)

View File

@ -13,7 +13,9 @@ fireFX.fx = {}
1.0.0 - Initial version
1.1.0 - persistence
1.1.1 - agl attribute
2.0.0 - dmlZones OOP
- rndLoc
--]]--
function fireFX.addFX(theZone)
@ -35,7 +37,7 @@ end
--
function fireFX.createFXWithZone(theZone)
-- decode size and fire
local theSize = cfxZones.getStringFromZoneProperty(theZone, "fireFX", "none")
local theSize = theZone:getStringFromZoneProperty("fireFX", "none")
theSize = dcsCommon.trim(theSize)
theSize = string.upper(theSize)
local fxCode = 1
@ -59,22 +61,22 @@ function fireFX.createFXWithZone(theZone)
trigger.action.outText("+++ffx: new FX with code = <" .. fxCode .. ">", 30)
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 cfxZones.hasProperty(theZone, "start?") then
theZone.fxStart = cfxZones.getStringFromZoneProperty(theZone, "start?", "*<none>")
theZone.fxLastStart = cfxZones.getFlagValue(theZone.fxStart, theZone)
if theZone:hasProperty("start?") then
theZone.fxStart = theZone:getStringFromZoneProperty("start?", "*<none>")
theZone.fxLastStart = theZone:getFlagValue(theZone.fxStart)
end
if cfxZones.hasProperty(theZone, "stop?") then
theZone.fxStop = cfxZones.getStringFromZoneProperty(theZone, "stop?", "*<none>")
theZone.fxLastStop = cfxZones.getFlagValue(theZone.fxStop, theZone)
if theZone:hasProperty("stop?") then
theZone.fxStop = theZone:getStringFromZoneProperty("stop?", "*<none>")
theZone.fxLastStop = theZone:getFlagValue(theZone.fxStop)
end
theZone.fxOnStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", false)
theZone.fxOnStart = theZone:getBoolFromZoneProperty("onStart", false)
theZone.burning = false
if not theZone.fxOnStart and not theZone.fxStart then
@ -84,14 +86,23 @@ function fireFX.createFXWithZone(theZone)
-- output method (not needed)
-- trigger method
theZone.fxTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "fxTriggerMethod", "change")
if cfxZones.hasProperty(theZone, "triggerMethod") then
theZone.fxTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
theZone.fxTriggerMethod = theZone:getStringFromZoneProperty( "fxTriggerMethod", "change")
if theZone:hasProperty("triggerMethod") then
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
if fireFX.verbose or theZone.verbose then
trigger.action.outText("+++ffx: new FX <".. theZone.name ..">", 30)
end
end
--
@ -99,18 +110,29 @@ end
--
function fireFX.startTheFire(theZone)
if not theZone.burning then
local p = cfxZones.getPoint(theZone)
p.y = land.getHeight({x = p.x, y = p.z}) + theZone.agl
local preset = theZone.fxCode
local density = theZone.density
trigger.action.effectSmokeBig(p, preset, density, theZone.name)
theZone.fireNames = {}
local num = cfxZones.randomInRange(theZone.min, theZone.max)
for i = 1, num do
local p = cfxZones.getPoint(theZone)
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
end
end
function fireFX.extinguishFire(theZone)
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
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.version = "1.3.3"
pulseFlags.version = "2.0.0"
pulseFlags.verbose = false
pulseFlags.requiredLibs = {
"dcsCommon", -- always
@ -39,6 +39,9 @@ pulseFlags.requiredLibs = {
- 1.3.1 typos corrected
- 1.3.2 removed last pulse's timeID upon entry in doPulse
- 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)
if cfxZones.hasProperty(theZone, "pulse") then
theZone.pulseFlag = cfxZones.getStringFromZoneProperty(theZone, "pulse", "*none") -- the flag to pulse
end
if cfxZones.hasProperty(theZone, "pulse!") then
theZone.pulseFlag = cfxZones.getStringFromZoneProperty(theZone, "pulse!", "*none") -- the flag to pulse
if theZone:hasProperty("pulse") then
theZone.pulseFlag = theZone:getStringFromZoneProperty("pulse", "*none") -- the flag to pulse
trigger.action.outText("Warning: pulser in zone <" .. theZone.name .. "> uses deprecated attribuet 'pulse'.", 30)
elseif theZone:hasProperty("pulse!") then
theZone.pulseFlag = theZone:getStringFromZoneProperty("pulse!", "*none") -- the flag to pulse
end
-- time can be number, or number-number range
theZone.minTime, theZone.time = cfxZones.getPositiveRangeFromZoneProperty(theZone, "time", 1)
if cfxZones.hasProperty(theZone, "pulseInterval") then
theZone.minTime, theZone.time = cfxZones.getPositiveRangeFromZoneProperty(theZone, "pulseInterval", 1)
theZone.minTime = 1
theZone.time = 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
if pulseFlags.verbose or theZone.verbose then
trigger.action.outText("+++pulF: zone <" .. theZone.name .. "> time is <".. theZone.minTime ..", " .. theZone.time .. "!", 30)
end
theZone.pulses = -1 -- set to infinite
if cfxZones.hasProperty(theZone, "pulses") then
local minP
local maxP
minP, maxP = cfxZones.getPositiveRangeFromZoneProperty(theZone, "pulses", 1)
if theZone:hasProperty("pulses") then
local minP, maxP = theZone:getPositiveRangeFromZoneProperty("pulses", 1)
if minP == maxP then theZone.pulses = minP
else
theZone.pulses = cfxZones.randomInRange(minP, maxP)
end
end
if pulseFlags.verbose or theZone.verbose then
trigger.action.outText("+++pulF: zone <" .. theZone.name .. "> set to <" .. theZone.pulses .. "> pulses", 30)
end
theZone.pulsesLeft = 0 -- will start new cycle
-- watchflag:
-- triggerMethod
theZone.pulseTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
theZone.pulseTriggerMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
if cfxZones.hasProperty(theZone, "pulseTriggerMethod") then
theZone.pulseTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "pulseTriggerMethod", "change")
if theZone:hasProperty("pulseTriggerMethod") then
theZone.pulseTriggerMethod = theZone:getStringFromZoneProperty("pulseTriggerMethod", "change")
end
-- trigger flags
if cfxZones.hasProperty(theZone, "activate?") then
theZone.activatePulseFlag = cfxZones.getStringFromZoneProperty(theZone, "activate?", "none")
theZone.lastActivateValue = cfxZones.getFlagValue(theZone.activatePulseFlag, theZone) -- trigger.misc.getUserFlag(theZone.activatePulseFlag) -- save last value
if theZone:hasProperty("activate?") then
theZone.activatePulseFlag = theZone:getStringFromZoneProperty("activate?", "none")
theZone.lastActivateValue = theZone:getFlagValue(theZone.activatePulseFlag)
end
if cfxZones.hasProperty(theZone, "startPulse?") then
theZone.activatePulseFlag = cfxZones.getStringFromZoneProperty(theZone, "startPulse?", "none")
theZone.lastActivateValue = cfxZones.getFlagValue(theZone.activatePulseFlag, theZone) -- trigger.misc.getUserFlag(theZone.activatePulseFlag) -- save last value
if theZone:hasProperty("startPulse?") then
theZone.activatePulseFlag = theZone:getStringFromZoneProperty("startPulse?", "none")
theZone.lastActivateValue = theZone:getFlagValue(theZone.activatePulseFlag)
end
if cfxZones.hasProperty(theZone, "pause?") then
theZone.pausePulseFlag = cfxZones.getStringFromZoneProperty(theZone, "pause?", "*none")
theZone.lastPauseValue = cfxZones.getFlagValue(theZone.pausePulseFlag, theZone)-- trigger.misc.getUserFlag(theZone.pausePulseFlag) -- save last value
if theZone:hasProperty("pause?") then
theZone.pausePulseFlag = theZone:getStringFromZoneProperty("pause?", "*none")
theZone.lastPauseValue = theZone:getFlagValue(theZone.pausePulseFlag)
end
if cfxZones.hasProperty(theZone, "pausePulse?") then
theZone.pausePulseFlag = cfxZones.getStringFromZoneProperty(theZone, "pausePulse?", "*none")
theZone.lastPauseValue = cfxZones.getFlagValue(theZone.pausePulseFlag, theZone)-- trigger.misc.getUserFlag(theZone.pausePulseFlag) -- save last value
if theZone:hasProperty("pausePulse?") then
theZone.pausePulseFlag = theZone:getStringFromZoneProperty( "pausePulse?", "*none")
theZone.lastPauseValue = theZone:getFlagValue(theZone.pausePulseFlag)
end
-- 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)
-- 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.pulsePaused = cfxZones.getBoolFromZoneProperty(theZone, "pulseStopped", false)
end
--]]--
theZone.pulseMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "flip")
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")
theZone.pulseMethod = theZone:getStringFromZoneProperty("method", "inc")
if theZone:hasProperty("outputMethod") then
theZone.pulseMethod = theZone:getStringFromZoneProperty( "outputMethod", "inc")
end
-- done flag
if cfxZones.hasProperty(theZone, "done+1") then
theZone.pulseDoneFlag = cfxZones.getStringFromZoneProperty(theZone, "done+1", "*none")
if theZone:hasProperty("pulsesDone!") then
theZone.pulseDoneFlag = theZone:getStringFromZoneProperty("pulsesDone!", "*none")
end
if cfxZones.hasProperty(theZone, "pulsesDone!") then
theZone.pulseDoneFlag = cfxZones.getStringFromZoneProperty(theZone, "pulsesDone!", "*none")
if theZone:hasProperty("done!") then
theZone.pulseDoneFlag = theZone:getStringFromZoneProperty("done!", "*none")
end
if cfxZones.hasProperty(theZone, "done!") then
theZone.pulseDoneFlag = cfxZones.getStringFromZoneProperty(theZone, "done!", "*none")
end
theZone.pulsing = false -- not running
theZone.hasPulsed = false
theZone.zeroPulse = cfxZones.getBoolFromZoneProperty(theZone, "zeroPulse", true)
theZone.zeroPulse = theZone:getBoolFromZoneProperty("zeroPulse", true)
end
--
@ -185,8 +168,7 @@ function pulseFlags.doPulse(args)
trigger.action.outText("+++pulF: will bang " .. theZone.pulseFlag, 30);
end
cfxZones.pollFlag(theZone.pulseFlag, theZone.pulseMethod, theZone)
theZone:pollFlag(theZone.pulseFlag, theZone.pulseMethod)
-- decrease count
if theZone.pulses > 0 then
-- only do this if ending
@ -196,11 +178,10 @@ function pulseFlags.doPulse(args)
if theZone.pulsesLeft < 1 then
-- increment done flag if set
if theZone.pulseDoneFlag then
--local currVal = cfxZones.getFlagValue(theZone.pulseDoneFlag, theZone)-- trigger.misc.getUserFlag(theZone.pulseDoneFlag)
cfxZones.pollFlag(theZone.pulseDoneFlag, "inc", theZone) -- trigger.action.setUserFlag(theZone.pulseDoneFlag, currVal + 1)
theZone:pollFlag(theZone.pulseDoneFlag, theZone.pulseMethod)
end
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
theZone.pulsing = false
theZone.pulsePaused = true
@ -218,7 +199,6 @@ function pulseFlags.doPulse(args)
-- if we get here, schedule next pulse
local delay = cfxZones.randomDelayFromPositiveRange(theZone.minTime, theZone.time)
-- schedule in delay time
theZone.scheduledTime = timer.getTime() + delay
theZone.timerID = timer.scheduleFunction(pulseFlags.doPulse, args, theZone.scheduledTime)
@ -228,7 +208,6 @@ function pulseFlags.doPulse(args)
end
end
-- start new pulse, will reset
function pulseFlags.startNewPulse(theZone)
theZone.pulsesLeft = theZone.pulses
@ -241,7 +220,6 @@ function pulseFlags.startNewPulse(theZone)
end
function pulseFlags.update()
-- call me in a second to poll triggers
timer.scheduleFunction(pulseFlags.update, {}, timer.getTime() + 1)
for idx, aZone in pairs(pulseFlags.pulses) do
@ -249,10 +227,7 @@ function pulseFlags.update()
if aZone.pulsing then
-- this zone has a pulse and has scheduled
-- a new pulse, nothing to do
else
-- this zone has not scheduled a new pulse
-- let's see why
if aZone.pulsePaused then
-- ok, zone is paused. all clear
else
@ -263,7 +238,7 @@ function pulseFlags.update()
-- see if we got a pause or activate command
-- 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
trigger.action.outText("+++pulF: activating <" .. aZone.name .. ">", 30)
end
@ -271,7 +246,7 @@ function pulseFlags.update()
end
-- 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
trigger.action.outText("+++pulF: pausing <" .. aZone.name .. ">", 30)
end
@ -296,11 +271,9 @@ function pulseFlags.readConfigZone()
if pulseFlags.verbose then
trigger.action.outText("+++pulF: NO config zone!", 30)
end
return
theZone = cfxZones.createSimpleZone("pulseFlagsConfig")
end
pulseFlags.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
pulseFlags.verbose = theZone.verbose
if pulseFlags.verbose then
trigger.action.outText("+++pulF: read config", 30)
end
@ -385,25 +358,19 @@ function pulseFlags.start()
-- read config
pulseFlags.readConfigZone()
-- process RND Zones
-- process "pulse" Zones - deprecated!!
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
pulseFlags.createPulseWithZone(aZone) -- process attribute and add to zone
pulseFlags.addPulse(aZone) -- remember it so we can pulse it
pulseFlags.createPulseWithZone(aZone)
pulseFlags.addPulse(aZone)
end
attrZones = cfxZones.getZonesWithAttributeNamed("pulse!")
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
pulseFlags.createPulseWithZone(aZone) -- process attribute and add to zone
pulseFlags.addPulse(aZone) -- remember it so we can pulse it
pulseFlags.createPulseWithZone(aZone)
pulseFlags.addPulse(aZone)
end
-- load any saved data
@ -417,7 +384,6 @@ function pulseFlags.start()
end
-- start update in 1 second
--pulseFlags.update()
timer.scheduleFunction(pulseFlags.update, {}, timer.getTime() + 1)
trigger.action.outText("cfx Pulse Flags v" .. pulseFlags.version .. " started.", 30)

View File

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

View File

@ -1,5 +1,5 @@
stopGap = {}
stopGap.version = "1.0.9"
stopGap.version = "1.0.10"
stopGap.verbose = false
stopGap.ssbEnabled = true
stopGap.ignoreMe = "-sg"
@ -48,6 +48,7 @@ stopGap.requiredLibs = {
1.0.8 - added refreshInterval option as requested
- refresh attribute config zone
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)
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
function stopGap.createStopGapSPZone(theZone)
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
--

Binary file not shown.