mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 2.4.4
Removed show-stopping bug in removeMark(), now stops smoke, better drones.
This commit is contained in:
parent
dff5faa06e
commit
2f80033077
File diff suppressed because one or more lines are too long
Binary file not shown.
@ -1,5 +1,5 @@
|
|||||||
FARPZones = {}
|
FARPZones = {}
|
||||||
FARPZones.version = "2.3.0"
|
FARPZones.version = "2.4.0"
|
||||||
FARPZones.verbose = false
|
FARPZones.verbose = false
|
||||||
--[[--
|
--[[--
|
||||||
Version History
|
Version History
|
||||||
@ -28,6 +28,7 @@ FARPZones.verbose = false
|
|||||||
2.2.0 - changing a FARP's owner invokes SSBClient if it is loaded
|
2.2.0 - changing a FARP's owner invokes SSBClient if it is loaded
|
||||||
2.3.0 - new attributes redCap!, blueCap! captured! and farpMethod
|
2.3.0 - new attributes redCap!, blueCap! captured! and farpMethod
|
||||||
- send out signals
|
- send out signals
|
||||||
|
2.4.0 - work-around for crashing DCS bug in trigger.action.removeMark
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
@ -564,6 +565,7 @@ function FARPZones.loadMission()
|
|||||||
|
|
||||||
local farps = theData.farps
|
local farps = theData.farps
|
||||||
if farps then
|
if farps then
|
||||||
|
local delay = timer.getTime() + 0.2
|
||||||
for fName, fData in pairs(farps) do
|
for fName, fData in pairs(farps) do
|
||||||
local theFARP = FARPZones.getFARPZoneByName(fName)
|
local theFARP = FARPZones.getFARPZoneByName(fName)
|
||||||
if theFARP then
|
if theFARP then
|
||||||
@ -574,8 +576,10 @@ function FARPZones.loadMission()
|
|||||||
theFARP.defenderData = dcsCommon.clone(fData.defenderData)
|
theFARP.defenderData = dcsCommon.clone(fData.defenderData)
|
||||||
|
|
||||||
FARPZones.produceVehicles(theFARP) -- do full defender and resource cycle
|
FARPZones.produceVehicles(theFARP) -- do full defender and resource cycle
|
||||||
FARPZones.drawFARPCircleInMap(theFARP) -- mark in map
|
-- stagger drawing the map in time to
|
||||||
|
-- prevent removeMark crashing the thread
|
||||||
|
timer.scheduleFunction(FARPZones.drawFARPCircleInMap, theFARP, delay) -- mark in map
|
||||||
|
delay = delay + 0.2
|
||||||
else
|
else
|
||||||
trigger.action.outText("frpZ: persistence: FARP <" .. fName .. "> no longer exists in mission, skipping", 30)
|
trigger.action.outText("frpZ: persistence: FARP <" .. fName .. "> no longer exists in mission, skipping", 30)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -9,7 +9,7 @@ rndFlags.requiredLibs = {
|
|||||||
Random Flags: DML module to select flags at random
|
Random Flags: DML module to select flags at random
|
||||||
and then change them
|
and then change them
|
||||||
|
|
||||||
Copyright 2022 by Christian Franz and cf/x
|
Copyright 2022-2025 by Christian Franz and cf/x
|
||||||
|
|
||||||
Version History
|
Version History
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxZones = {}
|
cfxZones = {}
|
||||||
cfxZones.version = "4.5.2"
|
cfxZones.version = "4.5.3"
|
||||||
|
|
||||||
-- cf/x zone management module
|
-- cf/x zone management module
|
||||||
-- reads dcs zones and makes them accessible and mutable
|
-- reads dcs zones and makes them accessible and mutable
|
||||||
@ -9,39 +9,15 @@ cfxZones.version = "4.5.2"
|
|||||||
--
|
--
|
||||||
|
|
||||||
--[[-- VERSION HISTORY
|
--[[-- VERSION HISTORY
|
||||||
- 4.1.0 - getBoolFromZoneProperty 'on/off' support for dml variant as well
|
|
||||||
- 4.1.1 - evalRemainder() updates
|
|
||||||
- 4.1.2 - hash property missing warning
|
|
||||||
- 4.2.0 - new createRandomPointInPopulatedZone()
|
|
||||||
- 4.3.0 - boolean supports maybe, random, rnd, ?
|
|
||||||
- small optimization for randomInRange()
|
|
||||||
- randomDelayFromPositiveRange also allows 0
|
|
||||||
- 4.3.1 - new drawText() for zones
|
|
||||||
- dmlZone:getClosestZone() bridge
|
|
||||||
- 4.3.2 - new getListFromZoneProperty()
|
|
||||||
- 4.3.3 - hardened calculateZoneBounds
|
|
||||||
- 4.3.4 - rewrote zone bounds for poly zones
|
|
||||||
- 4.3.5 - hardened getStringFromZoneProperty against number value returns (WebEd bug)
|
|
||||||
- 4.3.6 - tiny optimization in isPointInsideQuad
|
|
||||||
- moving zone - hardening code for static objects
|
|
||||||
- moving zones - now deriving dx, dy,uHeading from dcsCommon xref for linked zones
|
|
||||||
- 4.3.7 - corrected bug in processDynamicValues for lookup table
|
|
||||||
- 4.4.0 - dmlZone:getCoalition()
|
|
||||||
- dmlZone:getTypeName()
|
|
||||||
- dmlZone supports masterOwner by default
|
|
||||||
- dmlZone:getCoalition() dereferences masterOwner once
|
|
||||||
-4.4.1 - better verbosity for error in doPollFlag()
|
|
||||||
-4.4.2 - twn support for wildcards <twn: > and <loc:>
|
|
||||||
-4.4.3 - property name is trimmed (double check)
|
|
||||||
-4.4.4 - createGroundUnitsInZoneForCoalition supports drivable
|
|
||||||
-4.4.5 - corrected startMovingZones() for linked zones via ME's LINKZONE drop-down
|
|
||||||
-4.4.6 - corrected pattern bug in processDynamicAB()
|
|
||||||
-4.5.0 - corrected bug in getBoolFromZoneProperty for default = false and "rnd"
|
-4.5.0 - corrected bug in getBoolFromZoneProperty for default = false and "rnd"
|
||||||
- rnd in bool can have = xxx param for percentage
|
- rnd in bool can have = xxx param for percentage
|
||||||
- getSmokeColorNumberFromZoneProperty()
|
- getSmokeColorNumberFromZoneProperty()
|
||||||
-4.5.1 - moved processSimpleZoneDynamics to common
|
-4.5.1 - moved processSimpleZoneDynamics to common
|
||||||
-4.5.2 - NEW getAllZoneProperties()
|
-4.5.2 - NEW getAllZoneProperties()
|
||||||
- guard agains DCS radius stored as sting (WTF, ED?)
|
- guard agains DCS radius stored as sting (WTF, ED?)
|
||||||
|
-4.5.3 - added name for all smoke meths
|
||||||
|
- getSmokeColorStringFromZoneProperty() supports "?"
|
||||||
|
- getSmokeColorNumberFromZoneProperty() supports "?"
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -71,7 +47,6 @@ end
|
|||||||
-- dmlZone:getTypeName() -- returns "dmlZone"
|
-- dmlZone:getTypeName() -- returns "dmlZone"
|
||||||
-- dmlZone:getCoalition -- returns owner
|
-- dmlZone:getCoalition -- returns owner
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- CLASSIC INTERFACE
|
-- CLASSIC INTERFACE
|
||||||
--
|
--
|
||||||
@ -92,16 +67,14 @@ function cfxZones.readFromDCS(clearfirst)
|
|||||||
trigger.action.outText("cf/x zones: no env.triggers defined", 10)
|
trigger.action.outText("cf/x zones: no env.triggers defined", 10)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if not env.mission.triggers.zones then
|
if not env.mission.triggers.zones then
|
||||||
if cfxZones.verbose then
|
if cfxZones.verbose then
|
||||||
trigger.action.outText("cf/x zones: no zones defined", 10)
|
trigger.action.outText("cf/x zones: no zones defined", 10)
|
||||||
end
|
end
|
||||||
return;
|
return;
|
||||||
end
|
end
|
||||||
|
-- we only retrieve the data that we need. At this point it is name, location and radius
|
||||||
-- we only retrieve the data we need. At this point it is name, location and radius
|
|
||||||
-- and put this in our own little structure. we also convert to all upper case name for index
|
-- and put this in our own little structure. we also convert to all upper case name for index
|
||||||
-- and assume that the name may also carry meaning, e.g. 'LZ:' defines a landing zone
|
-- and assume that the name may also carry meaning, e.g. 'LZ:' defines a landing zone
|
||||||
-- so we can quickly create other sets from this
|
-- so we can quickly create other sets from this
|
||||||
@ -133,16 +106,8 @@ function cfxZones.readFromDCS(clearfirst)
|
|||||||
else
|
else
|
||||||
newZone.properties = {}
|
newZone.properties = {}
|
||||||
end -- WARNING: REF COPY. May need to clone
|
end -- WARNING: REF COPY. May need to clone
|
||||||
--[[--
|
|
||||||
trigger.action.outText("zone <> properties:trimmed", 30)
|
|
||||||
local msg = "["
|
|
||||||
for idx, val in pairs(newZone.properties) do
|
|
||||||
msg = msg .. "<" .. val.key .. ">:<" .. dcsCommon.trim(val.key) .. ">, "
|
|
||||||
end
|
|
||||||
trigger.action.outText(msg, 30)
|
|
||||||
--]]--
|
|
||||||
local upperName = newZone.name:upper()
|
|
||||||
|
|
||||||
|
local upperName = newZone.name:upper()
|
||||||
-- location as 'point'
|
-- location as 'point'
|
||||||
-- WARNING: zones locs are 2D (x,y) pairs, while y in DCS is altitude.
|
-- WARNING: zones locs are 2D (x,y) pairs, while y in DCS is altitude.
|
||||||
-- so we need to change (x,y) into (x, 0, z). Since Zones have no
|
-- so we need to change (x,y) into (x, 0, z). Since Zones have no
|
||||||
@ -160,20 +125,17 @@ function cfxZones.readFromDCS(clearfirst)
|
|||||||
newZone.point = dcsCommon.createPoint(dcsZone.x, 0, dcsZone.y)
|
newZone.point = dcsCommon.createPoint(dcsZone.x, 0, dcsZone.y)
|
||||||
newZone.dcsOrigin = dcsCommon.createPoint(dcsZone.x, 0, dcsZone.y)
|
newZone.dcsOrigin = dcsCommon.createPoint(dcsZone.x, 0, dcsZone.y)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- start type processing. if zone.type exists, we have a mission
|
-- start type processing. if zone.type exists, we have a mission
|
||||||
-- created with 2.7 or above, else earlier
|
-- created with 2.7 or above, else earlier
|
||||||
local zoneType = 0
|
local zoneType = 0
|
||||||
if (dcsZone.type) then
|
if (dcsZone.type) then
|
||||||
zoneType = dcsZone.type
|
zoneType = dcsZone.type
|
||||||
end
|
end
|
||||||
|
|
||||||
if zoneType == 0 then
|
if zoneType == 0 then
|
||||||
-- circular zone
|
-- circular zone
|
||||||
newZone.isCircle = true
|
newZone.isCircle = true
|
||||||
newZone.radius = tonumber(dcsZone.radius)
|
newZone.radius = tonumber(dcsZone.radius)
|
||||||
newZone.maxRadius = newZone.radius -- same for circular
|
newZone.maxRadius = newZone.radius -- same for circular
|
||||||
|
|
||||||
elseif zoneType == 2 then
|
elseif zoneType == 2 then
|
||||||
-- polyZone
|
-- polyZone
|
||||||
newZone.isPoly = true
|
newZone.isPoly = true
|
||||||
@ -190,7 +152,6 @@ function cfxZones.readFromDCS(clearfirst)
|
|||||||
-- in later versions, this was corrected
|
-- in later versions, this was corrected
|
||||||
verts = dcsZone.vertices -- see if this is ever called
|
verts = dcsZone.vertices -- see if this is ever called
|
||||||
end
|
end
|
||||||
|
|
||||||
for v=1, #verts do
|
for v=1, #verts do
|
||||||
local dcsPoint = verts[v]
|
local dcsPoint = verts[v]
|
||||||
local polyPoint = cfxZones.createPointFromDCSPoint(dcsPoint) -- (x, y) --> (x, 0, y-->z)
|
local polyPoint = cfxZones.createPointFromDCSPoint(dcsPoint) -- (x, y) --> (x, 0, y-->z)
|
||||||
@ -201,32 +162,22 @@ function cfxZones.readFromDCS(clearfirst)
|
|||||||
if dist > newZone.maxRadius then newZone.maxRadius = dist end
|
if dist > newZone.maxRadius then newZone.maxRadius = dist end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
|
||||||
trigger.action.outText("cf/x zones: malformed zone #" .. i .. " unknown type " .. zoneType, 10)
|
trigger.action.outText("cf/x zones: malformed zone #" .. i .. " unknown type " .. zoneType, 10)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- calculate bounds
|
-- calculate bounds
|
||||||
cfxZones.calculateZoneBounds(newZone)
|
cfxZones.calculateZoneBounds(newZone)
|
||||||
|
|
||||||
-- add to my table
|
-- add to my table
|
||||||
cfxZones.zones[upperName] = newZone -- WARNING: UPPER ZONE!!!
|
cfxZones.zones[upperName] = newZone -- WARNING: UPPER ZONE!!!
|
||||||
|
|
||||||
else
|
else
|
||||||
if cfxZones.verbose then
|
if cfxZones.verbose then trigger.action.outText("cf/x zones: malformed zone #" .. i .. " dropped", 10) end
|
||||||
trigger.action.outText("cf/x zones: malformed zone #" .. i .. " dropped", 10)
|
|
||||||
end
|
|
||||||
end -- else var not a table
|
end -- else var not a table
|
||||||
|
|
||||||
end -- for all zones kvp
|
end -- for all zones kvp
|
||||||
end -- readFromDCS
|
end -- readFromDCS
|
||||||
|
|
||||||
function cfxZones.calculateZoneBounds(theZone)
|
function cfxZones.calculateZoneBounds(theZone)
|
||||||
if not (theZone) then return
|
if not (theZone) then return
|
||||||
end
|
end
|
||||||
|
|
||||||
local bounds = theZone.bounds -- copy ref! -- DON'T BELIEVE THIS!
|
local bounds = theZone.bounds -- copy ref! -- DON'T BELIEVE THIS!
|
||||||
|
|
||||||
if theZone.isCircle then
|
if theZone.isCircle then
|
||||||
-- aabb are easy: center +/- radius
|
-- aabb are easy: center +/- radius
|
||||||
local center = theZone.point
|
local center = theZone.point
|
||||||
@ -237,7 +188,6 @@ function cfxZones.calculateZoneBounds(theZone)
|
|||||||
bounds.ur = dcsCommon.createPoint(center.x + radius, 0, center.z - radius)
|
bounds.ur = dcsCommon.createPoint(center.x + radius, 0, center.z - radius)
|
||||||
bounds.ll = dcsCommon.createPoint(center.x - radius, 0, center.z + radius)
|
bounds.ll = dcsCommon.createPoint(center.x - radius, 0, center.z + radius)
|
||||||
bounds.lr = dcsCommon.createPoint(center.x + radius, 0, center.z + radius)
|
bounds.lr = dcsCommon.createPoint(center.x + radius, 0, center.z + radius)
|
||||||
|
|
||||||
-- write back
|
-- write back
|
||||||
theZone.bounds = bounds
|
theZone.bounds = bounds
|
||||||
elseif theZone.isPoly then
|
elseif theZone.isPoly then
|
||||||
@ -245,7 +195,6 @@ function cfxZones.calculateZoneBounds(theZone)
|
|||||||
-- create the four points
|
-- create the four points
|
||||||
local p = cfxZones.createPointFromPoint(poly[1])
|
local p = cfxZones.createPointFromPoint(poly[1])
|
||||||
local pRad = dcsCommon.dist(theZone.point, poly[1]) -- rRad is radius for polygon from theZone.point
|
local pRad = dcsCommon.dist(theZone.point, poly[1]) -- rRad is radius for polygon from theZone.point
|
||||||
|
|
||||||
-- now iterate through all points and adjust bounds accordingly
|
-- now iterate through all points and adjust bounds accordingly
|
||||||
local lx, ly, mx, my = p.x, p.z, p.x, p.z
|
local lx, ly, mx, my = p.x, p.z, p.x, p.z
|
||||||
for vtx=1, #poly do
|
for vtx=1, #poly do
|
||||||
@ -257,7 +206,6 @@ function cfxZones.calculateZoneBounds(theZone)
|
|||||||
local dp = dcsCommon.dist(theZone.point, v)
|
local dp = dcsCommon.dist(theZone.point, v)
|
||||||
if dp > pRad then pRad = dp end -- find largst distance to vertex
|
if dp > pRad then pRad = dp end -- find largst distance to vertex
|
||||||
end
|
end
|
||||||
|
|
||||||
theZone.bounds.ul = dcsCommon.createPoint(lx, 0, my)
|
theZone.bounds.ul = dcsCommon.createPoint(lx, 0, my)
|
||||||
theZone.bounds.ur = dcsCommon.createPoint(mx, 0, my)
|
theZone.bounds.ur = dcsCommon.createPoint(mx, 0, my)
|
||||||
theZone.bounds.ll = dcsCommon.createPoint(lx, 0, ly)
|
theZone.bounds.ll = dcsCommon.createPoint(lx, 0, ly)
|
||||||
@ -270,7 +218,6 @@ function cfxZones.calculateZoneBounds(theZone)
|
|||||||
trigger.action.outText("cf/x zones: calc bounds: zone " .. theZone.name .. " has unknown type", 30)
|
trigger.action.outText("cf/x zones: calc bounds: zone " .. theZone.name .. " has unknown type", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function dmlZone:calculateZoneBounds()
|
function dmlZone:calculateZoneBounds()
|
||||||
@ -308,7 +255,6 @@ function cfxZones.createPointFromDCSPoint(inPoint)
|
|||||||
return dcsCommon.createPoint(inPoint.x, 0, inPoint.y)
|
return dcsCommon.createPoint(inPoint.x, 0, inPoint.y)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function cfxZones.createRandomPointInsideBounds(bounds)
|
function cfxZones.createRandomPointInsideBounds(bounds)
|
||||||
-- warning: bounds do not move woth zone! may have to be updated
|
-- warning: bounds do not move woth zone! may have to be updated
|
||||||
local x = math.random(bounds.ll.x, ur.x)
|
local x = math.random(bounds.ll.x, ur.x)
|
||||||
@ -362,8 +308,7 @@ function cfxZones.createRandomPointInCircleZone(theZone, onEdge)
|
|||||||
if not theZone.isCircle then
|
if not theZone.isCircle then
|
||||||
trigger.action.outText("+++Zones: warning - createRandomPointInCircleZone called for non-circle zone <" .. theZone.name .. ">", 30)
|
trigger.action.outText("+++Zones: warning - createRandomPointInCircleZone called for non-circle zone <" .. theZone.name .. ">", 30)
|
||||||
return {x=theZone.point.x, y=0, z=theZone.point.z}
|
return {x=theZone.point.x, y=0, z=theZone.point.z}
|
||||||
end
|
end
|
||||||
|
|
||||||
-- ok, let's first create a random percentage value for the new radius
|
-- ok, let's first create a random percentage value for the new radius
|
||||||
-- now lets get a random degree
|
-- now lets get a random degree
|
||||||
local degrees = math.random() * 2 * 3.14152 -- radiants.
|
local degrees = math.random() * 2 * 3.14152 -- radiants.
|
||||||
@ -391,11 +336,9 @@ function cfxZones.createRandomPointInPolyZone(theZone, onEdge)
|
|||||||
end
|
end
|
||||||
-- force update of all points
|
-- force update of all points
|
||||||
local p = cfxZones.getPoint(theZone)
|
local p = cfxZones.getPoint(theZone)
|
||||||
|
|
||||||
-- point in convex poly: choose two different lines from that polygon
|
-- point in convex poly: choose two different lines from that polygon
|
||||||
local lineIdxA = dcsCommon.smallRandom(#theZone.poly)
|
local lineIdxA = dcsCommon.smallRandom(#theZone.poly)
|
||||||
repeat lineIdxB = dcsCommon.smallRandom(#theZone.poly) until (lineIdxA ~= lineIdxB)
|
repeat lineIdxB = dcsCommon.smallRandom(#theZone.poly) until (lineIdxA ~= lineIdxB)
|
||||||
|
|
||||||
-- we now have two different lines. pick a random point on each.
|
-- we now have two different lines. pick a random point on each.
|
||||||
-- we use lerp to pick any point between a and b
|
-- we use lerp to pick any point between a and b
|
||||||
local a = theZone.poly[lineIdxA]
|
local a = theZone.poly[lineIdxA]
|
||||||
@ -409,7 +352,6 @@ function cfxZones.createRandomPointInPolyZone(theZone, onEdge)
|
|||||||
local polyPoint = sourceA
|
local polyPoint = sourceA
|
||||||
return polyPoint, polyPoint.x - p.x, polyPoint.z - p.z -- return loc, dx, dz
|
return polyPoint, polyPoint.x - p.x, polyPoint.z - p.z -- return loc, dx, dz
|
||||||
end
|
end
|
||||||
|
|
||||||
-- now get point on second line
|
-- now get point on second line
|
||||||
a = theZone.poly[lineIdxB]
|
a = theZone.poly[lineIdxB]
|
||||||
lineIdxB = lineIdxB + 1 -- get next point in poly and wrap around
|
lineIdxB = lineIdxB + 1 -- get next point in poly and wrap around
|
||||||
@ -417,7 +359,6 @@ function cfxZones.createRandomPointInPolyZone(theZone, onEdge)
|
|||||||
b = theZone.poly[lineIdxB]
|
b = theZone.poly[lineIdxB]
|
||||||
randompercent = math.random()
|
randompercent = math.random()
|
||||||
local sourceB = dcsCommon.vLerp (a, b, randompercent)
|
local sourceB = dcsCommon.vLerp (a, b, randompercent)
|
||||||
|
|
||||||
-- now take a random point on that line that entirely
|
-- now take a random point on that line that entirely
|
||||||
-- runs through the poly
|
-- runs through the poly
|
||||||
randompercent = math.random()
|
randompercent = math.random()
|
||||||
@ -443,14 +384,9 @@ function dmlZone:createRandomPointInPopulatedZone(radius, maxTries)
|
|||||||
local o = collector[1]
|
local o = collector[1]
|
||||||
local op = o:getPoint()
|
local op = o:getPoint()
|
||||||
d = dcsCommon.distFlat(op, p)
|
d = dcsCommon.distFlat(op, p)
|
||||||
-- trigger.action.outText("singleDist = " .. d, 30)
|
if d > radius/2 then return p, dx, dz end
|
||||||
if d > radius/2 then
|
|
||||||
-- trigger.action.outText("good enough, will use", 30)
|
|
||||||
return p, dx, dz
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
cnt = cnt + 1
|
cnt = cnt + 1
|
||||||
-- trigger.action.outText(hits .. "hits --> failed try " .. cnt, 30)
|
|
||||||
until cnt > maxTries
|
until cnt > maxTries
|
||||||
return p, dx, dz
|
return p, dx, dz
|
||||||
end
|
end
|
||||||
@ -489,15 +425,9 @@ function cfxZones.objectsInRange(pt, range)
|
|||||||
local op = anObject:getPoint()
|
local op = anObject:getPoint()
|
||||||
local dist = dcsCommon.dist(pt, op)
|
local dist = dcsCommon.dist(pt, op)
|
||||||
if dist < range then
|
if dist < range then
|
||||||
-- local e = {
|
|
||||||
-- dist = dist,
|
|
||||||
-- o = anObject
|
|
||||||
-- }
|
|
||||||
-- table.insert(filtered, e)
|
|
||||||
table.insert(filtered, anObject)
|
table.insert(filtered, anObject)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return #filtered, filtered
|
return #filtered, filtered
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -544,18 +474,14 @@ function cfxZones.createCircleZone(name, x, z, radius)
|
|||||||
newZone.isPoly = false
|
newZone.isPoly = false
|
||||||
newZone.poly = {}
|
newZone.poly = {}
|
||||||
newZone.bounds = {}
|
newZone.bounds = {}
|
||||||
|
|
||||||
newZone.name = name
|
newZone.name = name
|
||||||
newZone.radius = radius
|
newZone.radius = radius
|
||||||
newZone.point = dcsCommon.createPoint(x, 0, z)
|
newZone.point = dcsCommon.createPoint(x, 0, z)
|
||||||
newZone.dcsOrigin = dcsCommon.createPoint(x, 0, z)
|
newZone.dcsOrigin = dcsCommon.createPoint(x, 0, z)
|
||||||
|
|
||||||
-- props
|
-- props
|
||||||
newZone.properties = {}
|
newZone.properties = {}
|
||||||
|
|
||||||
-- calculate my bounds
|
-- calculate my bounds
|
||||||
cfxZones.calculateZoneBounds(newZone)
|
cfxZones.calculateZoneBounds(newZone)
|
||||||
|
|
||||||
return newZone
|
return newZone
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -567,9 +493,7 @@ function cfxZones.createSimplePolyZone(name, location, points, addToManaged)
|
|||||||
if not location.x then location.x = 0 end
|
if not location.x then location.x = 0 end
|
||||||
if not location.z then location.z = 0 end
|
if not location.z then location.z = 0 end
|
||||||
if not location.y then location.y = 0 end
|
if not location.y then location.y = 0 end
|
||||||
|
|
||||||
local newZone = cfxZones.createPolyZone(name, points, location)
|
local newZone = cfxZones.createPolyZone(name, points, location)
|
||||||
|
|
||||||
if addToManaged then
|
if addToManaged then
|
||||||
cfxZones.addZoneToManagedZones(newZone)
|
cfxZones.addZoneToManagedZones(newZone)
|
||||||
end
|
end
|
||||||
@ -617,7 +541,6 @@ function cfxZones.createPolyZone(name, poly, location) -- poly must be array of
|
|||||||
newZone.isPoly = true
|
newZone.isPoly = true
|
||||||
newZone.poly = {}
|
newZone.poly = {}
|
||||||
newZone.bounds = {}
|
newZone.bounds = {}
|
||||||
|
|
||||||
newZone.name = name
|
newZone.name = name
|
||||||
newZone.radius = 0
|
newZone.radius = 0
|
||||||
-- copy poly
|
-- copy poly
|
||||||
@ -625,10 +548,8 @@ function cfxZones.createPolyZone(name, poly, location) -- poly must be array of
|
|||||||
local theVertex = poly[v]
|
local theVertex = poly[v]
|
||||||
newZone.poly[v] = cfxZones.createPointFromPoint(theVertex)
|
newZone.poly[v] = cfxZones.createPointFromPoint(theVertex)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- properties
|
-- properties
|
||||||
newZone.properties = {}
|
newZone.properties = {}
|
||||||
|
|
||||||
cfxZones.calculateZoneBounds(newZone)
|
cfxZones.calculateZoneBounds(newZone)
|
||||||
return newZone
|
return newZone
|
||||||
end
|
end
|
||||||
@ -638,7 +559,6 @@ function cfxZones.createRandomZoneInZone(name, inZone, targetRadius, entirelyIns
|
|||||||
-- if entirelyInside is false, only the zone's center is guaranteed to be inside
|
-- if entirelyInside is false, only the zone's center is guaranteed to be inside
|
||||||
-- inZone.
|
-- inZone.
|
||||||
-- entirelyInside is not guaranteed for polyzones
|
-- entirelyInside is not guaranteed for polyzones
|
||||||
|
|
||||||
if inZone.isCircle then
|
if inZone.isCircle then
|
||||||
local sourceRadius = inZone.radius
|
local sourceRadius = inZone.radius
|
||||||
if entirelyInside and targetRadius > sourceRadius then targetRadius = sourceRadius end
|
if entirelyInside and targetRadius > sourceRadius then targetRadius = sourceRadius end
|
||||||
@ -654,13 +574,11 @@ function cfxZones.createRandomZoneInZone(name, inZone, targetRadius, entirelyIns
|
|||||||
-- construct new zone
|
-- construct new zone
|
||||||
local newZone = cfxZones.createCircleZone(name, x, z, targetRadius)
|
local newZone = cfxZones.createCircleZone(name, x, z, targetRadius)
|
||||||
return newZone
|
return newZone
|
||||||
|
|
||||||
elseif inZone.isPoly then
|
elseif inZone.isPoly then
|
||||||
local newPoint = cfxZones.createRandomPointInPolyZone(inZone)
|
local newPoint = cfxZones.createRandomPointInPolyZone(inZone)
|
||||||
-- construct new zone
|
-- construct new zone
|
||||||
local newZone = cfxZones.createCircleZone(name, newPoint.x, newPoint.z, targetRadius)
|
local newZone = cfxZones.createCircleZone(name, newPoint.x, newPoint.z, targetRadius)
|
||||||
return newZone
|
return newZone
|
||||||
|
|
||||||
else
|
else
|
||||||
-- zone type unknown
|
-- zone type unknown
|
||||||
trigger.action.outText("CreateZoneInZone: unknown zone type for inZone =" .. inZone.name , 10)
|
trigger.action.outText("CreateZoneInZone: unknown zone type for inZone =" .. inZone.name , 10)
|
||||||
@ -707,7 +625,6 @@ function cfxZones.isPointInsidePoly(thePoint, poly)
|
|||||||
end
|
end
|
||||||
-- final test
|
-- final test
|
||||||
if cfxZones.isLeftXZ(poly[#poly], poly[1], thePoint) ~= mustMatch then return false end
|
if cfxZones.isLeftXZ(poly[#poly], poly[1], thePoint) ~= mustMatch then return false end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -720,12 +637,10 @@ function cfxZones.isPointInsideZone(thePoint, theZone, radiusIncrease)
|
|||||||
local d = dcsCommon.dist(p, theZone.point)
|
local d = dcsCommon.dist(p, theZone.point)
|
||||||
return d < theZone.radius + radiusIncrease, d
|
return d < theZone.radius + radiusIncrease, d
|
||||||
end
|
end
|
||||||
|
|
||||||
if (theZone.isPoly) then
|
if (theZone.isPoly) then
|
||||||
--trigger.action.outText("zne: isPointInside: " .. theZone.name .. " is Polyzone!", 30)
|
--trigger.action.outText("zne: isPointInside: " .. theZone.name .. " is Polyzone!", 30)
|
||||||
return (cfxZones.isPointInsidePoly(p, theZone.poly)), 0 -- always returns delta 0
|
return (cfxZones.isPointInsidePoly(p, theZone.poly)), 0 -- always returns delta 0
|
||||||
end
|
end
|
||||||
|
|
||||||
trigger.action.outText("isPointInsideZone: Unknown zone type for " .. outerZone.name, 10)
|
trigger.action.outText("isPointInsideZone: Unknown zone type for " .. outerZone.name, 10)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -747,14 +662,12 @@ function cfxZones.getZonesContainingPoint(thePoint, testZones) -- return array
|
|||||||
if not testZones then
|
if not testZones then
|
||||||
testZones = cfxZones.zones
|
testZones = cfxZones.zones
|
||||||
end
|
end
|
||||||
|
|
||||||
local containerZones = {}
|
local containerZones = {}
|
||||||
for tName, tData in pairs(testZones) do
|
for tName, tData in pairs(testZones) do
|
||||||
if cfxZones.isPointInsideZone(thePoint, tData) then
|
if cfxZones.isPointInsideZone(thePoint, tData) then
|
||||||
table.insert(containerZones, tData)
|
table.insert(containerZones, tData)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return containerZones
|
return containerZones
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -762,13 +675,11 @@ function cfxZones.getFirstZoneContainingPoint(thePoint, testZones)
|
|||||||
if not testZones then
|
if not testZones then
|
||||||
testZones = cfxZones.zones
|
testZones = cfxZones.zones
|
||||||
end
|
end
|
||||||
|
|
||||||
for tName, tData in pairs(testZones) do
|
for tName, tData in pairs(testZones) do
|
||||||
if cfxZones.isPointInsideZone(thePoint, tData) then
|
if cfxZones.isPointInsideZone(thePoint, tData) then
|
||||||
return tData
|
return tData
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -776,7 +687,6 @@ function cfxZones.getAllZonesInsideZone(superZone, testZones) -- returnes array!
|
|||||||
if not testZones then
|
if not testZones then
|
||||||
testZones = cfxZones.zones
|
testZones = cfxZones.zones
|
||||||
end
|
end
|
||||||
|
|
||||||
local containedZones = {}
|
local containedZones = {}
|
||||||
for zName, zData in pairs(testZones) do
|
for zName, zData in pairs(testZones) do
|
||||||
if cfxZones.isZoneInsideZone(zData, superZone) then
|
if cfxZones.isZoneInsideZone(zData, superZone) then
|
||||||
@ -794,10 +704,8 @@ function dmlZone:getAllZonesInsideZone(testZones)
|
|||||||
return cfxZones.getAllZonesInsideZone(self, testZones)
|
return cfxZones.getAllZonesInsideZone(self, testZones)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function cfxZones.getZonesWithAttributeNamed(attributeName, testZones)
|
function cfxZones.getZonesWithAttributeNamed(attributeName, testZones)
|
||||||
if not testZones then testZones = cfxZones.zones end
|
if not testZones then testZones = cfxZones.zones end
|
||||||
|
|
||||||
local attributZones = {}
|
local attributZones = {}
|
||||||
for aName,aZone in pairs(testZones) do
|
for aName,aZone in pairs(testZones) do
|
||||||
local attr = cfxZones.getZoneProperty(aZone, attributeName)
|
local attr = cfxZones.getZoneProperty(aZone, attributeName)
|
||||||
@ -808,14 +716,11 @@ function cfxZones.getZonesWithAttributeNamed(attributeName, testZones)
|
|||||||
end
|
end
|
||||||
return attributZones
|
return attributZones
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- zone volume management
|
-- zone volume management
|
||||||
--
|
--
|
||||||
|
|
||||||
function cfxZones.getZoneVolume(theZone)
|
function cfxZones.getZoneVolume(theZone)
|
||||||
if not theZone then return nil end
|
if not theZone then return nil end
|
||||||
|
|
||||||
if (theZone.isCircle) then
|
if (theZone.isCircle) then
|
||||||
-- create a sphere volume
|
-- create a sphere volume
|
||||||
local p = cfxZones.getPoint(theZone)
|
local p = cfxZones.getPoint(theZone)
|
||||||
@ -844,7 +749,6 @@ function cfxZones.getZoneVolume(theZone)
|
|||||||
upperRight.x = theZone.bounds.ur.x
|
upperRight.x = theZone.bounds.ur.x
|
||||||
upperRight.z = theZone.bounds.ur.z
|
upperRight.z = theZone.bounds.ur.z
|
||||||
upperRight.y = alt -- we go higher
|
upperRight.y = alt -- we go higher
|
||||||
|
|
||||||
-- construct volume
|
-- construct volume
|
||||||
local vol = {
|
local vol = {
|
||||||
id = world.VolumeType.BOX,
|
id = world.VolumeType.BOX,
|
||||||
@ -863,7 +767,6 @@ function dmlZone:getZoneVolume()
|
|||||||
return cfxZones.getZoneVolume(self)
|
return cfxZones.getZoneVolume(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function cfxZones.declutterZone(theZone)
|
function cfxZones.declutterZone(theZone)
|
||||||
if not theZone then return end
|
if not theZone then return end
|
||||||
local theVol = cfxZones.getZoneVolume(theZone)
|
local theVol = cfxZones.getZoneVolume(theZone)
|
||||||
@ -874,7 +777,6 @@ function dmlZone:declutterZone()
|
|||||||
local theVol = cfxZones.getZoneVolume(self)
|
local theVol = cfxZones.getZoneVolume(self)
|
||||||
world.removeJunk(theVol)
|
world.removeJunk(theVol)
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- units / groups in zone
|
-- units / groups in zone
|
||||||
--
|
--
|
||||||
@ -941,7 +843,6 @@ function dmlZone:allStaticsInZone(useOrigin)
|
|||||||
return cfxZones.allStaticsInZone(self, useOrigin)
|
return cfxZones.allStaticsInZone(self, useOrigin)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function cfxZones.groupsOfCoalitionPartiallyInZone(coal, theZone, categ) -- categ is optional
|
function cfxZones.groupsOfCoalitionPartiallyInZone(coal, theZone, categ) -- categ is optional
|
||||||
local groupsInZone = {}
|
local groupsInZone = {}
|
||||||
local allGroups = coalition.getGroups(coal, categ)
|
local allGroups = coalition.getGroups(coal, categ)
|
||||||
@ -992,11 +893,9 @@ end
|
|||||||
function dmlZone:isEntireGroupInZone(aGroup)
|
function dmlZone:isEntireGroupInZone(aGroup)
|
||||||
return cfxZones.isEntireGroupInZone(aGroup, self)
|
return cfxZones.isEntireGroupInZone(aGroup, self)
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Zone Manipulation
|
-- Zone Manipulation
|
||||||
--
|
--
|
||||||
|
|
||||||
function cfxZones.offsetZone(theZone, dx, dz)
|
function cfxZones.offsetZone(theZone, dx, dz)
|
||||||
-- first, update center
|
-- first, update center
|
||||||
theZone.point.x = theZone.point.x + dx
|
theZone.point.x = theZone.point.x + dx
|
||||||
@ -1025,7 +924,6 @@ function dmlZone:offsetZone(dx, dz)
|
|||||||
cfxZones.offsetZone(self, dx, dz)
|
cfxZones.offsetZone(self, dx, dz)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function cfxZones.moveZoneTo(theZone, x, z)
|
function cfxZones.moveZoneTo(theZone, x, z)
|
||||||
local dx = x - theZone.point.x
|
local dx = x - theZone.point.x
|
||||||
local dz = z - theZone.point.z
|
local dz = z - theZone.point.z
|
||||||
@ -1046,7 +944,6 @@ function dmlZone:centerZoneOnUnit(theUnit)
|
|||||||
self:moveZoneTo(thePoint.x, thePoint.z)
|
self:moveZoneTo(thePoint.x, thePoint.z)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function cfxZones.dumpZones(zoneTable)
|
function cfxZones.dumpZones(zoneTable)
|
||||||
if not zoneTable then zoneTable = cfxZones.zones end
|
if not zoneTable then zoneTable = cfxZones.zones end
|
||||||
|
|
||||||
@ -1064,15 +961,12 @@ end
|
|||||||
function cfxZones.keysForTable(theTable)
|
function cfxZones.keysForTable(theTable)
|
||||||
local keyset={}
|
local keyset={}
|
||||||
local n=0
|
local n=0
|
||||||
|
|
||||||
for k,v in pairs(tab) do
|
for k,v in pairs(tab) do
|
||||||
n=n+1
|
n=n+1
|
||||||
keyset[n]=k
|
keyset[n]=k
|
||||||
end
|
end
|
||||||
return keyset
|
return keyset
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- return all zones that have a specific named property
|
-- return all zones that have a specific named property
|
||||||
--
|
--
|
||||||
@ -1091,7 +985,6 @@ function cfxZones.zonesWithProperty(propertyName, searchSet)
|
|||||||
end
|
end
|
||||||
return theZones
|
return theZones
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- return all zones from the zone table that begin with string prefix
|
-- return all zones from the zone table that begin with string prefix
|
||||||
--
|
--
|
||||||
@ -1107,7 +1000,6 @@ function cfxZones.zonesStartingWithName(prefix, searchSet)
|
|||||||
|
|
||||||
return prefixZones
|
return prefixZones
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- return all zones from the zone table that begin with the string or set of strings passed in prefix
|
-- return all zones from the zone table that begin with the string or set of strings passed in prefix
|
||||||
-- if you pass 'true' as second (optional) parameter, it will first look for all zones that begin
|
-- if you pass 'true' as second (optional) parameter, it will first look for all zones that begin
|
||||||
@ -1116,7 +1008,6 @@ end
|
|||||||
function cfxZones.zonesStartingWith(prefix, searchSet, debugging)
|
function cfxZones.zonesStartingWith(prefix, searchSet, debugging)
|
||||||
-- you can force zones by having their name start with "+"
|
-- you can force zones by having their name start with "+"
|
||||||
-- which will force them to return immediately if debugging is true for this call
|
-- which will force them to return immediately if debugging is true for this call
|
||||||
|
|
||||||
if (debugging) then
|
if (debugging) then
|
||||||
local debugZones = cfxZones.zonesStartingWithName("+", searchSet)
|
local debugZones = cfxZones.zonesStartingWithName("+", searchSet)
|
||||||
if not (next(debugZones) == nil) then -- # operator only works on array elements
|
if not (next(debugZones) == nil) then -- # operator only works on array elements
|
||||||
@ -1124,7 +1015,6 @@ function cfxZones.zonesStartingWith(prefix, searchSet, debugging)
|
|||||||
return debugZones
|
return debugZones
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (type(prefix) == "string") then
|
if (type(prefix) == "string") then
|
||||||
return cfxZones.zonesStartingWithName(prefix, searchSet)
|
return cfxZones.zonesStartingWithName(prefix, searchSet)
|
||||||
end
|
end
|
||||||
@ -1139,7 +1029,6 @@ function cfxZones.zonesStartingWith(prefix, searchSet, debugging)
|
|||||||
allZones[zName] = zInfo -- will also replace doublets
|
allZones[zName] = zInfo -- will also replace doublets
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return allZones
|
return allZones
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1158,13 +1047,11 @@ function cfxZones.getZonesContainingString(aString, searchSet)
|
|||||||
resultSet[zName] = zData
|
resultSet[zName] = zData
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end;
|
end;
|
||||||
|
|
||||||
-- filter zones by range to a point. returns indexed set
|
-- filter zones by range to a point. returns indexed set
|
||||||
function cfxZones.getZonesInRange(point, range, theZones)
|
function cfxZones.getZonesInRange(point, range, theZones)
|
||||||
if not theZones then theZones = cfxZones.zones end
|
if not theZones then theZones = cfxZones.zones end
|
||||||
|
|
||||||
local inRangeSet = {}
|
local inRangeSet = {}
|
||||||
for zName, zData in pairs (theZones) do
|
for zName, zData in pairs (theZones) do
|
||||||
if dcsCommon.dist(point, zData.point) < range then
|
if dcsCommon.dist(point, zData.point) < range then
|
||||||
@ -1216,43 +1103,41 @@ function cfxZones.getZoneByIndex(theZones, theIndex)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- place a smoke marker in center of zone, offset by dx, dy
|
-- place a smoke marker in center of zone, offset by dx, dy
|
||||||
function cfxZones.markZoneWithSmoke(theZone, dx, dz, smokeColor, alt)
|
function cfxZones.markZoneWithSmoke(theZone, dx, dz, smokeColor, alt, name)
|
||||||
if not alt then alt = 5 end
|
if not alt then alt = 5 end
|
||||||
local point = cfxZones.getPoint(theZone) --{} -- theZone.point
|
local point = cfxZones.getPoint(theZone) --{} -- theZone.point
|
||||||
point.x = point.x + dx -- getpoint updates and returns copy
|
point.x = point.x + dx -- getpoint updates and returns copy
|
||||||
point.z = point.z + dz
|
point.z = point.z + dz
|
||||||
-- get height at point
|
-- correct height at point
|
||||||
point.y = land.getHeight({x = point.x, y = point.z}) + alt
|
point.y = land.getHeight({x = point.x, y = point.z}) + alt
|
||||||
-- height-correct
|
trigger.action.smoke(point, smokeColor, name)
|
||||||
--local newPoint= {x = point.x, y = land.getHeight({x = point.x, y = point.z}) + 3, z= point.z}
|
|
||||||
trigger.action.smoke(point, smokeColor)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function dmlZone:markZoneWithSmoke(dx, dz, smokeColor, alt)
|
function dmlZone:markZoneWithSmoke(dx, dz, smokeColor, alt, name)
|
||||||
cfxZones.markZoneWithSmoke(self, dx, dz, smokeColor, alt)
|
cfxZones.markZoneWithSmoke(self, dx, dz, smokeColor, alt, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- place a smoke marker in center of zone, offset by radius and degrees
|
-- place a smoke marker in center of zone, offset by radius and degrees
|
||||||
function cfxZones.markZoneWithSmokePolar(theZone, radius, degrees, smokeColor, alt)
|
function cfxZones.markZoneWithSmokePolar(theZone, radius, degrees, smokeColor, alt, name)
|
||||||
local rads = degrees * math.pi / 180
|
local rads = degrees * math.pi / 180
|
||||||
local dx = radius * math.sin(rads)
|
local dx = radius * math.sin(rads)
|
||||||
local dz = radius * math.cos(rads)
|
local dz = radius * math.cos(rads)
|
||||||
cfxZones.markZoneWithSmoke(theZone, dx, dz, smokeColor, alt)
|
cfxZones.markZoneWithSmoke(theZone, dx, dz, smokeColor, alt, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
function dmlZone:markZoneWithSmokePolar(radius, degrees, smokeColor, alt)
|
function dmlZone:markZoneWithSmokePolar(radius, degrees, smokeColor, alt, name)
|
||||||
cfxZones.markZoneWithSmokePolar(self, radius, degrees, smokeColor, alt)
|
cfxZones.markZoneWithSmokePolar(self, radius, degrees, smokeColor, alt, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- place a smoke marker in center of zone, offset by radius and randomized degrees
|
-- place a smoke marker in center of zone, offset by radius and randomized degrees
|
||||||
function cfxZones.markZoneWithSmokePolarRandom(theZone, radius, smokeColor)
|
function cfxZones.markZoneWithSmokePolarRandom(theZone, radius, smokeColor, name)
|
||||||
local degrees = math.random(360)
|
local degrees = math.random(360)
|
||||||
cfxZones.markZoneWithSmokePolar(theZone, radius, degrees, smokeColor)
|
cfxZones.markZoneWithSmokePolar(theZone, radius, degrees, smokeColor, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
function dmlZone:markZoneWithSmokePolarRandom(radius, smokeColor)
|
function dmlZone:markZoneWithSmokePolarRandom(radius, smokeColor, name)
|
||||||
local degrees = math.random(360)
|
local degrees = math.random(360)
|
||||||
self:markZoneWithSmokePolar(radius, degrees, smokeColor)
|
self:markZoneWithSmokePolar(radius, degrees, smokeColor, name)
|
||||||
end
|
end
|
||||||
|
|
||||||
function cfxZones.pointInOneOfZones(thePoint, zoneArray, useOrig)
|
function cfxZones.pointInOneOfZones(thePoint, zoneArray, useOrig)
|
||||||
@ -1264,17 +1149,13 @@ function cfxZones.pointInOneOfZones(thePoint, zoneArray, useOrig)
|
|||||||
return false, 0, 0, nil
|
return false, 0, 0, nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- unitInZone returns true if theUnit is inside the zone
|
-- unitInZone returns true if theUnit is inside the zone
|
||||||
-- the second value returned is the percentage of distance
|
-- the second value returned is the percentage of distance
|
||||||
-- from center to rim, with 100% being entirely in center, 0 = outside
|
-- from center to rim, with 100% being entirely in center, 0 = outside
|
||||||
-- the third value returned is the distance to center
|
-- the third value returned is the distance to center
|
||||||
function cfxZones.pointInZone(thePoint, theZone, useOrig)
|
function cfxZones.pointInZone(thePoint, theZone, useOrig)
|
||||||
|
|
||||||
if not (theZone) then return false, 0, 0 end
|
if not (theZone) then return false, 0, 0 end
|
||||||
|
|
||||||
local pflat = {x = thePoint.x, y = 0, z = thePoint.z}
|
local pflat = {x = thePoint.x, y = 0, z = thePoint.z}
|
||||||
|
|
||||||
local zpoint
|
local zpoint
|
||||||
if useOrig then
|
if useOrig then
|
||||||
zpoint = cfxZones.getDCSOrigin(theZone)
|
zpoint = cfxZones.getDCSOrigin(theZone)
|
||||||
@ -1284,26 +1165,22 @@ function cfxZones.pointInZone(thePoint, theZone, useOrig)
|
|||||||
local ppoint = thePoint -- xyz
|
local ppoint = thePoint -- xyz
|
||||||
local pflat = {x = ppoint.x, y = 0, z = ppoint.z}
|
local pflat = {x = ppoint.x, y = 0, z = ppoint.z}
|
||||||
local dist = dcsCommon.dist(zpoint, pflat)
|
local dist = dcsCommon.dist(zpoint, pflat)
|
||||||
|
|
||||||
if theZone.isCircle then
|
if theZone.isCircle then
|
||||||
if theZone.radius <= 0 then
|
if theZone.radius <= 0 then
|
||||||
return false, 0, 0
|
return false, 0, 0
|
||||||
end
|
end
|
||||||
|
|
||||||
local success = dist < theZone.radius
|
local success = dist < theZone.radius
|
||||||
local percentage = 0
|
local percentage = 0
|
||||||
if (success) then
|
if (success) then
|
||||||
percentage = 1 - dist / theZone.radius
|
percentage = 1 - dist / theZone.radius
|
||||||
end
|
end
|
||||||
return success, percentage, dist
|
return success, percentage, dist
|
||||||
|
|
||||||
elseif theZone.isPoly then
|
elseif theZone.isPoly then
|
||||||
local success = cfxZones.isPointInsidePoly(pflat, theZone.poly)
|
local success = cfxZones.isPointInsidePoly(pflat, theZone.poly)
|
||||||
return success, 0, dist
|
return success, 0, dist
|
||||||
else
|
else
|
||||||
trigger.action.outText("pointInZone: Unknown zone type for " .. theZone.name, 10)
|
trigger.action.outText("pointInZone: Unknown zone type for " .. theZone.name, 10)
|
||||||
end
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1311,7 +1188,6 @@ function dmlZone:pointInZone(thePoint, useOrig)
|
|||||||
return cfxZones.pointInZone(thePoint, self, useOrig)
|
return cfxZones.pointInZone(thePoint, self, useOrig)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function cfxZones.unitInZone(theUnit, theZone)
|
function cfxZones.unitInZone(theUnit, theZone)
|
||||||
if not (theUnit) then return false, 0, 0 end
|
if not (theUnit) then return false, 0, 0 end
|
||||||
if not (theUnit:isExist()) then return false, 0, 0 end
|
if not (theUnit:isExist()) then return false, 0, 0 end
|
||||||
@ -1383,7 +1259,6 @@ end
|
|||||||
function cfxZones.growZone()
|
function cfxZones.growZone()
|
||||||
-- circular zones simply increase radius
|
-- circular zones simply increase radius
|
||||||
-- poly zones: not defined
|
-- poly zones: not defined
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -1394,7 +1269,6 @@ function cfxZones.createGroundUnitsInZoneForCoalition (theCoalition, groupName,
|
|||||||
if not drivable then drivable = false end
|
if not drivable then drivable = false end
|
||||||
-- group name will be taken from zone name and prependend with "G_"
|
-- group name will be taken from zone name and prependend with "G_"
|
||||||
local theGroup = dcsCommon.createGroundGroupWithUnits(groupName, theUnits, theZone.radius, nil, formation, nil, liveries)
|
local theGroup = dcsCommon.createGroundGroupWithUnits(groupName, theUnits, theZone.radius, nil, formation, nil, liveries)
|
||||||
|
|
||||||
theGroup.uncontrollable = false -- just for completeness
|
theGroup.uncontrollable = false -- just for completeness
|
||||||
if drivable then
|
if drivable then
|
||||||
local units = theGroup.units
|
local units = theGroup.units
|
||||||
@ -1402,34 +1276,26 @@ function cfxZones.createGroundUnitsInZoneForCoalition (theCoalition, groupName,
|
|||||||
theUnit.playerCanDrive = drivable
|
theUnit.playerCanDrive = drivable
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- turn the entire formation to heading
|
-- turn the entire formation to heading
|
||||||
if (not heading) then heading = 0 end
|
if (not heading) then heading = 0 end
|
||||||
dcsCommon.rotateGroupData(theGroup, heading) -- currently, group is still at origin, no cx, cy
|
dcsCommon.rotateGroupData(theGroup, heading) -- currently, group is still at origin, no cx, cy
|
||||||
|
|
||||||
|
|
||||||
-- now move the group to center of theZone
|
-- now move the group to center of theZone
|
||||||
dcsCommon.moveGroupDataTo(theGroup,
|
dcsCommon.moveGroupDataTo(theGroup,
|
||||||
theZone.point.x,
|
theZone.point.x,
|
||||||
theZone.point.z) -- watchit: Z!!!
|
theZone.point.z) -- watchit: Z!!!
|
||||||
|
|
||||||
-- create the group in the world and return it
|
-- create the group in the world and return it
|
||||||
-- first we need to translate the coalition to a legal
|
-- first we need to translate the coalition to a legal
|
||||||
-- country. we use UN for neutral, cjtf for red and blue
|
-- country. we use UN for neutral, cjtf for red and blue
|
||||||
local theSideCJTF = dcsCommon.coalition2county(theCoalition)
|
local theSideCJTF = dcsCommon.coalition2county(theCoalition)
|
||||||
-- store cty and cat for later access. DCS doesn't need it, but we may
|
-- store cty and cat for later access. DCS doesn't need it, but we may
|
||||||
|
|
||||||
theGroup.cty = theSideCJTF
|
theGroup.cty = theSideCJTF
|
||||||
theGroup.cat = Group.Category.GROUND
|
theGroup.cat = Group.Category.GROUND
|
||||||
|
|
||||||
-- create a copy of the group data for
|
-- create a copy of the group data for
|
||||||
-- later reference
|
-- later reference
|
||||||
local groupDataCopy = dcsCommon.clone(theGroup)
|
local groupDataCopy = dcsCommon.clone(theGroup)
|
||||||
|
|
||||||
local newGroup = coalition.addGroup(theSideCJTF, Group.Category.GROUND, theGroup)
|
local newGroup = coalition.addGroup(theSideCJTF, Group.Category.GROUND, theGroup)
|
||||||
return newGroup, groupDataCopy
|
return newGroup, groupDataCopy
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- ===============
|
-- ===============
|
||||||
-- FLAG PROCESSING
|
-- FLAG PROCESSING
|
||||||
@ -1456,7 +1322,6 @@ function cfxZones.pulseFlag(theFlag, method, theZone)
|
|||||||
end
|
end
|
||||||
local newVal = 1
|
local newVal = 1
|
||||||
cfxZones.setFlagValue(theFlag, newVal, theZone)
|
cfxZones.setFlagValue(theFlag, newVal, theZone)
|
||||||
|
|
||||||
-- schedule second half of pulse
|
-- schedule second half of pulse
|
||||||
timer.scheduleFunction(cfxZones.unPulseFlag, args, timer.getTime() + delay)
|
timer.scheduleFunction(cfxZones.unPulseFlag, args, timer.getTime() + delay)
|
||||||
end
|
end
|
||||||
@ -1489,7 +1354,6 @@ function cfxZones.evalRemainder(remainder, theZone)
|
|||||||
remainder = string.sub(remainder, 2)
|
remainder = string.sub(remainder, 2)
|
||||||
remainder = dcsCommon.trim(remainder)
|
remainder = dcsCommon.trim(remainder)
|
||||||
end
|
end
|
||||||
|
|
||||||
if esc == "(" and last == ")" and string.len(remainder) > 2 then
|
if esc == "(" and last == ")" and string.len(remainder) > 2 then
|
||||||
-- note: iisues with startswith("(") ???
|
-- note: iisues with startswith("(") ???
|
||||||
remainder = string.sub(remainder, 2, -2)
|
remainder = string.sub(remainder, 2, -2)
|
||||||
@ -1519,7 +1383,6 @@ function cfxZones.doPollFlag(theFlag, method, theZone) -- no OOP equivalent
|
|||||||
if not theZone then
|
if not theZone then
|
||||||
trigger.action.outText("+++zones: nil theZone on pollFlag", 30)
|
trigger.action.outText("+++zones: nil theZone on pollFlag", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
local mt = type(method)
|
local mt = type(method)
|
||||||
if mt == "number" then
|
if mt == "number" then
|
||||||
method = "#" .. method -- convert to immediate
|
method = "#" .. method -- convert to immediate
|
||||||
@ -1528,7 +1391,6 @@ function cfxZones.doPollFlag(theFlag, method, theZone) -- no OOP equivalent
|
|||||||
trigger.action.outText("+++zne: warning: zone <" .. theZone.name .. "> method type <" .. mt .. "> received. Ignoring", 30)
|
trigger.action.outText("+++zne: warning: zone <" .. theZone.name .. "> method type <" .. mt .. "> received. Ignoring", 30)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local val = nil
|
local val = nil
|
||||||
method = method:lower()
|
method = method:lower()
|
||||||
method = dcsCommon.trim(method)
|
method = dcsCommon.trim(method)
|
||||||
@ -1549,7 +1411,6 @@ function cfxZones.doPollFlag(theFlag, method, theZone) -- no OOP equivalent
|
|||||||
return
|
return
|
||||||
else
|
else
|
||||||
end
|
end
|
||||||
|
|
||||||
if dcsCommon.stringStartsWith(method, "#") then
|
if dcsCommon.stringStartsWith(method, "#") then
|
||||||
-- immediate value command. remove # and eval remainder
|
-- immediate value command. remove # and eval remainder
|
||||||
local remainder = dcsCommon.removePrefix(method, "#")
|
local remainder = dcsCommon.removePrefix(method, "#")
|
||||||
@ -1560,30 +1421,19 @@ function cfxZones.doPollFlag(theFlag, method, theZone) -- no OOP equivalent
|
|||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local currVal = cfxZones.getFlagValue(theFlag, theZone)
|
local currVal = cfxZones.getFlagValue(theFlag, theZone)
|
||||||
if method == "inc" or method == "f+1" then
|
if method == "inc" or method == "f+1" then
|
||||||
--trigger.action.setUserFlag(theFlag, currVal + 1)
|
|
||||||
cfxZones.setFlagValue(theFlag, currVal+1, theZone)
|
cfxZones.setFlagValue(theFlag, currVal+1, theZone)
|
||||||
|
|
||||||
elseif method == "dec" or method == "f-1" then
|
elseif method == "dec" or method == "f-1" then
|
||||||
-- trigger.action.setUserFlag(theFlag, currVal - 1)
|
|
||||||
cfxZones.setFlagValue(theFlag, currVal-1, theZone)
|
cfxZones.setFlagValue(theFlag, currVal-1, theZone)
|
||||||
|
|
||||||
elseif method == "off" or method == "f=0" then
|
elseif method == "off" or method == "f=0" then
|
||||||
-- trigger.action.setUserFlag(theFlag, 0)
|
|
||||||
cfxZones.setFlagValue(theFlag, 0, theZone)
|
cfxZones.setFlagValue(theFlag, 0, theZone)
|
||||||
|
|
||||||
elseif method == "flip" or method == "xor" then
|
elseif method == "flip" or method == "xor" then
|
||||||
if currVal ~= 0 then
|
if currVal ~= 0 then
|
||||||
-- trigger.action.setUserFlag(theFlag, 0)
|
|
||||||
cfxZones.setFlagValue(theFlag, 0, theZone)
|
cfxZones.setFlagValue(theFlag, 0, theZone)
|
||||||
|
|
||||||
else
|
else
|
||||||
--trigger.action.setUserFlag(theFlag, 1)
|
|
||||||
cfxZones.setFlagValue(theFlag, 1, theZone)
|
cfxZones.setFlagValue(theFlag, 1, theZone)
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif dcsCommon.stringStartsWith(method, "pulse") then
|
elseif dcsCommon.stringStartsWith(method, "pulse") then
|
||||||
cfxZones.pulseFlag(theFlag, method, theZone)
|
cfxZones.pulseFlag(theFlag, method, theZone)
|
||||||
|
|
||||||
@ -1595,22 +1445,18 @@ function cfxZones.doPollFlag(theFlag, method, theZone) -- no OOP equivalent
|
|||||||
if theZone.verbose then
|
if theZone.verbose then
|
||||||
trigger.action.outText("+++zones: (poll) updating with '+' flag <" .. theFlag .. "> in <" .. theZone.name .. "> by <" .. adder .. "> to <" .. adder + currVal .. ">", 30)
|
trigger.action.outText("+++zones: (poll) updating with '+' flag <" .. theFlag .. "> in <" .. theZone.name .. "> by <" .. adder .. "> to <" .. adder + currVal .. ">", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif dcsCommon.stringStartsWith(method, "-") then
|
elseif dcsCommon.stringStartsWith(method, "-") then
|
||||||
-- we subtract whatever is to the right
|
-- we subtract whatever is to the right
|
||||||
local remainder = dcsCommon.removePrefix(method, "-")
|
local remainder = dcsCommon.removePrefix(method, "-")
|
||||||
local adder = cfxZones.evalRemainder(remainder)
|
local adder = cfxZones.evalRemainder(remainder)
|
||||||
cfxZones.setFlagValue(theFlag, currVal-adder, theZone)
|
cfxZones.setFlagValue(theFlag, currVal-adder, theZone)
|
||||||
|
|
||||||
else
|
else
|
||||||
if method ~= "on" and method ~= "f=1" then
|
if method ~= "on" and method ~= "f=1" then
|
||||||
trigger.action.outText("+++zones: unknown method <" .. method .. "> for flag <" .. theFlag .. "> in zone <" .. theZone.name .. "> - setting to 1", 30)
|
trigger.action.outText("+++zones: unknown method <" .. method .. "> for flag <" .. theFlag .. "> in zone <" .. theZone.name .. "> - setting to 1", 30)
|
||||||
end
|
end
|
||||||
-- default: on.
|
-- default: on.
|
||||||
-- trigger.action.setUserFlag(theFlag, 1)
|
|
||||||
cfxZones.setFlagValue(theFlag, 1, theZone)
|
cfxZones.setFlagValue(theFlag, 1, theZone)
|
||||||
end
|
end
|
||||||
|
|
||||||
if cfxZones.verbose then
|
if cfxZones.verbose then
|
||||||
local newVal = cfxZones.getFlagValue(theFlag, theZone)
|
local newVal = cfxZones.getFlagValue(theFlag, theZone)
|
||||||
trigger.action.outText("+++zones: flag <" .. theFlag .. "> changed from " .. currVal .. " to " .. newVal, 30)
|
trigger.action.outText("+++zones: flag <" .. theFlag .. "> changed from " .. currVal .. " to " .. newVal, 30)
|
||||||
@ -1620,18 +1466,14 @@ end
|
|||||||
function cfxZones.pollFlag(theFlag, method, theZone)
|
function cfxZones.pollFlag(theFlag, method, theZone)
|
||||||
local allFlags = {}
|
local allFlags = {}
|
||||||
if dcsCommon.containsString(theFlag, ",") then
|
if dcsCommon.containsString(theFlag, ",") then
|
||||||
if cfxZones.verbose then
|
if cfxZones.verbose then trigger.action.outText("+++zones: will poll flag set <" .. theFlag .. "> with " .. method, 30) end
|
||||||
trigger.action.outText("+++zones: will poll flag set <" .. theFlag .. "> with " .. method, 30)
|
|
||||||
end
|
|
||||||
allFlags = dcsCommon.splitString(theFlag, ",")
|
allFlags = dcsCommon.splitString(theFlag, ",")
|
||||||
else
|
else
|
||||||
table.insert(allFlags, theFlag)
|
table.insert(allFlags, theFlag)
|
||||||
end
|
end
|
||||||
|
|
||||||
for idx, aFlag in pairs(allFlags) do
|
for idx, aFlag in pairs(allFlags) do
|
||||||
aFlag = dcsCommon.trim(aFlag)
|
aFlag = dcsCommon.trim(aFlag)
|
||||||
-- note: mey require range preprocessing, but that's not
|
-- note: mey require range preprocessing, but that's not a priority
|
||||||
-- a priority
|
|
||||||
cfxZones.doPollFlag(aFlag, method, theZone)
|
cfxZones.doPollFlag(aFlag, method, theZone)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1646,19 +1488,16 @@ function cfxZones.expandFlagName(theFlag, theZone)
|
|||||||
if theZone then
|
if theZone then
|
||||||
zoneName = theZone.name -- for flag wildcards
|
zoneName = theZone.name -- for flag wildcards
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(theFlag) == "number" then
|
if type(theFlag) == "number" then
|
||||||
-- straight number, return
|
-- straight number, return
|
||||||
return theFlag
|
return theFlag
|
||||||
end
|
end
|
||||||
|
|
||||||
-- we assume it's a string now
|
-- we assume it's a string now
|
||||||
theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces
|
theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces
|
||||||
local nFlag = tonumber(theFlag)
|
local nFlag = tonumber(theFlag)
|
||||||
if nFlag then -- a number, legal
|
if nFlag then -- a number, legal
|
||||||
return theFlag
|
return theFlag
|
||||||
end
|
end
|
||||||
|
|
||||||
-- now do wildcard processing. we have alphanumeric
|
-- now do wildcard processing. we have alphanumeric
|
||||||
if dcsCommon.stringStartsWith(theFlag, "*") then
|
if dcsCommon.stringStartsWith(theFlag, "*") then
|
||||||
theFlag = zoneName .. theFlag
|
theFlag = zoneName .. theFlag
|
||||||
@ -1677,9 +1516,7 @@ end
|
|||||||
function cfxZones.setFlagValueMult(theFlag, theValue, theZone)
|
function cfxZones.setFlagValueMult(theFlag, theValue, theZone)
|
||||||
local allFlags = {}
|
local allFlags = {}
|
||||||
if dcsCommon.containsString(theFlag, ",") then
|
if dcsCommon.containsString(theFlag, ",") then
|
||||||
if cfxZones.verbose then
|
if cfxZones.verbose then trigger.action.outText("+++zones: will multi-set flags <" .. theFlag .. "> to " .. theValue, 30)end
|
||||||
trigger.action.outText("+++zones: will multi-set flags <" .. theFlag .. "> to " .. theValue, 30)
|
|
||||||
end
|
|
||||||
allFlags = dcsCommon.splitString(theFlag, ",")
|
allFlags = dcsCommon.splitString(theFlag, ",")
|
||||||
else
|
else
|
||||||
table.insert(allFlags, theFlag)
|
table.insert(allFlags, theFlag)
|
||||||
@ -1687,8 +1524,7 @@ function cfxZones.setFlagValueMult(theFlag, theValue, theZone)
|
|||||||
|
|
||||||
for idx, aFlag in pairs(allFlags) do
|
for idx, aFlag in pairs(allFlags) do
|
||||||
aFlag = dcsCommon.trim(aFlag)
|
aFlag = dcsCommon.trim(aFlag)
|
||||||
-- note: mey require range preprocessing, but that's not
|
-- note: mey require range preprocessing, but that's not a priority
|
||||||
-- a priority
|
|
||||||
cfxZones.doSetFlagValue(aFlag, theValue, theZone)
|
cfxZones.doSetFlagValue(aFlag, theValue, theZone)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1700,7 +1536,6 @@ function cfxZones.doSetFlagValue(theFlag, theValue, theZone)
|
|||||||
else
|
else
|
||||||
zoneName = theZone.name -- for flag wildcards
|
zoneName = theZone.name -- for flag wildcards
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(theFlag) == "number" then
|
if type(theFlag) == "number" then
|
||||||
-- straight set, oldschool ME flag
|
-- straight set, oldschool ME flag
|
||||||
trigger.action.setUserFlag(theFlag, theValue)
|
trigger.action.setUserFlag(theFlag, theValue)
|
||||||
@ -1730,7 +1565,6 @@ function cfxZones.getFlagValue(theFlag, theZone)
|
|||||||
else
|
else
|
||||||
zoneName = theZone.name -- for flag wildcards
|
zoneName = theZone.name -- for flag wildcards
|
||||||
end
|
end
|
||||||
|
|
||||||
if type(theFlag) == "number" then
|
if type(theFlag) == "number" then
|
||||||
-- straight get, ME flag
|
-- straight get, ME flag
|
||||||
return tonumber(trigger.misc.getUserFlag(theFlag))
|
return tonumber(trigger.misc.getUserFlag(theFlag))
|
||||||
@ -1750,7 +1584,7 @@ function cfxZones.getFlagValue(theFlag, theZone)
|
|||||||
|
|
||||||
-- now do wildcard processing. we have alphanumeric
|
-- now do wildcard processing. we have alphanumeric
|
||||||
if dcsCommon.stringStartsWith(theFlag, "*") then
|
if dcsCommon.stringStartsWith(theFlag, "*") then
|
||||||
theFlag = zoneName .. theFlag
|
theFlag = zoneName .. theFlag
|
||||||
end
|
end
|
||||||
return tonumber(trigger.misc.getUserFlag(theFlag))
|
return tonumber(trigger.misc.getUserFlag(theFlag))
|
||||||
end
|
end
|
||||||
@ -2089,7 +1923,8 @@ function cfxZones.drawZone(theZone, lineColor, fillColor, markID)
|
|||||||
if not lineColor then lineColor = {0.8, 0.8, 0.8, 1.0} end
|
if not lineColor then lineColor = {0.8, 0.8, 0.8, 1.0} end
|
||||||
if not fillColor then fillColor = {0.8, 0.8, 0.8, 0.0} end
|
if not fillColor then fillColor = {0.8, 0.8, 0.8, 0.0} end
|
||||||
if not markID then markID = dcsCommon.numberUUID() end
|
if not markID then markID = dcsCommon.numberUUID() end
|
||||||
|
-- trigger.action.outText("drawZone <" .. theZone.name .. "> - L: r=" .. lineColor[1] .. ", g= " .. lineColor[2] .. ", b=" .. lineColor[3] .. ", a=" .. lineColor[4] .. ".", 30)
|
||||||
|
-- trigger.action.outText("and fill F: r=" .. fillColor[1] .. ", g= " .. fillColor[2] .. ", b=" .. fillColor[3] .. ", a=" .. fillColor[4] .. ".", 30)
|
||||||
if theZone.isCircle then
|
if theZone.isCircle then
|
||||||
trigger.action.circleToAll(-1, markID, theZone.point, theZone.radius, lineColor, fillColor, 1, true, "")
|
trigger.action.circleToAll(-1, markID, theZone.point, theZone.radius, lineColor, fillColor, 1, true, "")
|
||||||
else
|
else
|
||||||
@ -2803,6 +2638,8 @@ function cfxZones.getSmokeColorStringFromZoneProperty(theZone, theProperty, defa
|
|||||||
local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, default)
|
local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, default)
|
||||||
s = s:lower()
|
s = s:lower()
|
||||||
s = dcsCommon.trim(s)
|
s = dcsCommon.trim(s)
|
||||||
|
if s == "?" or s == "rnd" or s == "random" then s = tostring(dcsCommon.smallRandom(5) - 1) end
|
||||||
|
|
||||||
-- check numbers
|
-- check numbers
|
||||||
if (s == "0") then return "green" end
|
if (s == "0") then return "green" end
|
||||||
if (s == "1") then return "red" end
|
if (s == "1") then return "red" end
|
||||||
@ -2831,6 +2668,7 @@ function cfxZones.getSmokeColorNumberFromZoneProperty(theZone, theProperty, defa
|
|||||||
|
|
||||||
s = s:lower()
|
s = s:lower()
|
||||||
s = dcsCommon.trim(s)
|
s = dcsCommon.trim(s)
|
||||||
|
if s == "?" or s == "rnd" or s == "random" then s = tostring(dcsCommon.smallRandom(5) - 1) end
|
||||||
-- check numbers
|
-- check numbers
|
||||||
local n = tonumber(s)
|
local n = tonumber(s)
|
||||||
if n then
|
if n then
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cloneZones = {}
|
cloneZones = {}
|
||||||
cloneZones.version = "2.5.2"
|
cloneZones.version = "2.6.0"
|
||||||
cloneZones.verbose = false
|
cloneZones.verbose = false
|
||||||
cloneZones.requiredLibs = {
|
cloneZones.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
@ -61,6 +61,8 @@ cloneZones.respawnOnGroupID = true
|
|||||||
empty! detection through saves (missed hasClones)
|
empty! detection through saves (missed hasClones)
|
||||||
2.5.1 - f? and in? put on notice for depreciation
|
2.5.1 - f? and in? put on notice for depreciation
|
||||||
2.5.2 - removed bug when checking damaged! and no units cloned
|
2.5.2 - removed bug when checking damaged! and no units cloned
|
||||||
|
2.6.0 - maxCycles attribute
|
||||||
|
- increased vorbosity during persistance:loadData
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -332,6 +334,14 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
|||||||
if theZone:hasProperty("health#") then
|
if theZone:hasProperty("health#") then
|
||||||
theZone.health = theZone:getStringFromZoneProperty("health#")
|
theZone.health = theZone:getStringFromZoneProperty("health#")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- maxCycles
|
||||||
|
if theZone:hasProperty("maxCycles") then
|
||||||
|
theZone.maxCycles = theZone:getNumberFromZoneProperty("maxCycles", 99999)
|
||||||
|
end
|
||||||
|
if theZone:hasProperty("maxCycle") then
|
||||||
|
theZone.maxCycles = theZone:getNumberFromZoneProperty("maxCycle", 99999)
|
||||||
|
end
|
||||||
-- we end with clear plate
|
-- we end with clear plate
|
||||||
theZone.lastSize = 0 -- no units here
|
theZone.lastSize = 0 -- no units here
|
||||||
end
|
end
|
||||||
@ -1506,6 +1516,18 @@ function cloneZones.spawnWithCloner(theZone)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- see if we have spawned enough
|
||||||
|
if theZone.maxCycles then
|
||||||
|
if theZone.maxCycles > 0 then -- update and spawn
|
||||||
|
theZone.maxCycles = theZone.maxCycles - 1
|
||||||
|
else -- no spawn
|
||||||
|
if theZone.verbose then
|
||||||
|
trigger.action.outText("+++clnZ: cloner <" .. theZone.name .. "> out of cycles. No clone cycle", 30)
|
||||||
|
end
|
||||||
|
return -- no spawning, out of cycles
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- force spawn with this spawner
|
-- force spawn with this spawner
|
||||||
local templateZone = theZone
|
local templateZone = theZone
|
||||||
if theZone.source then
|
if theZone.source then
|
||||||
@ -1903,6 +1925,9 @@ function cloneZones.saveData()
|
|||||||
local cData = {}
|
local cData = {}
|
||||||
local cName = theCloner.name
|
local cName = theCloner.name
|
||||||
cData.myUniqueCounter = theCloner.myUniqueCounter
|
cData.myUniqueCounter = theCloner.myUniqueCounter
|
||||||
|
if theCloner.maxCycles then
|
||||||
|
cData.maxCycles = theCloner.maxCycles
|
||||||
|
end
|
||||||
cData.oSize = theCloner.oSize
|
cData.oSize = theCloner.oSize
|
||||||
cData.lastSize = theCloner.lastSize
|
cData.lastSize = theCloner.lastSize
|
||||||
-- mySpawns: all groups I'm curently observing for empty!
|
-- mySpawns: all groups I'm curently observing for empty!
|
||||||
@ -1946,7 +1971,8 @@ function cloneZones.loadData()
|
|||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
local gSpawn = 0
|
||||||
|
local uSpawn = 0
|
||||||
-- spawn all units
|
-- spawn all units
|
||||||
local allClones = theData.clones
|
local allClones = theData.clones
|
||||||
for gName, gData in pairs (allClones) do
|
for gName, gData in pairs (allClones) do
|
||||||
@ -1958,12 +1984,15 @@ 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)
|
||||||
|
uSpawn = uSpawn + #theGroup:getUnits()
|
||||||
|
gSpawn = gSpawn + 1
|
||||||
-- turn off AI if disabled
|
-- turn off AI if disabled
|
||||||
if not gData.useAI then
|
if not gData.useAI then
|
||||||
cloneZones.turnOffAI({theGroup})
|
cloneZones.turnOffAI({theGroup})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if cloneZones.verbose then trigger.action.outText("load: loaded <" .. gSpawn .. "> groups, <" .. uSpawn .. "> units total.", 30) end
|
||||||
-- spawn all static objects
|
-- spawn all static objects
|
||||||
local allObjects = theData.objects
|
local allObjects = theData.objects
|
||||||
for oName, oData in pairs(allObjects) do
|
for oName, oData in pairs(allObjects) do
|
||||||
@ -2001,6 +2030,7 @@ function cloneZones.loadData()
|
|||||||
end
|
end
|
||||||
if cData.oSize then theCloner.oSize = cData.oSize end
|
if cData.oSize then theCloner.oSize = cData.oSize end
|
||||||
if cData.lastSize then theCloner.lastSize = cData.lastSize end
|
if cData.lastSize then theCloner.lastSize = cData.lastSize end
|
||||||
|
if cData.maxCycles then theCloner.maxCycles = cData.maxCycles end
|
||||||
|
|
||||||
local mySpawns = {}
|
local mySpawns = {}
|
||||||
for idx, aName in pairs(cData.mySpawns) do
|
for idx, aName in pairs(cData.mySpawns) do
|
||||||
|
|||||||
@ -1,56 +1,16 @@
|
|||||||
csarManager = {}
|
csarManager = {}
|
||||||
csarManager.version = "4.2.1"
|
csarManager.version = "4.3.0"
|
||||||
csarManager.ups = 1
|
csarManager.ups = 1
|
||||||
|
|
||||||
--[[-- VERSION HISTORY
|
--[[-- VERSION HISTORY
|
||||||
|
|
||||||
- 2.3.0 - dmlZones
|
|
||||||
- onRoad attribute for CSAR mission Zones
|
|
||||||
- rndLoc support
|
|
||||||
- triggerMethod support
|
|
||||||
- 2.3.1 - addPrefix option
|
|
||||||
- delay asynch OK (message only)
|
|
||||||
- offset zone on randomized soldier
|
|
||||||
- smokeDist
|
|
||||||
- 2.3.2 - DCS 2.9 getCategory() fix
|
|
||||||
- 3.0.0 - moved mission creation out of update loop into own
|
|
||||||
- removed cfxPlayer dependency
|
|
||||||
- new event manager
|
|
||||||
- no longer single-proccing pilots
|
|
||||||
- can also handle aircraft - isTroopCarrier
|
|
||||||
- 3.1.0 - integration with scribe
|
|
||||||
- expanded internal API: newMissionCB, invoked at addMission
|
|
||||||
- expanded internal API: removedMissionCB
|
|
||||||
- added *rnd as option for csarName (requires "names")
|
|
||||||
- missions are sorted by distance
|
|
||||||
- mission timeLimit range implemented
|
|
||||||
- update handles time limit (pickup only)
|
|
||||||
- inflight status reflects time limit but will not time out
|
|
||||||
- pickupSound option
|
|
||||||
- lostSound option
|
|
||||||
- 3.1.1 - birth clears troopsOnBoard
|
|
||||||
- 3.2.0 - inPopulated csar option
|
|
||||||
- clearance csar attribute
|
|
||||||
- maxTries csar attribute
|
|
||||||
- 3.2.1 - comsRange attribute when mission times out
|
|
||||||
- rescueTypes option in config
|
|
||||||
3.2.2 - reset helicopter weight on birth
|
|
||||||
- cleanup
|
|
||||||
3.2.3 - hardening against *accidental* multi-unit player groups.
|
|
||||||
3.2.4 - pass theZone with missionCreateCB when created from zone
|
|
||||||
3.2.5 - smoke callbacks
|
|
||||||
- useRanks option
|
|
||||||
3.2.6 - inBuiltup analogon to cloner
|
|
||||||
3.2.7 - createCSARForParachutist now supports optional coa (autoCSAR)
|
|
||||||
3.3.0 - persistence support
|
|
||||||
3.4.0 - global timeLimit option in config zone
|
|
||||||
- fixes expiration bug when persisting data
|
|
||||||
4.0.0 - support for mainMenu
|
4.0.0 - support for mainMenu
|
||||||
4.0.1 - increased verbosity
|
4.0.1 - increased verbosity
|
||||||
- fix for Jul-11 2024 DCS bugs
|
- fix for Jul-11 2024 DCS bugs
|
||||||
4.1.0 - support for DCS 2.9.6 dynamic spawns
|
4.1.0 - support for DCS 2.9.6 dynamic spawns
|
||||||
4.2.0 - automatically support twn if present
|
4.2.0 - automatically support twn if present
|
||||||
4.2.1 - added Chinook to csar default set (via common)
|
4.2.1 - added Chinook to csar default set (via common)
|
||||||
|
4.3.0 - pilot's smoke can now extinguish immediately
|
||||||
|
- keepSmoke option
|
||||||
|
|
||||||
INTEGRATES AUTOMATICALLY WITH playerScore
|
INTEGRATES AUTOMATICALLY WITH playerScore
|
||||||
INTEGRATES WITH LIMITED AIRFRAMES
|
INTEGRATES WITH LIMITED AIRFRAMES
|
||||||
@ -549,6 +509,14 @@ function csarManager.heloLanded(theUnit)
|
|||||||
30)
|
30)
|
||||||
didPickup = true;
|
didPickup = true;
|
||||||
|
|
||||||
|
-- handle smoke
|
||||||
|
if csarManager.keepSmoke then
|
||||||
|
-- trigger.action.outText("keeping smokeName <" .. theMission.smokeName .. "> running", 30)
|
||||||
|
else
|
||||||
|
trigger.action.effectSmokeStop(theMission.smokeName)
|
||||||
|
-- trigger.action.outText("smokeName <" .. theMission.smokeName .. "> removed", 30)
|
||||||
|
end
|
||||||
|
|
||||||
local args = {}
|
local args = {}
|
||||||
args.theName = theMission.name
|
args.theName = theMission.name
|
||||||
args.mySide = mySide
|
args.mySide = mySide
|
||||||
@ -1186,18 +1154,19 @@ function csarManager.update() -- every second
|
|||||||
table.insert(csarMission.messagedUnits, uName) -- remember that we messaged them so we don't do again
|
table.insert(csarMission.messagedUnits, uName) -- remember that we messaged them so we don't do again
|
||||||
end
|
end
|
||||||
|
|
||||||
-- also pop smoke if not popped already, or more than 5 minutes ago
|
-- pop smoke if not popped already, or more than 5 minutes ago
|
||||||
if csarManager.useSmoke and (timer.getTime() - csarMission.lastSmokeTime) >= 5 * 60 then
|
if csarManager.useSmoke and
|
||||||
|
(timer.getTime() - csarMission.lastSmokeTime) >= 5 * 60 then
|
||||||
if csarMission.lastSmokeTime < 0 then
|
if csarMission.lastSmokeTime < 0 then
|
||||||
-- this is the first time that this mission pops smoke
|
-- this is the first time that this mission pops smoke
|
||||||
-- trigger.action.outText("***will invoke smoke cb", 30)
|
|
||||||
csarManager.invokeSmokeCallbacks(csarMission, uName)
|
csarManager.invokeSmokeCallbacks(csarMission, uName)
|
||||||
else
|
else
|
||||||
--trigger.action.outText("nope smoke's a dope", 30)
|
--trigger.action.outText("nope smoke's a dope", 30)
|
||||||
end
|
end
|
||||||
local smokePoint = dcsCommon.randomPointOnPerimeter(
|
local smokePoint = dcsCommon.randomPointOnPerimeter(
|
||||||
csarManager.smokeDist, csarMission.zone.point.x, csarMission.zone.point.z)
|
csarManager.smokeDist, csarMission.zone.point.x, csarMission.zone.point.z)
|
||||||
dcsCommon.markPointWithSmoke(smokePoint, csarManager.smokeColor)
|
csarMission.smokeName = dcsCommon.markPointWithSmoke(smokePoint, csarManager.smokeColor) -- returns unique smoke name
|
||||||
|
trigger.action.outText("smokeName <" .. csarMission.smokeName .. "> started", 30)
|
||||||
csarMission.lastSmokeTime = timer.getTime()
|
csarMission.lastSmokeTime = timer.getTime()
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1236,6 +1205,13 @@ function csarManager.update() -- every second
|
|||||||
table.insert(conf.troopsOnBoard, csarMission)
|
table.insert(conf.troopsOnBoard, csarMission)
|
||||||
csarMission.group:destroy() -- will shut up radio as well
|
csarMission.group:destroy() -- will shut up radio as well
|
||||||
csarMission.group = nil -- no more evacuees
|
csarMission.group = nil -- no more evacuees
|
||||||
|
-- turn off smoke?
|
||||||
|
if csarManager.keepSmoke then
|
||||||
|
-- trigger.action.outText("keeping smokeName <" .. csarMission.smokeName .. "> running", 30)
|
||||||
|
else
|
||||||
|
trigger.action.effectSmokeStop(csarMission.smokeName)
|
||||||
|
-- trigger.action.outText("smokeName <" .. csarMission.smokeName .. "> removed", 30)
|
||||||
|
end
|
||||||
needsGC = true -- need filtering missions
|
needsGC = true -- need filtering missions
|
||||||
|
|
||||||
-- now handle weight using cargoSuper
|
-- now handle weight using cargoSuper
|
||||||
@ -1425,8 +1401,7 @@ function csarManager.readCSARZone(theZone)
|
|||||||
theZone.numCrew = 1
|
theZone.numCrew = 1
|
||||||
theZone.csarMapMarker = nil
|
theZone.csarMapMarker = nil
|
||||||
if theZone:hasProperty("timeLimit") then
|
if theZone:hasProperty("timeLimit") then
|
||||||
local tmin, tmax = theZone:getPositiveRangeFromZoneProperty("timeLimit", 1)
|
local tmin, tmax = theZone:getPositiveRangeFromZoneProperty("timeLimit", 1) -- minutes
|
||||||
|
|
||||||
theZone.timeLimit = {tmin, tmax}
|
theZone.timeLimit = {tmin, tmax}
|
||||||
else
|
else
|
||||||
theZone.timeLimit = nil
|
theZone.timeLimit = nil
|
||||||
@ -1572,6 +1547,7 @@ function csarManager.readConfigZone()
|
|||||||
csarManager.ups = theZone:getNumberFromZoneProperty("ups", 1)
|
csarManager.ups = theZone:getNumberFromZoneProperty("ups", 1)
|
||||||
|
|
||||||
csarManager.useSmoke = theZone:getBoolFromZoneProperty("useSmoke", true)
|
csarManager.useSmoke = theZone:getBoolFromZoneProperty("useSmoke", true)
|
||||||
|
csarManager.keepSmoke = theZone:getBoolFromZoneProperty("keepSmoke", false)
|
||||||
csarManager.smokeColor = theZone:getSmokeColorStringFromZoneProperty("smokeColor", "blue")
|
csarManager.smokeColor = theZone:getSmokeColorStringFromZoneProperty("smokeColor", "blue")
|
||||||
csarManager.smokeDist = theZone:getNumberFromZoneProperty("smokeDist", 30)
|
csarManager.smokeDist = theZone:getNumberFromZoneProperty("smokeDist", 30)
|
||||||
csarManager.smokeColor = dcsCommon.smokeColor2Num(csarManager.smokeColor)
|
csarManager.smokeColor = dcsCommon.smokeColor2Num(csarManager.smokeColor)
|
||||||
@ -1807,4 +1783,5 @@ end
|
|||||||
player that they did not survive the transport
|
player that they did not survive the transport
|
||||||
|
|
||||||
- randomize smoke color if smoke color has more than one entries
|
- randomize smoke color if smoke color has more than one entries
|
||||||
|
- ELT freq higher bands?
|
||||||
--]]--
|
--]]--
|
||||||
@ -1,5 +1,5 @@
|
|||||||
dcsCommon = {}
|
dcsCommon = {}
|
||||||
dcsCommon.version = "3.2.0"
|
dcsCommon.version = "3.2.1"
|
||||||
--[[-- VERSION HISTORY
|
--[[-- VERSION HISTORY
|
||||||
3.0.0 - removed bad bug in stringStartsWith, only relevant if caseSensitive is false
|
3.0.0 - removed bad bug in stringStartsWith, only relevant if caseSensitive is false
|
||||||
- point2text new intsOnly option
|
- point2text new intsOnly option
|
||||||
@ -39,6 +39,7 @@ dcsCommon.version = "3.2.0"
|
|||||||
- cfxZones links to processTimeLocWildCards
|
- cfxZones links to processTimeLocWildCards
|
||||||
- new processAtoBWildCards()
|
- new processAtoBWildCards()
|
||||||
- tons of new wildcards like <eleft>
|
- tons of new wildcards like <eleft>
|
||||||
|
3.2.1 - markPointWithSmoke supports names and returns names
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
-- dcsCommon is a library of common lua functions
|
-- dcsCommon is a library of common lua functions
|
||||||
@ -2650,14 +2651,16 @@ end
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function dcsCommon.markPointWithSmoke(p, smokeColor)
|
function dcsCommon.markPointWithSmoke(p, smokeColor, name)
|
||||||
if not smokeColor then smokeColor = 0 end
|
if not smokeColor then smokeColor = 0 end
|
||||||
|
if not name then name = dcsCommon.uuid("dcsCsmoke") end
|
||||||
local x = p.x
|
local x = p.x
|
||||||
local z = p.z -- do NOT change the point directly
|
local z = p.z -- do NOT change the point directly
|
||||||
-- height-correct
|
-- height-correct
|
||||||
local y = land.getHeight({x = x, y = z})
|
local y = land.getHeight({x = x, y = z})
|
||||||
local newPoint= {x = x, y = y + 2, z = z}
|
local newPoint= {x = x, y = y + 2, z = z}
|
||||||
trigger.action.smoke(newPoint, smokeColor)
|
trigger.action.smoke(newPoint, smokeColor, name)
|
||||||
|
return name
|
||||||
end
|
end
|
||||||
|
|
||||||
-- based on buzzer1977's idea, channel is number, eg in 74X, channel is 74, mode is "X"
|
-- based on buzzer1977's idea, channel is number, eg in 74X, channel is 74, mode is "X"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxHeloTroops = {}
|
cfxHeloTroops = {}
|
||||||
cfxHeloTroops.version = "4.2.2"
|
cfxHeloTroops.version = "4.2.3"
|
||||||
cfxHeloTroops.verbose = false
|
cfxHeloTroops.verbose = false
|
||||||
cfxHeloTroops.autoDrop = true
|
cfxHeloTroops.autoDrop = true
|
||||||
cfxHeloTroops.autoPickup = false
|
cfxHeloTroops.autoPickup = false
|
||||||
@ -22,6 +22,8 @@ cfxHeloTroops.requestRange = 500 -- meters
|
|||||||
4.2.1 - increased verbosity
|
4.2.1 - increased verbosity
|
||||||
- also supports 'pickupRang" for reverse-compatibility with manual typo.
|
- also supports 'pickupRang" for reverse-compatibility with manual typo.
|
||||||
4.2.2 - support for attachTo:
|
4.2.2 - support for attachTo:
|
||||||
|
4.2.3 - dropZone supports 'keepWait' attribute
|
||||||
|
- dropZone supports 'setWait' attribute
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
cfxHeloTroops.minTime = 3 -- seconds beween tandings
|
cfxHeloTroops.minTime = 3 -- seconds beween tandings
|
||||||
@ -48,6 +50,8 @@ function cfxHeloTroops.processDropZone(theZone)
|
|||||||
theZone.dropMethod = theZone:getStringFromZoneProperty("dropMethod", "inc")
|
theZone.dropMethod = theZone:getStringFromZoneProperty("dropMethod", "inc")
|
||||||
theZone.dropCoa = theZone:getCoalitionFromZoneProperty("coalition", 0)
|
theZone.dropCoa = theZone:getCoalitionFromZoneProperty("coalition", 0)
|
||||||
theZone.autoDespawn = theZone:getNumberFromZoneProperty("autoDespawn", -1)
|
theZone.autoDespawn = theZone:getNumberFromZoneProperty("autoDespawn", -1)
|
||||||
|
theZone.keepWait = theZone:getBoolFromZoneProperty("keepWait", false)
|
||||||
|
theZone.setWait = theZone:getBoolFromZoneProperty("setWait", false)
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -704,20 +708,47 @@ function cfxHeloTroops.deployTroopsFromHelicopter(conf)
|
|||||||
local moveFormation = conf.troopsOnBoard.moveFormation
|
local moveFormation = conf.troopsOnBoard.moveFormation
|
||||||
local code = conf.troopsOnBoard.code
|
local code = conf.troopsOnBoard.code
|
||||||
local canDrive = conf.troopsOnBoard.canDrive
|
local canDrive = conf.troopsOnBoard.canDrive
|
||||||
|
local theCoalition = theUnit:getGroup():getCoalition() -- my coa
|
||||||
|
|
||||||
if not orders then orders = "guard" end
|
if not orders then orders = "guard" end
|
||||||
orders = string.lower(orders)
|
orders = string.lower(orders)
|
||||||
|
|
||||||
-- order processing: if the orders were pre-pended with "wait-"
|
-- order "wait" processing if not in special drop zone:
|
||||||
-- we now remove that, so after dropping they do what their
|
-- if the orders were pre-pended with "wait-"
|
||||||
-- orders where AFTER being picked up
|
-- remove that, so after dropping they do what their
|
||||||
|
-- orders where AFTER removing "wait"
|
||||||
|
-- or if setWait is true, add it
|
||||||
|
local closestDropZone = cfxZones.getClosestZone(p, cfxHeloTroops.dropzones)
|
||||||
if dcsCommon.stringStartsWith(orders, "wait-") then
|
if dcsCommon.stringStartsWith(orders, "wait-") then
|
||||||
orders = dcsCommon.removePrefix(orders, "wait-")
|
local dropWait = false
|
||||||
trigger.action.outTextForGroup(conf.id, "+++ <" .. conf.troopsOnBoard.name .. "> revoke 'wait' orders, proceed with <".. orders .. ">", 30)
|
if closestDropZone and closestDropZone:pointInZone(p) then
|
||||||
|
if closestDropZone.dropCoa == 0 or closestDropZone.dropCoa == theCoalition then
|
||||||
|
if not closestDropZone.keepWait then dropWait = true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- see if we are in a drop zone
|
||||||
|
if dropWait then
|
||||||
|
orders = dcsCommon.removePrefix(orders, "wait-")
|
||||||
|
trigger.action.outTextForGroup(conf.id, "+++ <" .. conf.troopsOnBoard.name .. "> revoke 'wait' orders, proceed with <".. orders .. ">", 30)
|
||||||
|
else trigger.action.outTextForGroup(conf.id, "+++ <" .. conf.troopsOnBoard.name .. "> keeping 'wait' orders (".. orders .. ")", 30) end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not dcsCommon.stringStartsWith(orders, "wait-") then
|
||||||
|
local setWait = false
|
||||||
|
if closestDropZone and closestDropZone:pointInZone(p) then
|
||||||
|
if closestDropZone.dropCoa == 0 or closestDropZone.dropCoa == theCoalition then
|
||||||
|
if not closestDropZone.setWait then setWait = true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- see if we are in a drop zone
|
||||||
|
if setWait then
|
||||||
|
orders = "wait-" .. orders
|
||||||
|
trigger.action.outTextForGroup(conf.id, "+++ <" .. conf.troopsOnBoard.name .. "> added 'wait' orders: <".. orders .. ">", 30)
|
||||||
|
else trigger.action.outTextForGroup(conf.id, "+++ <" .. conf.troopsOnBoard.name .. "> keeping orders (".. orders .. ")", 30) end
|
||||||
end
|
end
|
||||||
|
|
||||||
local chopperZone = cfxZones.createSimpleZone("choppa", p, 12) -- 12 m radius around choppa
|
local chopperZone = cfxZones.createSimpleZone("choppa", p, 12) -- 12 m radius around choppa
|
||||||
local theCoalition = theUnit:getGroup():getCoalition() -- make it chopper's COALITION
|
|
||||||
local theGroup, theData = cfxZones.createGroundUnitsInZoneForCoalition (
|
local theGroup, theData = cfxZones.createGroundUnitsInZoneForCoalition (
|
||||||
theCoalition,
|
theCoalition,
|
||||||
theName, -- group name, may be tracked
|
theName, -- group name, may be tracked
|
||||||
@ -1173,4 +1204,5 @@ if not cfxHeloTroops.start() then
|
|||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- TODO: weight when loading troops
|
-- TODO: weight when loading troops
|
||||||
|
-- TODO: keepWait for dropzones: troops keep their "wait" orders when dropzone has that tag
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxOwnedZones = {}
|
cfxOwnedZones = {}
|
||||||
cfxOwnedZones.version = "2.4.1"
|
cfxOwnedZones.version = "2.5.0"
|
||||||
cfxOwnedZones.verbose = false
|
cfxOwnedZones.verbose = false
|
||||||
cfxOwnedZones.announcer = true
|
cfxOwnedZones.announcer = true
|
||||||
cfxOwnedZones.name = "cfxOwnedZones"
|
cfxOwnedZones.name = "cfxOwnedZones"
|
||||||
@ -45,6 +45,8 @@ cfxOwnedZones.name = "cfxOwnedZones"
|
|||||||
2.3.1 - restored getNearestOwnedZoneToPoint
|
2.3.1 - restored getNearestOwnedZoneToPoint
|
||||||
2.4.0 - dmlZones masterOwner update
|
2.4.0 - dmlZones masterOwner update
|
||||||
2.4.1 - conquered flag now correctly guarded in loadData()
|
2.4.1 - conquered flag now correctly guarded in loadData()
|
||||||
|
2.5.0 - staggering zone drawing in time during loadData to avoid show-stopping DCS bug in trigger.action.removeMark()
|
||||||
|
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
cfxOwnedZones.requiredLibs = {
|
cfxOwnedZones.requiredLibs = {
|
||||||
@ -125,11 +127,11 @@ function cfxOwnedZones.drawZoneInMap(aZone)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if aZone.title then
|
if aZone.title then
|
||||||
aZone.titleID = aZone:drawText(aZone.title, 18, lineColor, {0, 0, 0, 0})
|
aZone.titleID = aZone:drawText(aZone.title, 18, lineColor, {0, 0, 0, 0}, nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
if aZone.hidden then return end
|
if aZone.hidden then return end
|
||||||
aZone.markID = aZone:drawZone(lineColor, fillColor) -- markID
|
aZone.markID = aZone:drawZone(lineColor, fillColor, nil) -- markID
|
||||||
end
|
end
|
||||||
|
|
||||||
function cfxOwnedZones.getOwnedZoneByName(zName)
|
function cfxOwnedZones.getOwnedZoneByName(zName)
|
||||||
@ -748,7 +750,7 @@ function cfxOwnedZones.loadData()
|
|||||||
local theData = persistence.getSavedDataForModule("cfxOwnedZones")
|
local theData = persistence.getSavedDataForModule("cfxOwnedZones")
|
||||||
if not theData then
|
if not theData then
|
||||||
if cfxOwnedZones.verbose then
|
if cfxOwnedZones.verbose then
|
||||||
trigger.action.outText("owdZ: no save date received, skipping.", 30)
|
trigger.action.outText("owdZ: no save data received, skipping.", 30)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -757,6 +759,9 @@ function cfxOwnedZones.loadData()
|
|||||||
-- flagInfo: module-global flags
|
-- flagInfo: module-global flags
|
||||||
-- attackers: all spawned attackers that we feed to groundTroops
|
-- attackers: all spawned attackers that we feed to groundTroops
|
||||||
local allZoneData = theData.zoneData
|
local allZoneData = theData.zoneData
|
||||||
|
local now = timer.getTime()
|
||||||
|
local delay = now + 0.5
|
||||||
|
|
||||||
for zName, zData in pairs(allZoneData) do
|
for zName, zData in pairs(allZoneData) do
|
||||||
-- access zone
|
-- access zone
|
||||||
local theZone = cfxOwnedZones.getOwnedZoneByName(zName)
|
local theZone = cfxOwnedZones.getOwnedZoneByName(zName)
|
||||||
@ -766,7 +771,10 @@ function cfxOwnedZones.loadData()
|
|||||||
theZone:setFlagValue(theZone.conqueredFlag, zData.conquered)
|
theZone:setFlagValue(theZone.conqueredFlag, zData.conquered)
|
||||||
end
|
end
|
||||||
-- update mark in map
|
-- update mark in map
|
||||||
cfxOwnedZones.drawZoneInMap(theZone)
|
-- does this impact performance?
|
||||||
|
timer.scheduleFunction(cfxOwnedZones.drawZoneInMap, theZone, delay)
|
||||||
|
delay = delay + 0.5
|
||||||
|
-- cfxOwnedZones.drawZoneInMap(theZone)
|
||||||
else
|
else
|
||||||
trigger.action.outText("owdZ: load - data mismatch: cannot find zone <" .. zName .. ">, skipping zone.", 30)
|
trigger.action.outText("owdZ: load - data mismatch: cannot find zone <" .. zName .. ">, skipping zone.", 30)
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
persistence = {}
|
persistence = {}
|
||||||
persistence.version = "3.0.2"
|
persistence.version = "3.1.0"
|
||||||
persistence.ups = 1 -- once every 1 seconds
|
persistence.ups = 1 -- once every 1 seconds
|
||||||
persistence.verbose = false
|
persistence.verbose = false
|
||||||
persistence.active = false
|
persistence.active = false
|
||||||
@ -24,6 +24,8 @@ persistence.requiredLibs = {
|
|||||||
code cleanup
|
code cleanup
|
||||||
3.0.2 - more logging
|
3.0.2 - more logging
|
||||||
vardump to log possible
|
vardump to log possible
|
||||||
|
3.1.0 - validFor attribute -- timed gc
|
||||||
|
- persistence deallocs data after validFor seconds
|
||||||
|
|
||||||
PROVIDES LOAD/SAVE ABILITY TO MODULES
|
PROVIDES LOAD/SAVE ABILITY TO MODULES
|
||||||
PROVIDES STANDALONE/HOSTED SERVER COMPATIBILITY
|
PROVIDES STANDALONE/HOSTED SERVER COMPATIBILITY
|
||||||
@ -74,12 +76,43 @@ end
|
|||||||
--
|
--
|
||||||
-- registered modules call this to get their data
|
-- registered modules call this to get their data
|
||||||
--
|
--
|
||||||
|
function persistence.count(theTable)
|
||||||
|
if not theTable then return 0 end
|
||||||
|
local c = 0
|
||||||
|
for idx, val in pairs(theTable) do
|
||||||
|
c = c + 1
|
||||||
|
end
|
||||||
|
return c
|
||||||
|
end
|
||||||
|
|
||||||
|
function persistence.filter(name) -- debugging
|
||||||
|
--if true then return false end
|
||||||
|
--if name == "WHpersistence" then return true end
|
||||||
|
--if name == "unitPersistence" then return true end
|
||||||
|
--if name == "cfxPlayerScore" then return true end
|
||||||
|
--if name == "cfxSSBClient" then return true end
|
||||||
|
--if name == "cfxSpawnZones" then return true end
|
||||||
|
--if name == "cfxHeloTroops" then return true end
|
||||||
|
--if name == "rndFlags" then return true end
|
||||||
|
--if name == "cfxOwnedZones" then return true end
|
||||||
|
--if name == "cloneZones" then return true end --*
|
||||||
|
--if name == "cfxObjectDestructDetector" then return true end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
function persistence.getSavedDataForModule(name, sharedDataName)
|
function persistence.getSavedDataForModule(name, sharedDataName)
|
||||||
|
-- if persistence.verbose then
|
||||||
|
-- trigger.action.outText("+++persistence: enter load for <" .. name .. ">", 30)
|
||||||
|
-- end
|
||||||
if not persistence.active then return nil end
|
if not persistence.active then return nil end
|
||||||
if not persistence.hasData then return nil end
|
if not persistence.hasData then return nil end
|
||||||
if not persistence.missionData then return end
|
if not persistence.missionData then return nil end
|
||||||
if not sharedDataName then sharedDataName = nil end
|
if not sharedDataName then sharedDataName = nil end
|
||||||
|
|
||||||
|
if persistence.filter(name) then
|
||||||
|
trigger.action.outText("FILTERED persistence for <" .. name .. ">", 30)
|
||||||
|
return nil
|
||||||
|
end
|
||||||
if sharedDataName then
|
if sharedDataName then
|
||||||
-- we read from shared data and only revert to
|
-- we read from shared data and only revert to
|
||||||
-- common if we find nothing
|
-- common if we find nothing
|
||||||
@ -90,6 +123,7 @@ function persistence.getSavedDataForModule(name, sharedDataName)
|
|||||||
local theData = persistence.loadTable(shFile, true)
|
local theData = persistence.loadTable(shFile, true)
|
||||||
if theData then
|
if theData then
|
||||||
if theData[name] then
|
if theData[name] then
|
||||||
|
trigger.action.outText("+++persistence: returning SHARED for <" .. name .. ">", 30)
|
||||||
return theData[name]
|
return theData[name]
|
||||||
end
|
end
|
||||||
if persistence.verbose then
|
if persistence.verbose then
|
||||||
@ -102,6 +136,9 @@ function persistence.getSavedDataForModule(name, sharedDataName)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: returning data (" .. persistence.count(persistence.missionData[name]) .. " records) for <" .. name .. ">", 30)
|
||||||
|
end
|
||||||
return persistence.missionData[name] -- simply get the modules data block
|
return persistence.missionData[name] -- simply get the modules data block
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -580,12 +617,25 @@ function persistence.readConfigZone()
|
|||||||
|
|
||||||
persistence.saveNotification = theZone:getBoolFromZoneProperty("saveNotification", true)
|
persistence.saveNotification = theZone:getBoolFromZoneProperty("saveNotification", true)
|
||||||
|
|
||||||
|
persistence.validFor = theZone:getNumberFromZoneProperty("validFor", 5) -- GC after ... seconds
|
||||||
|
|
||||||
if persistence.verbose then
|
if persistence.verbose then
|
||||||
trigger.action.outText("+++persistence: read config", 30)
|
trigger.action.outText("+++persistence: read config", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function persistence.GC()
|
||||||
|
-- destroy loaded mission data
|
||||||
|
if persistence.missionData then
|
||||||
|
persistence.missionData = nil
|
||||||
|
if persistence.verbose then
|
||||||
|
trigger.action.outText("+++persistence: relinquished loaded data.", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
persistence.hasData = false
|
||||||
|
end
|
||||||
|
|
||||||
function persistence.start()
|
function persistence.start()
|
||||||
-- lib check
|
-- lib check
|
||||||
if not dcsCommon.libCheck then
|
if not dcsCommon.libCheck then
|
||||||
@ -720,7 +770,7 @@ function persistence.start()
|
|||||||
|
|
||||||
-- we now see if we can and need load data
|
-- we now see if we can and need load data
|
||||||
persistence.missionStartDataLoad()
|
persistence.missionStartDataLoad()
|
||||||
|
timer.scheduleFunction(persistence.GC, nil, timer.getTime() + persistence.validFor) -- destroy loaded data after this interval
|
||||||
-- and start updating
|
-- and start updating
|
||||||
persistence.update()
|
persistence.update()
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
pulseFlags = {}
|
pulseFlags = {}
|
||||||
pulseFlags.version = "2.0.3"
|
pulseFlags.version = "2.0.4"
|
||||||
pulseFlags.verbose = false
|
pulseFlags.verbose = false
|
||||||
pulseFlags.requiredLibs = {
|
pulseFlags.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
@ -8,7 +8,7 @@ pulseFlags.requiredLibs = {
|
|||||||
--[[--
|
--[[--
|
||||||
Pulse Flags: DML module to regularly change a flag
|
Pulse Flags: DML module to regularly change a flag
|
||||||
|
|
||||||
Copyright 2022 by Christian Franz and cf/x
|
Copyright 2022-2025 by Christian Franz and cf/x
|
||||||
|
|
||||||
Version History
|
Version History
|
||||||
- 2.0.0 dmlZones / OOP
|
- 2.0.0 dmlZones / OOP
|
||||||
@ -16,6 +16,7 @@ pulseFlags.requiredLibs = {
|
|||||||
- 2.0.1 activateZoneFlag now works correctly
|
- 2.0.1 activateZoneFlag now works correctly
|
||||||
- 2.0.2 fixed scheduledTime bug while persisting
|
- 2.0.2 fixed scheduledTime bug while persisting
|
||||||
- 2.0.3 now setting -1 (infinite) as pulses works correctly
|
- 2.0.3 now setting -1 (infinite) as pulses works correctly
|
||||||
|
- 2.0.4 corrected typo when checking verbosity
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
pulseFlags.pulses = {}
|
pulseFlags.pulses = {}
|
||||||
@ -69,7 +70,7 @@ function pulseFlags.createPulseWithZone(theZone)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if theZone.verbose or pulseFlag.verbose then
|
if theZone.verbose or pulseFlags.verbose then
|
||||||
trigger.action.outText("+++pulF: set pulses in <" .. theZone.name .. "> to <" .. theZone.pulses .. ">", 30)
|
trigger.action.outText("+++pulF: set pulses in <" .. theZone.name .. "> to <" .. theZone.pulses .. ">", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
reaper = {}
|
reaper = {}
|
||||||
reaper.version = "1.2.0"
|
reaper.version = "1.3.0"
|
||||||
reaper.requiredLibs = {
|
reaper.requiredLibs = {
|
||||||
"dcsCommon",
|
"dcsCommon",
|
||||||
"cfxZones",
|
"cfxZones",
|
||||||
@ -21,8 +21,9 @@ VERSION HISTORY
|
|||||||
- completely rewrote scanning method (performance)
|
- completely rewrote scanning method (performance)
|
||||||
- added FAC task
|
- added FAC task
|
||||||
- split task generation from wp generation
|
- split task generation from wp generation
|
||||||
- updated reaper naming, uniqueNames attribute (undocumented)
|
- updated reaper naming, uniqueN ames attribute (undocumented)
|
||||||
1.2.0 - support twn when present
|
1.2.0 - support twn when present
|
||||||
|
1.3.0 - new invisible option for drone zone
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
@ -78,6 +79,7 @@ function reaper.readReaperZone(theZone)
|
|||||||
theZone.cycle = theZone:getStringFromZoneProperty("cycle?", "<none>")
|
theZone.cycle = theZone:getStringFromZoneProperty("cycle?", "<none>")
|
||||||
theZone.cycleVal = theZone:getFlagValue(theZone.cycle)
|
theZone.cycleVal = theZone:getFlagValue(theZone.cycle)
|
||||||
end
|
end
|
||||||
|
theZone.invisible = theZone:getBoolFromZoneProperty("invisible", false)
|
||||||
|
|
||||||
theZone.hasSpawned = false
|
theZone.hasSpawned = false
|
||||||
|
|
||||||
@ -149,7 +151,7 @@ function reaper.spawnForZone(theZone, ack)
|
|||||||
|
|
||||||
-- now create and add waypoints to route
|
-- now create and add waypoints to route
|
||||||
gdata.route.points = {}
|
gdata.route.points = {}
|
||||||
local wp1 = reaper.createInitialWP(left, unit.alt, unit.speed)
|
local wp1 = reaper.createInitialWP(left, unit.alt, unit.speed, theZone.invisible)
|
||||||
gdata.route.points[1] = wp1
|
gdata.route.points[1] = wp1
|
||||||
local wp2 = dcsCommon.createSimpleRoutePointData(right, unit.alt, unit.speed)
|
local wp2 = dcsCommon.createSimpleRoutePointData(right, unit.alt, unit.speed)
|
||||||
gdata.route.points[2] = wp2
|
gdata.route.points[2] = wp2
|
||||||
@ -195,75 +197,89 @@ function reaper.cleanUp(theZone)
|
|||||||
theZone.theSpot = nil
|
theZone.theSpot = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function reaper.createReaperTask(alt, speed, target, theZone)
|
function reaper.createReaperTask(alt, speed, target, theZone, invisible)
|
||||||
local task = {
|
if not invisible then invisible = false end
|
||||||
|
local task = {
|
||||||
["id"] = "ComboTask",
|
["id"] = "ComboTask",
|
||||||
["params"] = {
|
["params"] = {
|
||||||
["tasks"] = {
|
["tasks"] = {
|
||||||
[1] = {
|
[1] = {
|
||||||
["enabled"] = true,
|
|
||||||
["auto"] = true,
|
|
||||||
["id"] = "FAC",
|
|
||||||
["number"] = 1,
|
["number"] = 1,
|
||||||
["params"] =
|
["auto"] = false,
|
||||||
{}, -- end of ["params"]
|
["id"] = "WrappedAction",
|
||||||
|
["name"] = "INV",
|
||||||
|
["enabled"] = true,
|
||||||
|
["params"] = {
|
||||||
|
["action"] = {
|
||||||
|
["id"] = "SetInvisible",
|
||||||
|
["params"] = {
|
||||||
|
["value"] = invisible,
|
||||||
|
}, -- end of ["params"]
|
||||||
|
}, -- end of ["action"]
|
||||||
|
}, -- end of ["params"]
|
||||||
}, -- end of [1]
|
}, -- end of [1]
|
||||||
|
|
||||||
[2] = {
|
[2] = {
|
||||||
["enabled"] = true,
|
["enabled"] = true,
|
||||||
["auto"] = true,
|
["auto"] = true,
|
||||||
["id"] = "WrappedAction",
|
["id"] = "FAC",
|
||||||
["number"] = 2,
|
["number"] = 2,
|
||||||
|
["params"] =
|
||||||
|
{}, -- end of ["params"]
|
||||||
|
}, -- end of [2]
|
||||||
|
[3] = {
|
||||||
|
["enabled"] = true,
|
||||||
|
["auto"] = true,
|
||||||
|
["id"] = "WrappedAction",
|
||||||
|
["number"] = 3,
|
||||||
["params"] = {
|
["params"] = {
|
||||||
["action"] = {
|
["action"] = {
|
||||||
["id"] = "EPLRS",
|
["id"] = "EPLRS",
|
||||||
["params"] = {
|
["params"] = {
|
||||||
["value"] = true,
|
["value"] = true,
|
||||||
["groupId"] = 1,
|
["groupId"] = 1, -- <- looks bad
|
||||||
}, -- end of ["params"]
|
}, -- end of ["params"]
|
||||||
}, -- end of ["action"]
|
}, -- end of ["action"]
|
||||||
}, -- end of ["params"]
|
}, -- end of ["params"]
|
||||||
}, -- end of [2]
|
}, -- end of [3]
|
||||||
[3] = {
|
[4] = {
|
||||||
["enabled"] = true,
|
["enabled"] = true,
|
||||||
["auto"] = false,
|
["auto"] = false,
|
||||||
["id"] = "Orbit",
|
["id"] = "Orbit",
|
||||||
["number"] = 3,
|
["number"] = 4,
|
||||||
["params"] = {
|
["params"] = {
|
||||||
["altitude"] = alt,
|
["altitude"] = alt,
|
||||||
["pattern"] = "Race-Track",
|
["pattern"] = "Race-Track",
|
||||||
["speed"] = speed,
|
["speed"] = speed,
|
||||||
}, -- end of ["params"]
|
}, -- end of ["params"]
|
||||||
}, -- end of [3]
|
}, -- end of [4]
|
||||||
}, -- end of ["tasks"]
|
}, -- end of ["tasks"]
|
||||||
}, -- end of ["params"]
|
}, -- end of ["params"]
|
||||||
} -- end of ["task"]
|
} -- end of ["task"]
|
||||||
if theTarget and theZone then
|
if theTarget and theZone then
|
||||||
-- local gID = theTarget:getGroup():getID()
|
|
||||||
local gID = theTarget:getID() -- NOTE: theTarget is a GROUP!!!!
|
local gID = theTarget:getID() -- NOTE: theTarget is a GROUP!!!!
|
||||||
local task4 = {
|
local task4 = { -- now task5 after we added invisibility
|
||||||
["enabled"] = true,
|
["enabled"] = true,
|
||||||
["auto"] = false,
|
["auto"] = false,
|
||||||
["id"] = "FAC_AttackGroup",
|
["id"] = "FAC_AttackGroup",
|
||||||
["number"] = 4,
|
["number"] = 5,
|
||||||
["params"] =
|
["params"] =
|
||||||
{
|
{
|
||||||
["number"] = 1,
|
["number"] = 5,
|
||||||
["designation"] = "No",
|
["designation"] = "No",
|
||||||
["modulation"] = 0,
|
["modulation"] = 0,
|
||||||
["groupId"] = gID,
|
["groupId"] = gID,
|
||||||
-- ["callname"] = 1,
|
|
||||||
-- ["datalink"] = true,
|
|
||||||
["weaponType"] = 0, -- 9663676414,
|
["weaponType"] = 0, -- 9663676414,
|
||||||
["frequency"] = theZone.freq, -- 133000000,
|
["frequency"] = theZone.freq, -- 133000000,
|
||||||
}, -- end of ["params"]
|
}, -- end of ["params"]
|
||||||
} -- end of [4]
|
} -- end of [5]
|
||||||
task.params.tasks[4] = task4
|
task.params.tasks[5] = task4
|
||||||
end
|
end
|
||||||
return task
|
return task
|
||||||
end
|
end
|
||||||
|
|
||||||
function reaper.createInitialWP(p, alt, speed) -- warning: target must be a GROUP
|
function reaper.createInitialWP(p, alt, speed, invisible) -- warning: target must be a GROUP
|
||||||
|
if not invisible then invisible = false end
|
||||||
local wp = {
|
local wp = {
|
||||||
["alt"] = alt,
|
["alt"] = alt,
|
||||||
["action"] = "Turning Point",
|
["action"] = "Turning Point",
|
||||||
@ -282,7 +298,7 @@ function reaper.createInitialWP(p, alt, speed) -- warning: target must be a GROU
|
|||||||
["formation_template"] = "",
|
["formation_template"] = "",
|
||||||
} -- end of wp
|
} -- end of wp
|
||||||
|
|
||||||
wp.task = reaper.createReaperTask(alt, speed) -- no zone, no target
|
wp.task = reaper.createReaperTask(alt, speed, nil, nil, invisible) -- no zone, no target
|
||||||
return wp
|
return wp
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -319,7 +335,7 @@ function reaper.setTarget(theZone, theTarget, cycled)
|
|||||||
|
|
||||||
-- now make tracking the group the drone's task
|
-- now make tracking the group the drone's task
|
||||||
local theGroup = theTarget:getGroup()
|
local theGroup = theTarget:getGroup()
|
||||||
local theTask = reaper.createReaperTask(theZone.alt, theZone.speed, theGroup, theZone) -- create full FAC task with orbit and group engage
|
local theTask = reaper.createReaperTask(theZone.alt, theZone.speed, theGroup, theZone, theZone.invisible) -- create full FAC task with orbit and group engage
|
||||||
local theController = theZone.theUav:getController()
|
local theController = theZone.theUav:getController()
|
||||||
if not theController then
|
if not theController then
|
||||||
trigger.action.outText("+++Rpr: UAV has no controller, getting group")
|
trigger.action.outText("+++Rpr: UAV has no controller, getting group")
|
||||||
@ -927,4 +943,5 @@ end
|
|||||||
--[[--
|
--[[--
|
||||||
Idea: mobile launch vehicle, zone follows apc around. Can even be hauled along with hook
|
Idea: mobile launch vehicle, zone follows apc around. Can even be hauled along with hook
|
||||||
|
|
||||||
|
todo: make reaper invisible by attribute
|
||||||
--]]--
|
--]]--
|
||||||
|
|||||||
@ -1,108 +1,74 @@
|
|||||||
cfxSmokeZone = {}
|
cfxSmokeZone = {}
|
||||||
cfxSmokeZone.version = "2.0.1"
|
cfxSmokeZone.version = "3.0.0"
|
||||||
cfxSmokeZone.requiredLibs = {
|
cfxSmokeZone.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
"cfxZones", -- Zones, of course
|
"cfxZones", -- Zones, of course
|
||||||
}
|
}
|
||||||
--[[--
|
--[[--
|
||||||
Version History
|
Version History
|
||||||
2.0.0 - clean up
|
3.0.0 - now supports immediate smoke stop
|
||||||
2.0.1 - deprecating "f?"
|
- supports persistence
|
||||||
|
- code cleanup
|
||||||
--]]--
|
--]]--
|
||||||
cfxSmokeZone.smokeZones = {}
|
cfxSmokeZone.smokeZones = {}
|
||||||
cfxSmokeZone.updateDelay = 5 * 60 -- every 5 minutes
|
cfxSmokeZone.updateDelay = 5 * 60 -- every 5 minutes
|
||||||
|
|
||||||
function cfxSmokeZone.processSmokeZone(aZone)
|
function cfxSmokeZone.processSmokeZone(aZone)
|
||||||
local rawVal = aZone:getStringFromZoneProperty("smoke", "green")
|
aZone.smokeColor = aZone:getSmokeColorNumberFromZoneProperty("smoke", "green")--theColor
|
||||||
rawVal = rawVal:lower()
|
|
||||||
local theColor = 0
|
|
||||||
if rawVal == "red" or rawVal == "1" then theColor = 1 end
|
|
||||||
if rawVal == "white" or rawVal == "2" then theColor = 2 end
|
|
||||||
if rawVal == "orange" or rawVal == "3" then theColor = 3 end
|
|
||||||
if rawVal == "blue" or rawVal == "4" then theColor = 4 end
|
|
||||||
if rawVal == "?" or rawVal == "random" or rawVal == "rnd" then
|
|
||||||
theColor = dcsCommon.smallRandom(5) - 1
|
|
||||||
end
|
|
||||||
|
|
||||||
aZone.smokeColor = theColor
|
|
||||||
aZone.smokeAlt = aZone:getNumberFromZoneProperty("altitude", 1)
|
aZone.smokeAlt = aZone:getNumberFromZoneProperty("altitude", 1)
|
||||||
|
aZone.smokeName = aZone.name .. "-s-" .. dcsCommon.numberUUID()
|
||||||
if aZone:hasProperty("alt") then
|
if aZone:hasProperty("alt") then
|
||||||
aZone.smokeAlt = aZone:getNumberFromZoneProperty("alt", 1)
|
aZone.smokeAlt = aZone:getNumberFromZoneProperty("alt", 1)
|
||||||
elseif aZone:hasProperty("agl") then
|
elseif aZone:hasProperty("agl") then
|
||||||
aZone.smokeAlt = aZone:getNumberFromZoneProperty("agl", 1)
|
aZone.smokeAlt = aZone:getNumberFromZoneProperty("agl", 1)
|
||||||
end
|
end
|
||||||
|
aZone.paused = aZone:getBoolFromZoneProperty("paused", false)
|
||||||
-- paused
|
aZone.onFlag = aZone:getStringFromZoneProperty("startSmoke?", "none")
|
||||||
aZone.paused = aZone:getBoolFromZoneProperty("paused", false)
|
|
||||||
|
|
||||||
if aZone:hasProperty("f?") then
|
|
||||||
aZone.onFlag = aZone:getStringFromZoneProperty("f?", "*<none>")
|
|
||||||
trigger.action.outText("+++smokeZones: WARNING: smoke zone <" .. aZone.name .. "> uses deprecated attribute 'f?' - use 'startSmoke?' instead.", 30)
|
|
||||||
elseif aZone:hasProperty("startSmoke?") then
|
|
||||||
aZone.onFlag = aZone:getStringFromZoneProperty("startSmoke?", "none")
|
|
||||||
end
|
|
||||||
|
|
||||||
if aZone.onFlag then
|
if aZone.onFlag then
|
||||||
aZone.onFlagVal = aZone:getFlagValue(aZone.onFlag) -- save last value
|
aZone.onFlagVal = aZone:getFlagValue(aZone.onFlag) -- save last value
|
||||||
end
|
end
|
||||||
|
|
||||||
if aZone:hasProperty("stopSmoke?") then
|
if aZone:hasProperty("stopSmoke?") then
|
||||||
aZone.smkStopFlag = aZone:getStringFromZoneProperty("stopSmoke?", "<none>")
|
aZone.smkStopFlag = aZone:getStringFromZoneProperty("stopSmoke?", "<none>")
|
||||||
aZone.smkLastStopFlag = aZone:getFlagValue(aZone.smkStopFlag)
|
aZone.smkLastStopFlag = aZone:getFlagValue(aZone.smkStopFlag)
|
||||||
end
|
end
|
||||||
|
|
||||||
aZone.smokeTriggerMethod = aZone:getStringFromZoneProperty( "triggerMethod", "change")
|
aZone.smokeTriggerMethod = aZone:getStringFromZoneProperty( "triggerMethod", "change")
|
||||||
|
|
||||||
if aZone:hasProperty("smokeTriggerMethod") then
|
if aZone:hasProperty("smokeTriggerMethod") then
|
||||||
aZone.smokeTriggerMethod = aZone:getStringFromZoneProperty( "smokeTriggerMethod", "change")
|
aZone.smokeTriggerMethod = aZone:getStringFromZoneProperty( "smokeTriggerMethod", "change")
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function cfxSmokeZone.addSmokeZone(aZone)
|
function cfxSmokeZone.addSmokeZone(aZone)
|
||||||
table.insert(cfxSmokeZone.smokeZones, aZone)
|
table.insert(cfxSmokeZone.smokeZones, aZone)
|
||||||
end
|
end
|
||||||
|
|
||||||
function cfxSmokeZone.addSmokeZoneWithColor(aZone, aColor, anAltitude, paused, onFlag)
|
function cfxSmokeZone.getSmokeZoneNamed(aName)
|
||||||
if not aColor then aColor = 0 end -- default green
|
if not aName then return end
|
||||||
if not anAltitude then anAltitude = 5 end
|
local aName = string.upper(aName)
|
||||||
if not aZone then return end
|
for idx, theZone in pairs(cfxSmokeZone.smokeZones) do
|
||||||
if not paused then paused = false end
|
if theZone.name == aName then return theZone end
|
||||||
|
end
|
||||||
aZone.smokeColor = aColor
|
return nil
|
||||||
aZone.smokeAlt = anAltitude
|
|
||||||
aZone.paused = paused
|
|
||||||
|
|
||||||
if onFlag then
|
|
||||||
aZone.onFlag = onFlag
|
|
||||||
aZone.onFlagVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- trigger.misc.getUserFlag(onFlag)
|
|
||||||
end
|
|
||||||
|
|
||||||
cfxSmokeZone.addSmokeZone(aZone) -- add to update loop
|
|
||||||
if not paused then
|
|
||||||
cfxSmokeZone.startSmoke(aZone)
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function cfxSmokeZone.startSmoke(aZone)
|
function cfxSmokeZone.startSmoke(aZone)
|
||||||
if type(aZone) == "string" then
|
|
||||||
aZone = cfxZones.getZoneByName(aZone)
|
|
||||||
end
|
|
||||||
if not aZone then return end
|
if not aZone then return end
|
||||||
if not aZone.smokeColor then return end
|
if not aZone.smokeColor then return end
|
||||||
|
-- remove old smoke if running
|
||||||
|
if cfxSmokeZone.verbose or aZone.verbose then trigger.action.outText("+++smk: starting zone <" .. aZone.name .. "> smoke with name <" .. aZone.smokeName .. ">", 30) end
|
||||||
|
trigger.action.effectSmokeStop(aZone.smokeName)
|
||||||
aZone.paused = false
|
aZone.paused = false
|
||||||
cfxZones.markZoneWithSmoke(aZone, 0, 0, aZone.smokeColor, aZone.smokeAlt)
|
aZone:markZoneWithSmoke(0, 0, aZone.smokeColor, aZone.smokeAlt, aZone.smokeName)
|
||||||
end
|
end
|
||||||
|
|
||||||
function cfxSmokeZone.removeSmokeZone(aZone)
|
function cfxSmokeZone.stopSmoke(aZone)
|
||||||
if type(aZone) == "string" then
|
|
||||||
aZone = cfxZones.getZoneByName(aZone)
|
|
||||||
end
|
|
||||||
if not aZone then return end
|
if not aZone then return end
|
||||||
|
if cfxSmokeZone.verbose or aZone.verbose then trigger.action.outText("+++smk: ENDING zone <" .. aZone.name .. ">'s smoke with name <" .. aZone.smokeName .. ">", 30) end
|
||||||
-- now create new table
|
trigger.action.effectSmokeStop(aZone.smokeName)
|
||||||
|
aZone.paused = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function cfxSmokeZone.removeSmokeZone(aZone)
|
||||||
|
if not aZone then return end
|
||||||
local filtered = {}
|
local filtered = {}
|
||||||
for idx, theZone in pairs(cfxSmokeZone.smokeZones) do
|
for idx, theZone in pairs(cfxSmokeZone.smokeZones) do
|
||||||
if theZone ~= aZone then
|
if theZone ~= aZone then
|
||||||
@ -112,12 +78,9 @@ function cfxSmokeZone.removeSmokeZone(aZone)
|
|||||||
cfxSmokeZone.smokeZones = filtered
|
cfxSmokeZone.smokeZones = filtered
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function cfxSmokeZone.update()
|
function cfxSmokeZone.update()
|
||||||
-- call me in a couple of minutes to 'rekindle'
|
-- 'rekindle' all smoke after 5 mins
|
||||||
timer.scheduleFunction(cfxSmokeZone.update, {}, timer.getTime() + cfxSmokeZone.updateDelay)
|
timer.scheduleFunction(cfxSmokeZone.update, {}, timer.getTime() + cfxSmokeZone.updateDelay)
|
||||||
|
|
||||||
-- re-smoke all zones after delay
|
|
||||||
for idx, aZone in pairs(cfxSmokeZone.smokeZones) do
|
for idx, aZone in pairs(cfxSmokeZone.smokeZones) do
|
||||||
if not aZone.paused and aZone.smokeColor then
|
if not aZone.paused and aZone.smokeColor then
|
||||||
cfxSmokeZone.startSmoke(aZone)
|
cfxSmokeZone.startSmoke(aZone)
|
||||||
@ -125,52 +88,72 @@ function cfxSmokeZone.update()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
function cfxSmokeZone.checkFlags()
|
function cfxSmokeZone.checkFlags()
|
||||||
timer.scheduleFunction(cfxSmokeZone.checkFlags, {}, timer.getTime() + 1) -- every second
|
timer.scheduleFunction(cfxSmokeZone.checkFlags, {}, timer.getTime() + 1) -- every second
|
||||||
for idx, aZone in pairs(cfxSmokeZone.smokeZones) do
|
for idx, aZone in pairs(cfxSmokeZone.smokeZones) do
|
||||||
|
|
||||||
if aZone.paused and aZone.onFlagVal then
|
if aZone.paused and aZone.onFlagVal then
|
||||||
-- see if this changed
|
-- see if this changed
|
||||||
if cfxZones.testZoneFlag(aZone, aZone.onFlag, aZone.smokeTriggerMethod, "onFlagVal") then
|
if cfxZones.testZoneFlag(aZone, aZone.onFlag, aZone.smokeTriggerMethod, "onFlagVal") then
|
||||||
cfxSmokeZone.startSmoke(aZone)
|
cfxSmokeZone.startSmoke(aZone)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if aZone.smkStopFlag then
|
if aZone.smkStopFlag then
|
||||||
if cfxZones.testZoneFlag(aZone, aZone.smkStopFlag, aZone.smokeTriggerMethod, "smkLastStopFlag") then
|
if cfxZones.testZoneFlag(aZone, aZone.smkStopFlag, aZone.smokeTriggerMethod, "smkLastStopFlag") then
|
||||||
aZone.paused = true -- will no longer re-smoke on update
|
cfxSmokeZone.stopSmoke(aZone)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function cfxSmokeZone.start()
|
function cfxSmokeZone.saveData()
|
||||||
if not dcsCommon.libCheck("cfx Smoke Zones", cfxSmokeZone.requiredLibs) then
|
local theData = {}
|
||||||
return false
|
for idx, theZone in pairs(cfxSmokeZone.smokeZones) do
|
||||||
|
local entry = {}
|
||||||
|
entry.paused = theZone.paused
|
||||||
|
theData[theZone.name] = entry
|
||||||
|
end
|
||||||
|
-- save current log. simple clone
|
||||||
|
return theData, cfxSmokeZone.sharedData -- second val only if shared
|
||||||
|
end
|
||||||
|
|
||||||
|
function cfxSmokeZone.loadData()
|
||||||
|
if not persistence then return end
|
||||||
|
local theData = persistence.getSavedDataForModule("smokeZones", cfxSmokeZone.sharedData)
|
||||||
|
if not theData then
|
||||||
|
if cfxSmokeZone.verbose then trigger.action.outText("+++smk: no save date received, skipping.", 30) end
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
for name, entry in pairs(theData) do
|
||||||
-- collect all zones with 'smoke' attribute
|
local theZone = cfxSmokeZone.getSmokeZoneNamed(name)
|
||||||
|
if theZone then
|
||||||
|
theZone.paused = entry.paused
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function cfxSmokeZone.start()
|
||||||
|
if not dcsCommon.libCheck("cfx Smoke Zones", cfxSmokeZone.requiredLibs) then return false end
|
||||||
local attrZones = cfxZones.getZonesWithAttributeNamed("smoke")
|
local attrZones = cfxZones.getZonesWithAttributeNamed("smoke")
|
||||||
for k, aZone in pairs(attrZones) do
|
for k, aZone in pairs(attrZones) do
|
||||||
cfxSmokeZone.processSmokeZone(aZone)
|
cfxSmokeZone.processSmokeZone(aZone)
|
||||||
cfxSmokeZone.addSmokeZone(aZone)
|
cfxSmokeZone.addSmokeZone(aZone)
|
||||||
|
end
|
||||||
|
if persistence then -- sign up for persistence
|
||||||
|
callbacks = {}
|
||||||
|
callbacks.persistData = cfxSmokeZone.saveData
|
||||||
|
persistence.registerModule("smokeZones", callbacks)
|
||||||
|
-- now load my data
|
||||||
|
persistence.loadData() -- will start with update
|
||||||
end
|
end
|
||||||
|
-- start update and checkflag loops
|
||||||
-- start update loop
|
|
||||||
cfxSmokeZone.update() -- also starts all unpaused
|
cfxSmokeZone.update() -- also starts all unpaused
|
||||||
|
|
||||||
-- start check loop in one second
|
|
||||||
timer.scheduleFunction(cfxSmokeZone.checkFlags, {}, timer.getTime() + 1)
|
timer.scheduleFunction(cfxSmokeZone.checkFlags, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
-- say hi
|
|
||||||
|
|
||||||
trigger.action.outText("cfx smoke zones v" .. cfxSmokeZone.version .. " started.", 30)
|
trigger.action.outText("cfx smoke zones v" .. cfxSmokeZone.version .. " started.", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- let's go
|
-- let's go
|
||||||
if not cfxSmokeZone.start() then
|
if not cfxSmokeZone.start() then
|
||||||
trigger.action.outText("cf/x Smoke Zones aborted: missing libraries", 30)
|
trigger.action.outText("cf/x Smoke Zones failed to start", 30)
|
||||||
cfxSmokeZone = nil
|
cfxSmokeZone = nil
|
||||||
end
|
end
|
||||||
Binary file not shown.
Binary file not shown.
BIN
tutorial & demo missions/demo - colored smoke switcher.miz
Normal file
BIN
tutorial & demo missions/demo - colored smoke switcher.miz
Normal file
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user