Version 1.1.10

Quad Zones improvements
Semaphore stubs
This commit is contained in:
Christian Franz 2022-11-24 09:27:10 +01:00
parent 8f225cc30a
commit 3de20ed5f1
8 changed files with 229 additions and 58 deletions

Binary file not shown.

View File

@ -1,5 +1,5 @@
cfxOwnedZones = {} cfxOwnedZones = {}
cfxOwnedZones.version = "1.2.2" cfxOwnedZones.version = "1.2.3"
cfxOwnedZones.verbose = false cfxOwnedZones.verbose = false
cfxOwnedZones.announcer = true cfxOwnedZones.announcer = true
cfxOwnedZones.name = "cfxOwnedZones" cfxOwnedZones.name = "cfxOwnedZones"
@ -47,6 +47,7 @@ cfxOwnedZones.name = "cfxOwnedZones"
- no cfxGroundTroop bug (no delay) - no cfxGroundTroop bug (no delay)
1.2.1 - fix in load to correctly re-establish all attackers for subsequent save 1.2.1 - fix in load to correctly re-establish all attackers for subsequent save
1.2.2 - redCap! and blueCap! 1.2.2 - redCap! and blueCap!
1.2.3 - fix for persistence bug when not using conquered flag
--]]-- --]]--
@ -901,7 +902,9 @@ function cfxOwnedZones.saveData()
zoneData.defenderData = dcsCommon.clone(theZone.defenderData) zoneData.defenderData = dcsCommon.clone(theZone.defenderData)
dcsCommon.synchGroupData(zoneData.defenderData) dcsCommon.synchGroupData(zoneData.defenderData)
end end
zoneData.conquered = cfxZones.getFlagValue(theZone.conqueredFlag, theZone) if theZone.conqueredFlag then
zoneData.conquered = cfxZones.getFlagValue(theZone.conqueredFlag, theZone)
end
zoneData.owner = theZone.owner zoneData.owner = theZone.owner
zoneData.state = theZone.state -- will prevent immediate spawn zoneData.state = theZone.state -- will prevent immediate spawn
-- since new zones are spawned with 'init' -- since new zones are spawned with 'init'
@ -972,7 +975,9 @@ function cfxOwnedZones.loadData()
end end
theZone.owner = zData.owner theZone.owner = zData.owner
theZone.state = zData.state theZone.state = zData.state
cfxZones.setFlagValue(theZone.conqueredFlag, zData.conquered, theZone) if zData.conquered then
cfxZones.setFlagValue(theZone.conqueredFlag, zData.conquered, theZone)
end
-- update mark in map -- update mark in map
cfxOwnedZones.drawZoneInMap(theZone) cfxOwnedZones.drawZoneInMap(theZone)
else else

View File

@ -1,5 +1,5 @@
cfxZones = {} cfxZones = {}
cfxZones.version = "2.9.1" cfxZones.version = "2.9.2"
-- 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
@ -109,6 +109,11 @@ cfxZones.version = "2.9.1"
- 2.9.1 - new evalRemainder() - 2.9.1 - new evalRemainder()
- pollFlag supports +/- for immediate numbers, flags, number flags in parantheses - pollFlag supports +/- for immediate numbers, flags, number flags in parantheses
- stronger guards in hasProperty - stronger guards in hasProperty
- 2.9.2 - new createRandomPointInPolyZone()
- createRandomZoneInZone uses createRandomPointInPolyZone
- new createRandomPointInZone()
- new randomPointInZone()
--]]-- --]]--
cfxZones.verbose = false cfxZones.verbose = false
@ -207,7 +212,7 @@ function cfxZones.readFromDCS(clearfirst)
local upperName = newZone.name:upper() local upperName = newZone.name:upper()
-- location as 'point' -- location as 'point'
-- WARNING: zones locs are 2D (x,y) pairs, whily 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
-- altitude (they are an infinite cylinder) this works. Remember to -- altitude (they are an infinite cylinder) this works. Remember to
-- drop y from zone calculations to see if inside. -- drop y from zone calculations to see if inside.
@ -229,10 +234,12 @@ function cfxZones.readFromDCS(clearfirst)
elseif zoneType == 2 then elseif zoneType == 2 then
-- polyZone -- polyZone
newZone.isPoly = true newZone.isPoly = true
newZone.radius = dcsZone.radius -- radius is still written in DCS, may change later newZone.radius = dcsZone.radius -- radius is still written in DCS, may change later. The radius has no meaning and is the last radius written before zone changed to poly.
-- note that newZone.point is only inside the tone for
-- convex polys, and DML only correctly works with convex polys
-- now transfer all point in the poly -- now transfer all point in the poly
-- note: DCS in 2.7 misspells vertices as 'verticies' -- note: DCS in 2.7 misspells vertices as 'verticies'
-- correct vor this -- correct for this
local verts = {} local verts = {}
if dcsZone.verticies then verts = dcsZone.verticies if dcsZone.verticies then verts = dcsZone.verticies
else else
@ -242,7 +249,7 @@ function cfxZones.readFromDCS(clearfirst)
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)
newZone.poly[v] = polyPoint newZone.poly[v] = polyPoint
end end
else else
@ -290,15 +297,18 @@ function cfxZones.calculateZoneBounds(theZone)
local lr = cfxZones.createPointFromPoint(poly[1]) local lr = cfxZones.createPointFromPoint(poly[1])
local ul = cfxZones.createPointFromPoint(poly[1]) local ul = cfxZones.createPointFromPoint(poly[1])
local ur = cfxZones.createPointFromPoint(poly[1]) local ur = cfxZones.createPointFromPoint(poly[1])
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
for v=2, #poly do for v=2, #poly do
local vertex = poly[v] local vertex = poly[v]
if (vertex.x < ll.x) then ll.x = vertex.x; ul.x = vertex.x end if (vertex.x < ll.x) then ll.x = vertex.x; ul.x = vertex.x end
if (vertex.x > lr.x) then lr.x = vertex.x; ur.x = vertex.x end if (vertex.x > lr.x) then lr.x = vertex.x; ur.x = vertex.x end
if (vertex.z < ul.z) then ul.z = vertex.z; ur.z = vertex.z end if (vertex.z < ul.z) then ul.z = vertex.z; ur.z = vertex.z end
if (vertex.z > ll.z) then ll.z = vertex.z; lr.z = vertex.z end if (vertex.z > ll.z) then ll.z = vertex.z; lr.z = vertex.z end
local dp = dcsCommon.dist(theZone.point, vertex)
if dp > pRad then pRad = dp end -- find largst distance to vertex
end end
-- now keep the new point references -- now keep the new point references
@ -307,6 +317,9 @@ function cfxZones.calculateZoneBounds(theZone)
bounds.lr = lr bounds.lr = lr
bounds.ul = ul bounds.ul = ul
bounds.ur = ur bounds.ur = ur
-- store pRad
theZone.pRad = pRad -- not sure we'll ever need that, but at least we have it
-- trigger.action.outText("+++Zones: poly zone <" .. theZone.name .. "> has pRad = " .. pRad, 30) -- remember to remove me
else else
-- huston, we have a problem -- huston, we have a problem
if cfxZones.verbose then if cfxZones.verbose then
@ -351,11 +364,82 @@ end
function cfxZones.createRandomPointInsideBounds(bounds) function cfxZones.createRandomPointInsideBounds(bounds)
-- 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)
local z = math.random(bounds.ll.z, ur.z) local z = math.random(bounds.ll.z, ur.z)
return cfxZones.createPoint(x, 0, z) return cfxZones.createPoint(x, 0, z)
end end
function cfxZones.createRandomPointInZone(theZone)
if not theZone then return nil end
if theZone.isPoly then
local loc, dx, dy = cfxZones.createRandomPointInPolyZone(theZone)
return loc, dx, dy
else
local loc, dx, dy = cfxZones.createRandomPointInCircleZone(theZone)
return loc, dx, dy
end
end
function cfxZones.randomPointInZone(theZone)
local loc, dx, dy = cfxZones.createRandomPointInZone(theZone)
return loc, dx, dy
end
function cfxZones.createRandomPointInCircleZone(theZone)
if not theZone.isCircle then
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}
end
-- ok, let's first create a random percentage value for the new radius
-- now lets get a random degree
local degrees = math.random() * 2 * 3.14152 -- radiants.
local r = theZone.radius * math.random()
local p = cfxZones.getPoint(theZone) -- force update of zone if linked
local dx = r * math.cos(degrees)
local dz = r * math.sin(degrees)
local px = p.x + dx -- r * math.cos(degrees)
local pz = p.z + dz -- r * math.sin(degrees)
return {x=px, y=0, z = pz}, dx, dz -- returns loc and offsets to theZone.point
end
function cfxZones.createRandomPointInPolyZone(theZone)
if not theZone.isPoly then
trigger.action.outText("+++Zones: warning - createRandomPointInPolyZone called for non-poly zone <" .. theZone.name .. ">", 30)
return cfxZones.createPoint(theZone.point.x, 0, theZone.point.z)
end
-- force update of all points
local p = cfxZones.getPoint(theZone)
-- point in convex poly: choose two different lines from that polygon
local lineIdxA = dcsCommon.smallRandom(#theZone.poly)
repeat lineIdxB = dcsCommon.smallRandom(#theZone.poly) until (lineIdxA ~= lineIdxB)
-- we now have two different lines. pick a random point on each.
-- we use lerp to pick any point between a and b
local a = theZone.poly[lineIdxA]
lineIdxA = lineIdxA + 1 -- get next point in poly and wrap around
if lineIdxA > #theZone.poly then lineIdxA = 1 end
local b = theZone.poly[lineIdxA]
local randompercent = math.random()
local sourceA = dcsCommon.vLerp (a, b, randompercent)
-- now get point on second line
a = theZone.poly[lineIdxB]
lineIdxB = lineIdxB + 1 -- get next point in poly and wrap around
if lineIdxB > #theZone.poly then lineIdxB = 1 end
b = theZone.poly[lineIdxB]
randompercent = math.random()
local sourceB = dcsCommon.vLerp (a, b, randompercent)
-- now take a random point on that line that entirely
-- runs through the poly
randompercent = math.random()
local polyPoint = dcsCommon.vLerp (sourceA, sourceB, randompercent)
return polyPoint, polyPoint.x - p.x, polyPoint.z - p.z -- return loc, dx, dz
end
function cfxZones.addZoneToManagedZones(theZone) function cfxZones.addZoneToManagedZones(theZone)
local upperName = string.upper(theZone.name) -- newZone.name:upper() local upperName = string.upper(theZone.name) -- newZone.name:upper()
cfxZones.zones[upperName] = theZone cfxZones.zones[upperName] = theZone
@ -435,6 +519,7 @@ function cfxZones.createRandomZoneInZone(name, inZone, targetRadius, entirelyIns
-- create a new circular zone with center placed inside inZone -- create a new circular zone with center placed inside inZone
-- 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
-- trigger.action.outText("Zones: creating rZiZ with tr = " .. targetRadius .. " for " .. inZone.name .. " that as r = " .. inZone.radius, 10) -- trigger.action.outText("Zones: creating rZiZ with tr = " .. targetRadius .. " for " .. inZone.name .. " that as r = " .. inZone.radius, 10)
@ -458,6 +543,8 @@ function cfxZones.createRandomZoneInZone(name, inZone, targetRadius, entirelyIns
-- we have a poly zone. the way we do this is simple: -- we have a poly zone. the way we do this is simple:
-- generate random x, z with ranges of the bounding box -- generate random x, z with ranges of the bounding box
-- until the point falls within the polygon. -- until the point falls within the polygon.
--[[ replaced by new code
local newPoint = {} local newPoint = {}
local emergencyBrake = 0 local emergencyBrake = 0
repeat repeat
@ -465,11 +552,12 @@ function cfxZones.createRandomZoneInZone(name, inZone, targetRadius, entirelyIns
emergencyBrake = emergencyBrake + 1 emergencyBrake = emergencyBrake + 1
if (emergencyBrake > 100) then if (emergencyBrake > 100) then
newPoint = cfxZones.copyPoint(inZone.Point) newPoint = cfxZones.copyPoint(inZone.Point)
trigger.action.outText("CreateZoneInZone: mergency brake for inZone" .. inZone.name, 10) trigger.action.outText("CreateZoneInZone: emergency brake for inZone" .. inZone.name, 10)
break break
end end
until cfxZones.isPointInsidePoly(newPoint, inZone.poly) until cfxZones.isPointInsidePoly(newPoint, inZone.poly)
--]]--
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

View File

@ -1,5 +1,5 @@
cloneZones = {} cloneZones = {}
cloneZones.version = "1.6.0" cloneZones.version = "1.6.1"
cloneZones.verbose = false cloneZones.verbose = false
cloneZones.requiredLibs = { cloneZones.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -65,6 +65,12 @@ cloneZones.allCObjects = {} -- all clones objects
1.6.0 - fixed issues with cloning for zones with linked units 1.6.0 - fixed issues with cloning for zones with linked units
- cloning with useHeading - cloning with useHeading
- major declutter - major declutter
1.6.1 - removed some verbosity when not rotating routes
- updateTaskLocations ()
- cloning groups now also adjusts tasks like search and engage in zone
- cloning with rndLoc supports polygons
- corrected rndLoc without centerOnly to not include individual offsets
- ensure support of recovery tanker resolve cloned group
--]]-- --]]--
@ -402,6 +408,21 @@ function cloneZones.rotateWPAroundCenter(thePoint, center, angle)
thePoint.y = py + center.z -- !! thePoint.y = py + center.z -- !!
end end
function cloneZones.updateTaskLocations(thePoint, zoneDelta)
-- parse tasks for x and y and update them by zoneDelta
if thePoint and thePoint.task and thePoint.task.params and thePoint.task.params.tasks then
local theTasks = thePoint.task.params.tasks
for idx, aTask in pairs(theTasks) do
-- EngageTargetsInZone task has x & y in params
if aTask.params and aTask.params.x and aTask.params.y then
aTask.params.x = aTask.params.x + zoneDelta.x
aTask.params.y = aTask.params.y + zoneDelta.z --!!
-- trigger.action.outText("moved search & engage zone", 30)
end
end
end
end
function cloneZones.updateLocationsInGroupData(theData, zoneDelta, adjustAllWaypoints, center, angle) function cloneZones.updateLocationsInGroupData(theData, zoneDelta, adjustAllWaypoints, center, angle)
-- enter with theData being group's data block -- enter with theData being group's data block
-- remember that zoneDelta's [z] modifies theData's y!! -- remember that zoneDelta's [z] modifies theData's y!!
@ -427,8 +448,9 @@ function cloneZones.updateLocationsInGroupData(theData, zoneDelta, adjustAllWayp
if center and angle then if center and angle then
cloneZones.rotateWPAroundCenter(thePoints[i], center, angle) cloneZones.rotateWPAroundCenter(thePoints[i], center, angle)
else else
trigger.action.outText("not rotating route", 30) -- trigger.action.outText("not rotating route", 30)
end end
cloneZones.updateTaskLocations(thePoints[i], zoneDelta)
end end
else else
-- only first point -- only first point
@ -437,6 +459,7 @@ function cloneZones.updateLocationsInGroupData(theData, zoneDelta, adjustAllWayp
if center and angle then if center and angle then
cloneZones.rotateWPAroundCenter(thePoints[1], center, angle) cloneZones.rotateWPAroundCenter(thePoints[1], center, angle)
end end
cloneZones.updateTaskLocations(thePoints[i], zoneDelta)
end end
-- if there is an airodrome id given in first waypoint, -- if there is an airodrome id given in first waypoint,
@ -617,8 +640,10 @@ function cloneZones.resolveWPReferences(rawData, theZone, dataTable)
local task = aPoint.task local task = aPoint.task
if task and task.params and task.params.tasks then if task and task.params and task.params.tasks then
local tasks = task.params.tasks local tasks = task.params.tasks
-- iterate all tasks for this waypoint
for idy, taskData in pairs(tasks) do for idy, taskData in pairs(tasks) do
-- resolve group references in TASKS -- resolve group references in TASKS
-- also covers recovery tanke etc
if taskData.id and taskData.params and taskData.params.groupId if taskData.id and taskData.params and taskData.params.groupId
then then
-- we resolve group reference -- we resolve group reference
@ -628,7 +653,7 @@ function cloneZones.resolveWPReferences(rawData, theZone, dataTable)
end end
-- resolve EMBARK/DISEMBARK groupd references -- resolve EMBARK/DISEMBARK group references
if taskData.id and taskData.params and taskData.params.groupsForEmbarking if taskData.id and taskData.params and taskData.params.groupsForEmbarking
then then
-- build new groupsForEmbarking -- build new groupsForEmbarking
@ -686,6 +711,7 @@ function cloneZones.resolveWPReferences(rawData, theZone, dataTable)
end end
-- resolve unit references in ACTIONS -- resolve unit references in ACTIONS
-- for example TACAN
if taskData.params and taskData.params.action and if taskData.params and taskData.params.action and
taskData.params.action.params and taskData.params.action.params.unitId then taskData.params.action.params and taskData.params.action.params.unitId then
local uID = taskData.params.action.params.unitId local uID = taskData.params.action.params.unitId
@ -795,24 +821,32 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
if spawnZone.rndLoc then if spawnZone.rndLoc then
-- calculate the entire group's displacement -- calculate the entire group's displacement
local units = rawData.units local units = rawData.units
--[[
local r = math.random() * spawnZone.radius local r = math.random() * spawnZone.radius
local phi = 6.2831 * math.random() -- that's 2Pi, folx local phi = 6.2831 * math.random() -- that's 2Pi, folx
local dx = r * math.cos(phi) local dx = r * math.cos(phi)
local dy = r * math.sin(phi) local dy = r * math.sin(phi)
--]]
local loc, dx, dy = cfxZones.createRandomPointInZone(spawnZone) -- also supports polygonal zones
for idx, aUnit in pairs(units) do for idx, aUnit in pairs(units) do
if not spawnZone.centerOnly then if not spawnZone.centerOnly then
-- *every unit's displacement is randomized -- *every unit's displacement is randomized
r = math.random() * spawnZone.radius -- r = math.random() * spawnZone.radius
phi = 6.2831 * math.random() -- that's 2Pi, folx -- phi = 6.2831 * math.random() -- that's 2Pi, folx
dx = r * math.cos(phi) -- dx = r * math.cos(phi)
dy = r * math.sin(phi) -- dy = r * math.sin(phi)
loc, dx, dy = cfxZones.createRandomPointInZone(spawnZone)
aUnit.x = loc.x
aUnit.y = loc.z
else
aUnit.x = aUnit.x + dx
aUnit.y = aUnit.y + dy
end end
if spawnZone.verbose or cloneZones.verbose then if spawnZone.verbose or cloneZones.verbose then
trigger.action.outText("+++clnZ: <" .. spawnZone.name .. "> R = " .. spawnZone.radius .. ":G<" .. rawData.name .. "/" .. aUnit.name .. "> - rndLoc: r = " .. r .. ", dx = " .. dx .. ", dy= " .. dy .. ".", 30) trigger.action.outText("+++clnZ: <" .. spawnZone.name .. "> R = " .. spawnZone.radius .. ":G<" .. rawData.name .. "/" .. aUnit.name .. "> - rndLoc: r = " .. r .. ", dx = " .. dx .. ", dy= " .. dy .. ".", 30)
end end
aUnit.x = aUnit.x + dx
aUnit.y = aUnit.y + dy
end end
end end
@ -982,10 +1016,11 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
-- randomize if enabled -- randomize if enabled
if spawnZone.rndLoc then if spawnZone.rndLoc then
local r = math.random() * spawnZone.radius --local r = math.random() * spawnZone.radius
local phi = 6.2831 * math.random() -- that's 2Pi, folx --local phi = 6.2831 * math.random() -- that's 2Pi, folx
local dx = r * math.cos(phi) --local dx = r * math.cos(phi)
local dy = r * math.sin(phi) --local dy = r * math.sin(phi)
local loc, dx, dy = cfxZones.createRandomPointInZone(spawnZone) -- also supports polygonal zones
rawData.x = rawData.x + dx rawData.x = rawData.x + dx
rawData.y = rawData.y + dy rawData.y = rawData.y + dy
end end

View File

@ -1,5 +1,5 @@
dcsCommon = {} dcsCommon = {}
dcsCommon.version = "2.7.9" dcsCommon.version = "2.7.10"
--[[-- VERSION HISTORY --[[-- VERSION HISTORY
2.2.6 - compassPositionOfARelativeToB 2.2.6 - compassPositionOfARelativeToB
- clockPositionOfARelativeToB - clockPositionOfARelativeToB
@ -117,6 +117,7 @@ dcsCommon.version = "2.7.9"
- createGroundGroupWithUnits corrected spelling of minDist, crashed scattered formation - createGroundGroupWithUnits corrected spelling of minDist, crashed scattered formation
- randomPointInCircle fixed erroneous local for x, z - randomPointInCircle fixed erroneous local for x, z
- "scattered" formation repaired - "scattered" formation repaired
2.7.10- semaphore groundwork
--]]-- --]]--
@ -2892,7 +2893,30 @@ function dcsCommon.LSR(a, num)
return a return a
end end
--
-- SEMAPHORES
--
dcsCommon.semaphores = {}
-- replacement for trigger.misc.getUserFlag
function dcsCommon.getUserFlag(flagName)
if dcsCommon.semaphores[flagName] then
return dcsCommon.semaphores[flagName]
end
return trigger.misc.getUserFlag(flagName)
end
-- replacement for trigger.action.setUserFlag
function dcsCommon.setUserFlag(flagName, theValue)
-- not yet connected: semaphores
-- forget semaphore content if new value is old-school
if type(theValue) == "number" then
dcsCommon.semaphores[theValue] = nil --return to old-school
end
trigger.action.setUserFlag(flagName, theValue)
end
-- --
-- --
-- INIT -- INIT

View File

@ -43,24 +43,24 @@ messenger.messengers = {}
- unit - unit
- group - group
2.0.1 - config optimization 2.0.1 - config optimization
2.1.0 - unit only: dynamicUnitProcessing for 2.1.0 - unit only: dynamicUnitProcessing with other units/zones
- <bae: u/z> bearing to unit/zone - <bae: u/z> bearing to unit/zone
- <rbae u/z> response mapped by unit's heading - <rbae u/z> response mapped by unit's heading
- <clk: u/z> bearing in clock position to unit/zone - <clk: u/z> bearing in clock position to unit/zone
- <rng: u/z> range to unit/zone - <rng: u/z> range to unit/zone
- <hnd: u/z> bearing in left/right/ahead/behind - <hnd: u/z> bearing in left/right/ahead/behind
- <sde: u/z> bearing in starboard/port/ahead/aft - <sde: u/z> bearing in starboard/port/ahead/aft
- added dynamicGroupProcessing to select unit 1 - added dynamicGroupProcessing to select unit 1
- responses attribute - responses attribute
- <rsp: flag> - <rsp: flag>
- <rrnd> response randomized - <rrnd> response randomized
- <rhdg: u/z> respons mapped by unit's heading - <rhdg: u/z> respons mapped by unit's heading
- <cls unit> closing speed - <cls unit> closing speed
- <vel unit> velocity (speed) - <vel unit> velocity (speed)
- <asp unit> aspect - <asp unit> aspect
- fix to messageMute - fix to messageMute
- <type: unit> - <type: unit>
2.1.1 - cosmetic: only output text if len>0 and not cls
--]]-- --]]--
@ -665,14 +665,18 @@ function messenger.isTriggered(theZone)
if theZone.spaceAfter then msg = msg .. "\n" end if theZone.spaceAfter then msg = msg .. "\n" end
if theZone.msgCoalition then if theZone.msgCoalition then
trigger.action.outTextForCoalition(theZone.msgCoalition, msg, theZone.duration, theZone.clearScreen) if #msg > 0 or theZone.clearScreen then
trigger.action.outTextForCoalition(theZone.msgCoalition, msg, theZone.duration, theZone.clearScreen)
end
trigger.action.outSoundForCoalition(theZone.msgCoalition, fileName) trigger.action.outSoundForCoalition(theZone.msgCoalition, fileName)
elseif theZone.msgGroup then elseif theZone.msgGroup then
local theGroup = Group.getByName(theZone.msgGroup) local theGroup = Group.getByName(theZone.msgGroup)
if theGroup and Group.isExist(theGroup) then if theGroup and Group.isExist(theGroup) then
local ID = theGroup:getID() local ID = theGroup:getID()
msg = messenger.dynamicGroupProcessing(msg, theZone, theGroup) msg = messenger.dynamicGroupProcessing(msg, theZone, theGroup)
trigger.action.outTextForGroup(ID, msg, theZone.duration, theZone.clearScreen) if #msg > 0 or theZone.clearScreen then
trigger.action.outTextForGroup(ID, msg, theZone.duration, theZone.clearScreen)
end
trigger.action.outSoundForGroup(ID, fileName) trigger.action.outSoundForGroup(ID, fileName)
end end
elseif theZone.msgUnit then elseif theZone.msgUnit then
@ -680,12 +684,16 @@ function messenger.isTriggered(theZone)
if theUnit and Unit.isExist(theUnit) then if theUnit and Unit.isExist(theUnit) then
local ID = theUnit:getID() local ID = theUnit:getID()
msg = messenger.dynamicUnitProcessing(msg, theZone, theUnit) msg = messenger.dynamicUnitProcessing(msg, theZone, theUnit)
trigger.action.outTextForUnit(ID, msg, theZone.duration, theZone.clearScreen) if #msg > 0 or theZone.clearScreen then
trigger.action.outTextForUnit(ID, msg, theZone.duration, theZone.clearScreen)
end
trigger.action.outSoundForUnit(ID, fileName) trigger.action.outSoundForUnit(ID, fileName)
end end
else else
-- out to all -- out to all
trigger.action.outText(msg, theZone.duration, theZone.clearScreen) if #msg > 0 or theZone.clearScreen then
trigger.action.outText(msg, theZone.duration, theZone.clearScreen)
end
trigger.action.outSound(fileName) trigger.action.outSound(fileName)
end end
end end

View File

@ -25,6 +25,7 @@ persistence.requiredLibs = {
1.0.3 - no longer always tells " mission saved to" 1.0.3 - no longer always tells " mission saved to"
new 'saveNotification" can be off new 'saveNotification" can be off
1.0.4 - new optional 'root' property 1.0.4 - new optional 'root' property
1.0.5 - desanitize check on readConfig to early-abort
PROVIDES LOAD/SAVE ABILITY TO MODULES PROVIDES LOAD/SAVE ABILITY TO MODULES
@ -419,6 +420,11 @@ function persistence.collectFlagsFromZone(theZone)
end end
function persistence.readConfigZone() function persistence.readConfigZone()
if not _G["lfs"] then
trigger.action.outText("+++persistence: DCS not correctly desanitized. Persistence disabled", 30)
return
end
local theZone = cfxZones.getZoneByName("persistenceConfig") local theZone = cfxZones.getZoneByName("persistenceConfig")
local hasConfig = true local hasConfig = true
if not theZone then if not theZone then

View File

@ -1,5 +1,5 @@
radioMenu = {} radioMenu = {}
radioMenu.version = "2.0.0" radioMenu.version = "2.0.1"
radioMenu.verbose = false radioMenu.verbose = false
radioMenu.ups = 1 radioMenu.ups = 1
radioMenu.requiredLibs = { radioMenu.requiredLibs = {
@ -24,6 +24,8 @@ radioMenu.menus = {}
gereric helo type gereric helo type
generic plane type generic plane type
type works with coalition type works with coalition
2.0.1 corrections to installMenu(), as suggested by GumidekCZ
--]]-- --]]--
@ -198,8 +200,9 @@ function radioMenu.installMenu(theZone)
if cfxZones.hasProperty(theZone, "itemB") then if cfxZones.hasProperty(theZone, "itemB") then
local menuB = cfxZones.getStringFromZoneProperty(theZone, "itemB", "<no B submenu>") local menuB = cfxZones.getStringFromZoneProperty(theZone, "itemB", "<no B submenu>")
if theZone.menuGroup or theZone.menuTypes then if theZone.menuGroup or theZone.menuTypes then
theZone.menuB = {}
for idx, grp in pairs(gID) do for idx, grp in pairs(gID) do
theZone.menuB[grp] = missionCommands.addCommandForGroup(grp, menuB, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, "B"}) theZone.menuB[grp] = missionCommands.addCommandForGroup(grp, menuB, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, "B", grp})
end end
elseif theZone.coalition == 0 then elseif theZone.coalition == 0 then
theZone.menuB = missionCommands.addCommand(menuB, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, "B"}) theZone.menuB = missionCommands.addCommand(menuB, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, "B"})
@ -211,8 +214,9 @@ function radioMenu.installMenu(theZone)
if cfxZones.hasProperty(theZone, "itemC") then if cfxZones.hasProperty(theZone, "itemC") then
local menuC = cfxZones.getStringFromZoneProperty(theZone, "itemC", "<no C submenu>") local menuC = cfxZones.getStringFromZoneProperty(theZone, "itemC", "<no C submenu>")
if theZone.menuGroup or theZone.menuTypes then if theZone.menuGroup or theZone.menuTypes then
theZone.menuC = {}
for idx, grp in pairs(gID) do for idx, grp in pairs(gID) do
theZone.menuC[grp] = missionCommands.addCommandForGroup(grp, menuC, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, "C"}) theZone.menuC[grp] = missionCommands.addCommandForGroup(grp, menuC, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, "C", grp})
end end
elseif theZone.coalition == 0 then elseif theZone.coalition == 0 then
theZone.menuC = missionCommands.addCommand(menuC, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, "C"}) theZone.menuC = missionCommands.addCommand(menuC, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, "C"})
@ -224,8 +228,9 @@ function radioMenu.installMenu(theZone)
if cfxZones.hasProperty(theZone, "itemD") then if cfxZones.hasProperty(theZone, "itemD") then
local menuD = cfxZones.getStringFromZoneProperty(theZone, "itemD", "<no D submenu>") local menuD = cfxZones.getStringFromZoneProperty(theZone, "itemD", "<no D submenu>")
if theZone.menuGroup or theZone.menuTypes then if theZone.menuGroup or theZone.menuTypes then
theZone.menuD = {}
for idx, grp in pairs(gID) do for idx, grp in pairs(gID) do
theZone.menuD[grp] = missionCommands.addCommandForGroup(grp, menuD, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, "D"}) theZone.menuD[grp] = missionCommands.addCommandForGroup(grp, menuD, theZone.rootMenu[grp], radioMenu.redirectMenuX, {theZone, "D", grp})
end end
elseif theZone.coalition == 0 then elseif theZone.coalition == 0 then
theZone.menuD = missionCommands.addCommand(menuD, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, "D"}) theZone.menuD = missionCommands.addCommand(menuD, theZone.rootMenu[0], radioMenu.redirectMenuX, {theZone, "D"})