mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 0.985
Quick Ref Clone Zones Reference Resolve Clone Relations Demo
This commit is contained in:
parent
d69ce05d80
commit
f1aa9cabf1
Binary file not shown.
BIN
Doc/DML Quick Reference.pdf
Normal file
BIN
Doc/DML Quick Reference.pdf
Normal file
Binary file not shown.
@ -178,13 +178,8 @@ function FARPZones.createFARPFromZone(aZone)
|
||||
|
||||
return theFarp
|
||||
end
|
||||
--[[--
|
||||
function FARPZones.drawFarp(theFarp)
|
||||
local theZone = theFarp.zone
|
||||
local theOwner = theFarp.owner
|
||||
FARPZones.drawZoneInMap(theZone, theOwner)
|
||||
end
|
||||
--]]--
|
||||
|
||||
|
||||
function FARPZones.drawFARPCircleInMap(theFarp)
|
||||
if not theFarp then return end
|
||||
|
||||
@ -430,6 +425,7 @@ function FARPZones.readConfig()
|
||||
|
||||
FARPZones.spinUpDelay = cfxZones.getNumberFromZoneProperty(theZone, "spinUpDelay", 30)
|
||||
|
||||
|
||||
if FARPZones.verbose then
|
||||
trigger.action.outText("***frpZ: read config", 30)
|
||||
end
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxArtilleryZones = {}
|
||||
cfxArtilleryZones.version = "2.0.1"
|
||||
cfxArtilleryZones.version = "2.0.2"
|
||||
cfxArtilleryZones.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
"cfxZones", -- Zones, of course
|
||||
@ -24,7 +24,8 @@ cfxArtilleryZones.verbose = false
|
||||
- att transition time to zone info mark
|
||||
- made compatible with linked zones
|
||||
- added silent attribute
|
||||
- added transition time to arty command chatter
|
||||
- added transition time to arty command chatter
|
||||
2.0.2 - boom?, arty? synonyms
|
||||
|
||||
Artillery Target Zones *** EXTENDS ZONES ***
|
||||
Target Zones for artillery. Can determine which zones are in range and visible and then handle artillery barrage to this zone
|
||||
@ -121,13 +122,18 @@ function cfxArtilleryZones.processArtilleryZone(aZone)
|
||||
aZone.addMark = cfxZones.getBoolFromZoneProperty(aZone, "addMark", true) -- note: defaults to true
|
||||
aZone.shellVariance = cfxZones.getNumberFromZoneProperty(aZone, "shellVariance", 0.2) -- strength of explosion can vary by +/- this amount
|
||||
if cfxZones.hasProperty(aZone, "f?") then
|
||||
aZone.triggerFlag = cfxZones.getStringFromZoneProperty(aZone, "f?", "none")
|
||||
aZone.artyTriggerFlag = cfxZones.getStringFromZoneProperty(aZone, "f?", "none")
|
||||
end
|
||||
--[[--
|
||||
if cfxZones.hasProperty(aZone, "triggerFlag") then
|
||||
aZone.triggerFlag = cfxZones.getStringFromZoneProperty(aZone, "triggerFlag", "none")
|
||||
aZone.artyTriggerFlag = cfxZones.getStringFromZoneProperty(aZone, "triggerFlag", "none")
|
||||
end
|
||||
if aZone.triggerFlag then
|
||||
aZone.lastTriggerValue = trigger.misc.getUserFlag(aZone.triggerFlag) -- save last value
|
||||
--]]--
|
||||
if cfxZones.hasProperty(aZone, "artillery?") then
|
||||
aZone.artyTriggerFlag = cfxZones.getStringFromZoneProperty(aZone, "artillery?", "none")
|
||||
end
|
||||
if aZone.artyTriggerFlag then
|
||||
aZone.lastTriggerValue = trigger.misc.getUserFlag(aZone.artyTriggerFlag) -- save last value
|
||||
end
|
||||
aZone.cooldown =cfxZones.getNumberFromZoneProperty(aZone, "cooldown", 120) -- seconds
|
||||
aZone.baseAccuracy = cfxZones.getNumberFromZoneProperty(aZone, "baseAccuracy", aZone.radius) -- meters from center radius shell impact
|
||||
@ -380,8 +386,8 @@ function cfxArtilleryZones.update()
|
||||
|
||||
-- iterate all zones to see if a trigger has changed
|
||||
for idx, aZone in pairs(cfxArtilleryZones.artilleryZones) do
|
||||
if aZone.triggerFlag then
|
||||
local currTriggerVal = trigger.misc.getUserFlag(aZone.triggerFlag)
|
||||
if aZone.artyTriggerFlag then
|
||||
local currTriggerVal = trigger.misc.getUserFlag(aZone.artyTriggerFlag)
|
||||
if currTriggerVal ~= aZone.lastTriggerValue
|
||||
then
|
||||
-- a triggered release!
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxCargoReceiver = {}
|
||||
cfxCargoReceiver.version = "1.1.0"
|
||||
cfxCargoReceiver.version = "1.2.0"
|
||||
cfxCargoReceiver.ups = 1 -- once a second
|
||||
cfxCargoReceiver.maxDirectionRange = 500 -- in m. distance when cargo manager starts talking to pilots who are carrying that cargo
|
||||
cfxCargoReceiver.requiredLibs = {
|
||||
@ -13,7 +13,9 @@ cfxCargoReceiver.requiredLibs = {
|
||||
- 1.0.0 initial vbersion
|
||||
- 1.1.0 added flag manipulation options
|
||||
no negative agl on announcement
|
||||
silent attribute
|
||||
silent attribute
|
||||
- 1.2.0 method
|
||||
f!, cargoReceived!
|
||||
|
||||
|
||||
CargoReceiver is a zone enhancement you use to be automatically
|
||||
@ -67,6 +69,17 @@ function cfxCargoReceiver.processReceiverZone(aZone) -- process attribute and ad
|
||||
if cfxZones.hasProperty(aZone, "f-1") then
|
||||
aZone.decreaseFlag = cfxZones.getStringFromZoneProperty(aZone, "f-1", "999")
|
||||
end
|
||||
|
||||
-- new method support
|
||||
aZone.method = cfxZones.getStringFromZoneProperty(aZone, "method", "inc")
|
||||
|
||||
if cfxZones.hasProperty(aZone, "f!") then
|
||||
aZone.outReceiveFlag = cfxZones.getNumberFromZoneProperty(aZone, "f!", -1)
|
||||
end
|
||||
if cfxZones.hasProperty(aZone, "cargoReceived!") then
|
||||
aZone.outReceiveFlag = cfxZones.getNumberFromZoneProperty(aZone, "cargoReceived!", -1)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function cfxCargoReceiver.addReceiverZone(aZone)
|
||||
@ -132,6 +145,9 @@ function cfxCargoReceiver.cargoEvent(event, object, name)
|
||||
trigger.action.setUserFlag(aZone.decreaseFlag, val)
|
||||
end
|
||||
|
||||
if aZone.outReceiveFlag then
|
||||
cfxZones.pollFlag(aZone.outReceiveFlag, aZone.method)
|
||||
end
|
||||
|
||||
--trigger.action.outText("+++rcv: " .. name .. " delivered in zone " .. aZone.name, 30)
|
||||
--trigger.action.outSound("Quest Snare 3.wav")
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxMX = {}
|
||||
cfxMX.version = "1.0.1"
|
||||
cfxMX.version = "1.1.0"
|
||||
--[[--
|
||||
Mission data decoder. Access to ME-built mission structures
|
||||
|
||||
@ -8,9 +8,17 @@ cfxMX.version = "1.0.1"
|
||||
Version History
|
||||
1.0.0 - initial version
|
||||
1.0.1 - getStaticFromDCSbyName()
|
||||
1.1.0 - getStaticFromDCSbyName also copies groupID when not fetching orig
|
||||
- on start up collects a cross reference table of all
|
||||
original group id
|
||||
- add linkUnit for statics
|
||||
|
||||
|
||||
--]]--
|
||||
cfxMX.groupNamesByID = {}
|
||||
cfxMX.groupIDbyName = {}
|
||||
cfxMX.groupDataByName = {}
|
||||
|
||||
|
||||
function cfxMX.getGroupFromDCSbyName(aName, fetchOriginal)
|
||||
if not fetchOriginal then fetchOriginal = false end
|
||||
@ -105,6 +113,15 @@ function cfxMX.getStaticFromDCSbyName(aName, fetchOriginal)
|
||||
local category = obj_type_name
|
||||
if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's at least one static in group!
|
||||
for group_num, group_data in pairs(obj_type_data.group) do
|
||||
-- get linkUnit info if it exists
|
||||
local linkUnit = nil
|
||||
if group_data and group_data.route and group_data.route and group_data.route.points[1] then
|
||||
linkUnit = group_data.route.points[1].linkUnit
|
||||
if linkUnit then
|
||||
--trigger.action.outText("MX: found missing link to " .. linkUnit .. " in " .. group_data.name, 30)
|
||||
end
|
||||
end
|
||||
|
||||
if group_data and group_data.units and type(group_data.units) == 'table'
|
||||
then --make sure - again - that this is a valid group
|
||||
for unit_num, unit_data in pairs(group_data.units) do -- iterate units
|
||||
@ -113,6 +130,11 @@ function cfxMX.getStaticFromDCSbyName(aName, fetchOriginal)
|
||||
local theStatic = unit_data
|
||||
if not fetchOriginal then
|
||||
theStatic = dcsCommon.clone(unit_data)
|
||||
-- copy group ID from group above
|
||||
theStatic.groupId = group_data.groupId
|
||||
-- copy linked unit data
|
||||
theStatic.linkUnit = linkUnit
|
||||
|
||||
end
|
||||
return theStatic, category, countryID, groupName
|
||||
|
||||
@ -132,6 +154,51 @@ function cfxMX.getStaticFromDCSbyName(aName, fetchOriginal)
|
||||
return nil, "<none>", "<none>", "<no group name>"
|
||||
end
|
||||
|
||||
function cfxMX.createCrossReference()
|
||||
for coa_name_miz, coa_data in pairs(env.mission.coalition) do -- iterate all coalitions
|
||||
local coa_name = coa_name_miz
|
||||
if string.lower(coa_name_miz) == 'neutrals' then -- remove 's' at neutralS
|
||||
coa_name = 'neutral'
|
||||
end
|
||||
-- directly convert coalition into number for easier access later
|
||||
local coaNum = 0
|
||||
if coa_name == "red" then coaNum = 1 end
|
||||
if coa_name == "blue" then coaNum = 2 end
|
||||
|
||||
if type(coa_data) == 'table' then -- coalition = {bullseye, nav_points, name, county},
|
||||
-- with county being an array
|
||||
if coa_data.country then -- make sure there a country table for this coalition
|
||||
for cntry_id, cntry_data in pairs(coa_data.country) do -- iterate all countries for this
|
||||
-- per country = {id, name, vehicle, helicopter, plane, ship, static}
|
||||
local countryName = string.lower(cntry_data.name)
|
||||
local countryID = cntry_data.id
|
||||
if type(cntry_data) == 'table' then -- filter strings .id and .name
|
||||
for obj_type_name, obj_type_data in pairs(cntry_data) do
|
||||
if obj_type_name == "helicopter" or
|
||||
obj_type_name == "ship" or
|
||||
obj_type_name == "plane" or
|
||||
obj_type_name == "vehicle" or
|
||||
obj_type_name == "static"
|
||||
then -- (so it's not id or name)
|
||||
local category = obj_type_name
|
||||
if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's at least one group!
|
||||
for group_num, group_data in pairs(obj_type_data.group) do
|
||||
local aName = group_data.name
|
||||
local aID = group_data.groupId
|
||||
cfxMX.groupNamesByID[aID] = aName
|
||||
cfxMX.groupIDbyName[aName] = aID
|
||||
cfxMX.groupDataByName[aName] = group_data
|
||||
end
|
||||
end --if has category data
|
||||
end --if plane, helo etc... category
|
||||
end --for all objects in country
|
||||
end --if has country data
|
||||
end --for all countries in coalition
|
||||
end --if coalition has country table
|
||||
end -- if there is coalition data
|
||||
end --for all coalitions in mission
|
||||
end
|
||||
|
||||
function cfxMX.catText2ID(inText)
|
||||
local outCat = 0 -- airplane
|
||||
local c = inText:lower()
|
||||
@ -144,3 +211,11 @@ function cfxMX.catText2ID(inText)
|
||||
return outCat
|
||||
end
|
||||
|
||||
function cfxMX.start()
|
||||
cfxMX.createCrossReference()
|
||||
trigger.action.outText("cfxMX: "..#cfxMX.groupNamesByID .. " groups processed successfully", 30)
|
||||
end
|
||||
|
||||
-- start
|
||||
cfxMX.start()
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxObjectDestructDetector = {}
|
||||
cfxObjectDestructDetector.version = "1.0.1"
|
||||
cfxObjectDestructDetector.version = "1.1.0"
|
||||
cfxObjectDestructDetector.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
"cfxZones", -- Zones, of course
|
||||
@ -9,6 +9,8 @@ cfxObjectDestructDetector.verbose = false
|
||||
VERSION HISTORY
|
||||
1.0.0 initial version, based on parashoo, arty zones
|
||||
1.0.1 fixed bug: trigger.MISC.getUserFlag()
|
||||
1.1.0 added support for method, f! and destroyed!
|
||||
|
||||
|
||||
Detect when an object with OBJECT ID as assigned in ME dies
|
||||
*** EXTENDS ZONES
|
||||
@ -69,6 +71,16 @@ function cfxObjectDestructDetector.processObjectDestructZone(aZone)
|
||||
if cfxZones.hasProperty(aZone, "f-1") then
|
||||
aZone.decreaseFlag = cfxZones.getStringFromZoneProperty(aZone, "f-1", "999")
|
||||
end
|
||||
|
||||
-- new method support
|
||||
aZone.method = cfxZones.getStringFromZoneProperty(aZone, "method", "flip")
|
||||
|
||||
if cfxZones.hasProperty(aZone, "f!") then
|
||||
aZone.outDestroyFlag = cfxZones.getNumberFromZoneProperty(aZone, "f!", -1)
|
||||
end
|
||||
if cfxZones.hasProperty(aZone, "destroyed!") then
|
||||
aZone.outDestroyFlag = cfxZones.getNumberFromZoneProperty(aZone, "destroyed!", -1)
|
||||
end
|
||||
end
|
||||
--
|
||||
-- MAIN DETECTOR
|
||||
@ -98,6 +110,11 @@ function cfxObjectDestructDetector:onEvent(event)
|
||||
trigger.action.setUserFlag(aZone.decreaseFlag, val)
|
||||
end
|
||||
|
||||
-- support for banging
|
||||
if aZone.outDestroyFlag then
|
||||
cfxZones.pollFlag(aZone.outDestroyFlag, aZone.method)
|
||||
end
|
||||
|
||||
-- invoke callbacks
|
||||
cfxObjectDestructDetector.invokeCallbacksFor(aZone)
|
||||
if cfxObjectDestructDetector.verbose then
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxObjectSpawnZones = {}
|
||||
cfxObjectSpawnZones.version = "1.1.4"
|
||||
cfxObjectSpawnZones.version = "1.1.5"
|
||||
cfxObjectSpawnZones.requiredLibs = {
|
||||
"dcsCommon", -- common is of course needed for everything
|
||||
-- pretty stupid to check for this since we
|
||||
@ -23,6 +23,7 @@ cfxObjectSpawnZones.ups = 1
|
||||
-- - added possibility to autoUnlink
|
||||
-- 1.1.3 - ME-triggered flag via f? and triggerFlag
|
||||
-- 1.1.4 - activate?, pause? attributes
|
||||
-- 1.1.5 - spawn?, spawnObjects? synonyms
|
||||
|
||||
-- Object spawn zones have the following major uses:
|
||||
-- - dynamically spawn cargo
|
||||
@ -85,6 +86,16 @@ function cfxObjectSpawnZones.createSpawner(inZone)
|
||||
theSpawner.lastTriggerValue = trigger.misc.getUserFlag(theSpawner.triggerFlag)
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(inZone, "spawn?") then
|
||||
theSpawner.triggerFlag = cfxZones.getStringFromZoneProperty(inZone, "spawn?", "none")
|
||||
theSpawner.lastTriggerValue = trigger.misc.getUserFlag(theSpawner.triggerFlag)
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(inZone, "spawnObjects?") then
|
||||
theSpawner.triggerFlag = cfxZones.getStringFromZoneProperty(inZone, "spawnObjects?", "none")
|
||||
theSpawner.lastTriggerValue = trigger.misc.getUserFlag(theSpawner.triggerFlag)
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(inZone, "activate?") then
|
||||
theSpawner.activateFlag = cfxZones.getStringFromZoneProperty(inZone, "activate?", "none")
|
||||
theSpawner.lastActivateValue = trigger.misc.getUserFlag(theSpawner.activateFlag)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxSmokeZone = {}
|
||||
cfxSmokeZone.version = "1.0.3"
|
||||
cfxSmokeZone.version = "1.0.4"
|
||||
cfxSmokeZone.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
"cfxZones", -- Zones, of course
|
||||
@ -12,7 +12,10 @@ cfxSmokeZone.requiredLibs = {
|
||||
1.0.3 - added paused attribute
|
||||
- added f? attribute --> onFlag
|
||||
- broke out startSmoke
|
||||
|
||||
1.0.4 - startSmoke? synonym
|
||||
- alphanum flag upgrade
|
||||
- random color support
|
||||
|
||||
SMOKE ZONES *** EXTENDS ZONES ***
|
||||
keeps 'eternal' smoke up for any zone that has the
|
||||
'smoke' attribute
|
||||
@ -34,6 +37,9 @@ function cfxSmokeZone.processSmokeZone(aZone)
|
||||
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 = cfxZones.getNumberFromZoneProperty(aZone, "altitude", 1)
|
||||
@ -46,8 +52,12 @@ function cfxSmokeZone.processSmokeZone(aZone)
|
||||
aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "f?", "none")
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(aZone, "startSmoke?") then
|
||||
aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "startSmoke?", "none")
|
||||
end
|
||||
|
||||
if aZone.onFlag then
|
||||
aZone.onFlagVal = trigger.misc.getUserFlag(aZone.onFlag) -- save last value
|
||||
aZone.onFlagVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- save last value
|
||||
end
|
||||
end
|
||||
|
||||
@ -67,7 +77,7 @@ function cfxSmokeZone.addSmokeZoneWithColor(aZone, aColor, anAltitude, paused, o
|
||||
|
||||
if onFlag then
|
||||
aZone.onFlag = onFlag
|
||||
aZone.onFlagVal = trigger.misc.getUserFlag(onFlag)
|
||||
aZone.onFlagVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- trigger.misc.getUserFlag(onFlag)
|
||||
end
|
||||
|
||||
cfxSmokeZone.addSmokeZone(aZone) -- add to update loop
|
||||
@ -123,7 +133,7 @@ function cfxSmokeZone.checkFlags()
|
||||
for idx, aZone in pairs(cfxSmokeZone.smokeZones) do
|
||||
if aZone.paused and aZone.onFlagVal then
|
||||
-- see if this changed
|
||||
local currTriggerVal = trigger.misc.getUserFlag(aZone.onFlag)
|
||||
local currTriggerVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- trigger.misc.getUserFlag(aZone.onFlag)
|
||||
if currTriggerVal ~= aZone.onFlagVal then
|
||||
-- yupp, trigger start
|
||||
cfxSmokeZone.startSmoke(aZone)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxSpawnZones = {}
|
||||
cfxSpawnZones.version = "1.5.2"
|
||||
cfxSpawnZones.version = "1.5.3"
|
||||
cfxSpawnZones.requiredLibs = {
|
||||
"dcsCommon", -- common is of course needed for everything
|
||||
-- pretty stupid to check for this since we
|
||||
@ -52,6 +52,7 @@ cfxSpawnZones.verbose = false
|
||||
-- 1.5.1 - relaxed baseName and default to dcsCommon.uuid()
|
||||
-- - verbose
|
||||
-- 1.5.2 - activate?, pause? flag
|
||||
-- 1.5.3 - spawn?, spawnUnits? flags
|
||||
--
|
||||
-- new version requires cfxGroundTroops, where they are
|
||||
--
|
||||
@ -140,6 +141,17 @@ function cfxSpawnZones.createSpawner(inZone)
|
||||
theSpawner.lastTriggerValue = trigger.misc.getUserFlag(theSpawner.triggerFlag)
|
||||
end
|
||||
|
||||
-- synonyms spawn? and spawnObject?
|
||||
if cfxZones.hasProperty(inZone, "spawn?") then
|
||||
theSpawner.triggerFlag = cfxZones.getStringFromZoneProperty(inZone, "spawn?", "none")
|
||||
theSpawner.lastTriggerValue = trigger.misc.getUserFlag(theSpawner.triggerFlag)
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(inZone, "spawnUnits?") then
|
||||
theSpawner.triggerFlag = cfxZones.getStringFromZoneProperty(inZone, "spawnObject?", "none")
|
||||
theSpawner.lastTriggerValue = trigger.misc.getUserFlag(theSpawner.triggerFlag)
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(inZone, "activate?") then
|
||||
theSpawner.activateFlag = cfxZones.getStringFromZoneProperty(inZone, "activate?", "none")
|
||||
theSpawner.lastActivateValue = trigger.misc.getUserFlag(theSpawner.activateFlag)
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
--
|
||||
|
||||
cfxZones = {}
|
||||
cfxZones.version = "2.5.5"
|
||||
cfxZones.version = "2.5.6"
|
||||
--[[-- VERSION HISTORY
|
||||
- 2.2.4 - getCoalitionFromZoneProperty
|
||||
- getStringFromZoneProperty
|
||||
@ -50,6 +50,10 @@ cfxZones.version = "2.5.5"
|
||||
- extractPropertyFromDCS trims key and property
|
||||
- 2.5.5 - pollFlag() centralized for banging
|
||||
- allStaticsInZone
|
||||
- 2.5.6 - flag accessor setFlagValue(), getFlagValue
|
||||
- pollFlag supports theZone as final parameter
|
||||
- randomDelayFromPositiveRange
|
||||
- isMEFlag
|
||||
|
||||
--]]--
|
||||
cfxZones.verbose = false
|
||||
@ -197,6 +201,7 @@ function cfxZones.readFromDCS(clearfirst)
|
||||
|
||||
-- add to my table
|
||||
cfxZones.zones[upperName] = newZone -- WARNING: UPPER ZONE!!!
|
||||
--trigger.action.outText("znd: procced " .. newZone.name .. " with radius " .. newZone.radius, 30)
|
||||
else
|
||||
if cfxZones.verbose then
|
||||
trigger.action.outText("cf/x zones: malformed zone #" .. i .. " dropped", 10)
|
||||
@ -467,11 +472,13 @@ end;
|
||||
function cfxZones.isPointInsideZone(thePoint, theZone)
|
||||
local p = {x=thePoint.x, y = 0, z = thePoint.z} -- zones have no altitude
|
||||
if (theZone.isCircle) then
|
||||
local zp = cfxZones.getPoint(theZone)
|
||||
local d = dcsCommon.dist(p, theZone.point)
|
||||
return d < theZone.radius
|
||||
end
|
||||
|
||||
if (theZone.isPoly) then
|
||||
--trigger.action.outText("zne: isPointInside: " .. theZone.name .. " is Polyzone!", 30)
|
||||
return (cfxZones.isPointInsidePoly(p, theZone.poly))
|
||||
end
|
||||
|
||||
@ -550,6 +557,7 @@ end
|
||||
--
|
||||
function cfxZones.allGroupsInZone(theZone, categ) -- categ is optional, must be code
|
||||
-- warning: does not check for exiting!
|
||||
--trigger.action.outText("Zone " .. theZone.name .. " radius " .. theZone.radius, 30)
|
||||
local inZones = {}
|
||||
local coals = {0, 1, 2} -- all coalitions
|
||||
for idx, coa in pairs(coals) do
|
||||
@ -601,9 +609,12 @@ function cfxZones.isGroupPartiallyInZone(aGroup, aZone)
|
||||
for uk, aUnit in pairs (allUnits) do
|
||||
if aUnit:isExist() and aUnit:getLife() > 1 then
|
||||
local p = aUnit:getPoint()
|
||||
if cfxZones.isPointInsideZone(p, aZone) then
|
||||
local inzone, percent, dist = cfxZones.pointInZone(p, aZone)
|
||||
if inzone then -- cfxZones.isPointInsideZone(p, aZone) then
|
||||
--trigger.action.outText("zne: YAY <" .. aUnit:getName() .. "> IS IN " .. aZone.name, 30)
|
||||
return true
|
||||
end
|
||||
--trigger.action.outText("zne: <" .. aUnit:getName() .. "> not in " .. aZone.name .. ", dist = " .. dist .. ", rad = ", aZone.radius, 30)
|
||||
end
|
||||
end
|
||||
return false
|
||||
@ -1048,7 +1059,7 @@ end
|
||||
--
|
||||
-- Flag Pulling
|
||||
--
|
||||
function cfxZones.pollFlag(theFlag, method)
|
||||
function cfxZones.pollFlag(theFlag, method, theZone)
|
||||
if cfxZones.verbose then
|
||||
trigger.action.outText("+++zones: polling flag " .. theFlag .. " with " .. method, 30)
|
||||
end
|
||||
@ -1085,6 +1096,68 @@ function cfxZones.pollFlag(theFlag, method)
|
||||
end
|
||||
end
|
||||
|
||||
function cfxZones.setFlagValue(theFlag, theValue, theZone)
|
||||
local zoneName = "<dummy>"
|
||||
if not theZone then
|
||||
trigger.action.outText("+++Zne: no zone on setFlagValue")
|
||||
else
|
||||
zoneName = theZone.name -- for flag wildcards
|
||||
end
|
||||
|
||||
if type(theFlag) == "number" then
|
||||
-- straight set, ME flag
|
||||
trigger.action.setUserFlag(theFlag, theValue)
|
||||
return
|
||||
end
|
||||
|
||||
-- we assume it's a string now
|
||||
theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces
|
||||
local nFlag = tonumber(theFlag)
|
||||
if nFlag then
|
||||
trigger.action.setUserFlag(theFlag, theValue)
|
||||
return
|
||||
end
|
||||
|
||||
-- now do wildcard processing. we have alphanumeric
|
||||
if dcsCommon.stringStartsWith(theFlag, "*") then
|
||||
theFlag = zoneName .. theFlag
|
||||
end
|
||||
trigger.action.setUserFlag(theFlag, theValue)
|
||||
end
|
||||
|
||||
function cfxZones.getFlagValue(theFlag, theZone)
|
||||
local zoneName = "<dummy>"
|
||||
if not theZone then
|
||||
trigger.action.outText("+++Zne: no zone on getFlagValue")
|
||||
else
|
||||
zoneName = theZone.name -- for flag wildcards
|
||||
end
|
||||
|
||||
if type(theFlag) == "number" then
|
||||
-- straight get, ME flag
|
||||
return trigger.misc.getUserFlag(theFlag)
|
||||
end
|
||||
|
||||
-- we assume it's a string now
|
||||
theFlag = dcsCommon.trim(theFlag) -- clear leading/trailing spaces
|
||||
local nFlag = tonumber(theFlag)
|
||||
if nFlag then
|
||||
return trigger.misc.getUserFlag(theFlag)
|
||||
end
|
||||
|
||||
-- now do wildcard processing. we have alphanumeric
|
||||
if dcsCommon.stringStartsWith(theFlag, "*") then
|
||||
theFlag = zoneName .. theFlag
|
||||
end
|
||||
return trigger.misc.getUserFlag(theFlag)
|
||||
end
|
||||
|
||||
function cfxZones.isMEFlag(inFlag)
|
||||
return true
|
||||
-- returns true if inFlag is a pure positive number
|
||||
-- inFlag = dcsCommon.trim(inFlag)
|
||||
-- return dcsCommon.stringIsPositiveNumber(inFlag)
|
||||
end
|
||||
|
||||
--
|
||||
-- PROPERTY PROCESSING
|
||||
@ -1167,6 +1240,19 @@ function cfxZones.getMinMaxFromZoneProperty(theZone, theProperty)
|
||||
|
||||
end
|
||||
|
||||
function cfxZones.randomDelayFromPositiveRange(minVal, maxVal)
|
||||
if not maxVal then return minVal end
|
||||
if not minVal then return maxVal end
|
||||
local delay = maxVal
|
||||
if minVal > 0 and minVal < delay then
|
||||
-- we want a randomized from time from minTime .. delay
|
||||
local varPart = delay - minVal + 1
|
||||
varPart = dcsCommon.smallRandom(varPart) - 1
|
||||
delay = minVal + varPart
|
||||
end
|
||||
return delay
|
||||
end
|
||||
|
||||
function cfxZones.getPositiveRangeFromZoneProperty(theZone, theProperty, default)
|
||||
-- reads property as string, and interprets as range 'a-b'.
|
||||
-- if not a range but single number, returns both for upper and lower
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cloneZones = {}
|
||||
cloneZones.version = "1.1.1"
|
||||
cloneZones.version = "1.2.0"
|
||||
cloneZones.verbose = false
|
||||
cloneZones.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
@ -7,7 +7,10 @@ cloneZones.requiredLibs = {
|
||||
"cfxMX",
|
||||
}
|
||||
cloneZones.cloners = {}
|
||||
|
||||
cloneZones.callbacks = {}
|
||||
cloneZones.unitXlate = {}
|
||||
cloneZones.groupXlate = {} -- used to translate original groupID to cloned. only holds last spawned group id
|
||||
cloneZones.uniqueCounter = 9200000 -- we start group numbering here
|
||||
--[[--
|
||||
Clones Groups from ME mission data
|
||||
Copyright (c) 2022 by Christian Franz and cf/x AG
|
||||
@ -18,6 +21,16 @@ cloneZones.cloners = {}
|
||||
1.1.0 - support for static objects
|
||||
- despawn? attribute
|
||||
1.1.1 - despawnAll: isExist guard
|
||||
- map in? to f?
|
||||
1.2.0 - Lua API integration: callbacks
|
||||
- groupXlate struct
|
||||
- unitXlate struct
|
||||
- resolveReferences
|
||||
- getGroupsInZone rewritten for data
|
||||
- static resolve
|
||||
- linkUnit resolve
|
||||
- clone? synonym
|
||||
- empty! and method attributes
|
||||
|
||||
--]]--
|
||||
|
||||
@ -38,18 +51,82 @@ function cloneZones.getCloneZoneByName(aName)
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--
|
||||
-- callbacks
|
||||
--
|
||||
|
||||
function cloneZones.addCallback(theCallback)
|
||||
if not theCallback then return end
|
||||
table.insert(cloneZones.callbacks, theCallback)
|
||||
end
|
||||
|
||||
-- reasons for callback
|
||||
-- "will despawn group" - args is the group about to be despawned
|
||||
-- "did spawn group" -- args is group that was spawned
|
||||
-- "will despawn static"
|
||||
-- "did spawn static"
|
||||
-- "spawned" -- completed spawn cycle. args contains .groups and .statics spawned
|
||||
-- "empty" -- all spawns have been killed, args is empty
|
||||
-- "wiped" -- preWipe executed
|
||||
-- "<none" -- something went wrong
|
||||
|
||||
function cloneZones.invokeCallbacks(theZone, reason, args)
|
||||
if not theZone then return end
|
||||
if not reason then reason = "<none>" end
|
||||
if not args then args = {} end
|
||||
|
||||
-- invoke anyone who wants to know that a group
|
||||
-- of people was rescued.
|
||||
for idx, cb in pairs(cloneZones.callbacks) do
|
||||
cb(theZone, reason, args)
|
||||
end
|
||||
end
|
||||
|
||||
-- group translation orig id
|
||||
|
||||
--
|
||||
-- reading zones
|
||||
--
|
||||
function cloneZones.partOfGroupDataInZone(theZone, theUnits)
|
||||
local zP = cfxZones.getPoint(theZone)
|
||||
zP.y = 0
|
||||
|
||||
for idx, aUnit in pairs(theUnits) do
|
||||
local uP = {}
|
||||
uP.x = aUnit.x
|
||||
uP.y = 0
|
||||
uP.z = aUnit.y -- !! y-z
|
||||
local dist = dcsCommon.dist(uP, zP)
|
||||
if dist <= theZone.radius then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function cloneZones.allGroupsInZoneByData(theZone)
|
||||
local theGroupsInZone = {}
|
||||
local radius = theZone.radius
|
||||
for groupName, groupData in pairs(cfxMX.groupDataByName) do
|
||||
if groupData.units then
|
||||
if cloneZones.partOfGroupDataInZone(theZone, groupData.units) then
|
||||
theGroup = Group.getByName(groupName)
|
||||
table.insert(theGroupsInZone, theGroup)
|
||||
end
|
||||
end
|
||||
end
|
||||
return theGroupsInZone
|
||||
end
|
||||
|
||||
function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
||||
local localZones = cfxZones.allGroupsInZone(theZone)
|
||||
if cloneZones.verbose then
|
||||
trigger.action.outText("+++clnZ: new cloner " .. theZone.name, 30)
|
||||
end
|
||||
|
||||
local localZones = cloneZones.allGroupsInZoneByData(theZone)
|
||||
local localObjects = cfxZones.allStaticsInZone(theZone)
|
||||
theZone.cloner = true -- this is a cloner zoner
|
||||
theZone.mySpawns = {}
|
||||
theZone.myStatics = {}
|
||||
--theZone.groupVectors = {}
|
||||
theZone.origin = cfxZones.getPoint(theZone) -- save reference point for all groupVectors
|
||||
|
||||
-- source tells us which template to use. it can be the following:
|
||||
@ -72,8 +149,15 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
||||
if gName then
|
||||
table.insert(theZone.cloneNames, gName)
|
||||
table.insert(theZone.mySpawns, aGroup) -- collect them for initial despawn
|
||||
-- now get group data and save a lookup for
|
||||
-- resolving internal references
|
||||
local rawData, cat, ctry = cfxMX.getGroupFromDCSbyName(gName)
|
||||
local origID = rawData.groupId
|
||||
-- cloneZones.templateGroups[gName] = origID
|
||||
-- cloneZones.templateGroupsReverse[origID] = gName
|
||||
end
|
||||
end
|
||||
|
||||
for idx, aStatic in pairs (localObjects) do
|
||||
local sName = aStatic:getName()
|
||||
if sName then
|
||||
@ -111,6 +195,12 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
||||
theZone.lastSpawnValue = trigger.misc.getUserFlag(theZone.spawnFlag) -- save last value
|
||||
end
|
||||
|
||||
-- synonyms
|
||||
if cfxZones.hasProperty(theZone, "clone?") then
|
||||
theZone.spawnFlag = cfxZones.getStringFromZoneProperty(theZone, "clone?", "none")
|
||||
theZone.lastSpawnValue = trigger.misc.getUserFlag(theZone.spawnFlag) -- save last value
|
||||
end
|
||||
|
||||
-- deSpawn?
|
||||
if cfxZones.hasProperty(theZone, "deSpawn?") then
|
||||
theZone.deSpawnFlag = cfxZones.getStringFromZoneProperty(theZone, "deSpawn?", "none")
|
||||
@ -127,16 +217,19 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
||||
theZone.emptyFlag = cfxZones.getNumberFromZoneProperty(theZone, "empty+1", "<None>") -- note string on number default
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(theZone, "empty!") then
|
||||
theZone.emptyBangFlag = cfxZones.getNumberFromZoneProperty(theZone, "empty!", "<None>") -- note string on number default
|
||||
end
|
||||
|
||||
theZone.method = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
|
||||
|
||||
if cfxZones.hasProperty(theZone, "masterOwner") then
|
||||
theZone.masterOwner = cfxZones.getStringFromZoneProperty(theZone, "masterOwner", "<none>")
|
||||
end
|
||||
|
||||
--cloneZones.spawnWithCloner(theZone)
|
||||
theZone.turn = cfxZones.getNumberFromZoneProperty(theZone, "turn", 0)
|
||||
|
||||
-- make sure we spawn at least once
|
||||
-- bad idea, since we may want to simply create a template
|
||||
-- if not theZone.spawnFlag then theZone.onStart = true end
|
||||
-- we end with clear plate
|
||||
end
|
||||
|
||||
--
|
||||
@ -148,7 +241,10 @@ function cloneZones.despawnAll(theZone)
|
||||
trigger.action.outText("wiping <" .. theZone.name .. ">", 30)
|
||||
end
|
||||
for idx, aGroup in pairs(theZone.mySpawns) do
|
||||
--trigger.action.outText("++clnZ: despawn all " .. aGroup.name, 30)
|
||||
|
||||
if aGroup:isExist() then
|
||||
cloneZones.invokeCallbacks(theZone, "will despawn group", aGroup)
|
||||
Group.destroy(aGroup)
|
||||
end
|
||||
end
|
||||
@ -156,7 +252,10 @@ function cloneZones.despawnAll(theZone)
|
||||
-- warning! may be mismatch because we are looking at groups
|
||||
-- not objects. let's see
|
||||
if aStatic:isExist() then
|
||||
trigger.action.outText("Destroying static <" .. aStatic:getName() .. ">", 30)
|
||||
if cloneZones.verbose then
|
||||
trigger.action.outText("Destroying static <" .. aStatic:getName() .. ">", 30)
|
||||
end
|
||||
cloneZones.invokeCallbacks(theZone, "will despawn static", aStatic)
|
||||
Object.destroy(aStatic) -- we don't aStatio:destroy() to find out what it is
|
||||
end
|
||||
end
|
||||
@ -165,7 +264,7 @@ function cloneZones.despawnAll(theZone)
|
||||
end
|
||||
|
||||
function cloneZones.updateLocationsInGroupData(theData, zoneDelta, adjustAllWaypoints)
|
||||
--trigger.action.outText("Update loc - zone delta: [" .. zoneDelta.x .. "," .. zoneDelta.z .. "]", 30)
|
||||
|
||||
-- remember that zoneDelta's [z] modifies theData's y!!
|
||||
theData.x = theData.x + zoneDelta.x
|
||||
theData.y = theData.y + zoneDelta.z -- !!!
|
||||
@ -178,8 +277,6 @@ function cloneZones.updateLocationsInGroupData(theData, zoneDelta, adjustAllWayp
|
||||
-- first waypoint, but only all others if asked
|
||||
-- to
|
||||
local theRoute = theData.route
|
||||
-- TODO: vehicles can have 'spans' - may need to program for
|
||||
-- those as well. we currently only go for points
|
||||
if theRoute then
|
||||
local thePoints = theRoute.points
|
||||
if thePoints and #thePoints > 0 then
|
||||
@ -227,8 +324,13 @@ function cloneZones.updateLocationsInGroupData(theData, zoneDelta, adjustAllWayp
|
||||
end
|
||||
end
|
||||
end
|
||||
function cloneZones.uniqueID()
|
||||
local uid = cloneZones.uniqueCounter
|
||||
cloneZones.uniqueCounter = cloneZones.uniqueCounter + 1
|
||||
return uid
|
||||
end
|
||||
|
||||
function cloneZones.uniqueNameGroupData(theData)
|
||||
function cloneZones.uniqueNameGroupData(theData)
|
||||
theData.name = dcsCommon.uuid(theData.name)
|
||||
local units = theData.units
|
||||
for idx, aUnit in pairs(units) do
|
||||
@ -236,6 +338,21 @@ function cloneZones.uniqueNameGroupData(theData)
|
||||
end
|
||||
end
|
||||
|
||||
function cloneZones.uniqueIDGroupData(theData)
|
||||
theData.groupId = cloneZones.uniqueID()
|
||||
end
|
||||
|
||||
function cloneZones.uniqueIDUnitData(theData)
|
||||
if not theData then return end
|
||||
if not theData.units then return end
|
||||
local units = theData.units
|
||||
for idx, aUnit in pairs(units) do
|
||||
aUnit.CZorigID = aUnit.unitId
|
||||
aUnit.unitId = cloneZones.uniqueID()
|
||||
aUnit.CZTargetID = aUnit.unitId
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function cloneZones.resolveOwnership(spawnZone, ctry)
|
||||
if not spawnZone.masterOwner then return ctry end
|
||||
@ -254,9 +371,151 @@ function cloneZones.resolveOwnership(spawnZone, ctry)
|
||||
return ctry
|
||||
end
|
||||
|
||||
--
|
||||
-- resolve external group references
|
||||
--
|
||||
|
||||
function cloneZones.resolveGroupID(gID, rawData, dataTable, reason)
|
||||
local resolvedID = gID
|
||||
local myOName = rawData.CZorigName
|
||||
local groupName = cfxMX.groupNamesByID[gID]
|
||||
--trigger.action.outText("Resolve for <" .. myOName .. "> the external ID: " .. gID .. " --> " .. groupName .. " for <" .. reason.. "> task", 30)
|
||||
|
||||
-- first, check if this an internal reference, i.e. inside the same
|
||||
-- zone template
|
||||
for idx, otherData in pairs(dataTable) do
|
||||
-- look in own data table
|
||||
if otherData.CZorigName == groupName then
|
||||
-- using cfxMX for clarity only (name access)
|
||||
resolvedID = otherData.CZTargetID
|
||||
--trigger.action.outText("resolved (internally) " .. gID .. " to " .. resolvedID, 30)
|
||||
return resolvedID
|
||||
end
|
||||
end
|
||||
|
||||
-- now check if we have spawned this before
|
||||
local lastClone = cloneZones.groupXlate[gID]
|
||||
if lastClone then
|
||||
resolvedID = lastClone
|
||||
--trigger.action.outText("resolved (EXT) " .. gID .. " to " .. resolvedID, 30)
|
||||
return resolvedID
|
||||
end
|
||||
|
||||
-- if we get here, reference is not to a cloned item
|
||||
--trigger.action.outText("resolved " .. gID .. " to " .. resolvedID, 30)
|
||||
return resolvedID
|
||||
end
|
||||
|
||||
function cloneZones.resolveUnitID(uID, rawData, dataTable, reason)
|
||||
-- also resolves statics as they share ID with units
|
||||
local resolvedID = uID
|
||||
--trigger.action.outText("Resolve reference to unitId <" .. uID .. "> for <" .. reason.. "> task", 30)
|
||||
|
||||
-- first, check if this an internal reference, i.e. inside the same
|
||||
-- zone template
|
||||
for idx, otherData in pairs(dataTable) do
|
||||
-- iterate all units
|
||||
for idy, aUnit in pairs(otherData.units) do
|
||||
if aUnit.CZorigID == uID then
|
||||
resolvedID = aUnit.CZTargetID
|
||||
--trigger.action.outText("resolved (internally) " .. uID .. " to " .. resolvedID, 30)
|
||||
return resolvedID
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- now check if we have spawned this before
|
||||
local lastClone = cloneZones.unitXlate[uID]
|
||||
if lastClone then
|
||||
resolvedID = lastClone
|
||||
--trigger.action.outText("resolved (U-EXT) " .. uID .. " to " .. resolvedID, 30)
|
||||
return resolvedID
|
||||
end
|
||||
|
||||
-- if we get here, reference is not to a cloned item
|
||||
--trigger.action.outText("resolved G-" .. uID .. " to " .. resolvedID, 30)
|
||||
return resolvedID
|
||||
end
|
||||
|
||||
function cloneZones.resolveStaticLinkUnit(uID)
|
||||
local resolvedID = uID
|
||||
local lastClone = cloneZones.unitXlate[uID]
|
||||
if lastClone then
|
||||
resolvedID = lastClone
|
||||
--trigger.action.outText("resolved (U-EXT) " .. uID .. " to " .. resolvedID, 30)
|
||||
return resolvedID
|
||||
end
|
||||
return resolvedID
|
||||
end
|
||||
|
||||
function cloneZones.resolveWPReferences(rawData, theZone, dataTable)
|
||||
-- check to see if we really need data table, as we have theZone
|
||||
-- perform a check of route for group or unit references
|
||||
if not rawData then return end
|
||||
local myOName = rawData.CZorigName
|
||||
|
||||
if rawData.route and rawData.route.points then
|
||||
local points = rawData.route.points
|
||||
for idx, aPoint in pairs(points) do
|
||||
-- check if there is a link unit here and resolve
|
||||
if aPoint.linkUnit then
|
||||
local gID = aPoint.linkUnit
|
||||
local resolvedID = cloneZones.resolveUnitID(gID, rawData, dataTable, "linkUnit")
|
||||
aPoint.linkUnit = resolvedID
|
||||
--trigger.action.outText("resolved link unit to "..resolvedID .. " for " .. rawData.name, 30)
|
||||
end
|
||||
|
||||
-- iterate all tasks assigned to point
|
||||
local task = aPoint.task
|
||||
if task and task.params and task.params.tasks then
|
||||
local tasks = task.params.tasks
|
||||
for idy, taskData in pairs(tasks) do
|
||||
-- resolve group references in TASKS
|
||||
if taskData.id and taskData.params and taskData.params.groupId
|
||||
then
|
||||
-- we resolve group reference
|
||||
local gID = taskData.params.groupId
|
||||
local resolvedID = cloneZones.resolveGroupID(gID, rawData, dataTable, taskData.id)
|
||||
taskData.params.groupId = resolvedID
|
||||
|
||||
end
|
||||
|
||||
-- resolve unit references in TASKS
|
||||
if taskData.id and taskData.params and taskData.params.unitId
|
||||
then
|
||||
-- we don't look for keywords, we simply resolve
|
||||
local uID = taskData.params.unitId
|
||||
local resolvedID = cloneZones.resolveUnitID(uID, rawData, dataTable, taskData.id)
|
||||
taskData.params.unitId = resolvedID
|
||||
end
|
||||
|
||||
-- resolve unit references in ACTIONS
|
||||
if taskData.params and taskData.params.action and
|
||||
taskData.params.action.params and taskData.params.action.params.unitId then
|
||||
local uID = taskData.params.action.params.unitId
|
||||
local resolvedID = cloneZones.resolveUnitID(uID, rawData, dataTable, "Action")
|
||||
taskData.params.action.params.unitId = resolvedID
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function cloneZones.resolveReferences(theZone, dataTable)
|
||||
-- when an action refers to another group, we check if
|
||||
-- the group referred to is also a clone, and update
|
||||
-- the reference to the newest incardnation
|
||||
|
||||
for idx, rawData in pairs(dataTable) do
|
||||
-- resolve references in waypoints
|
||||
cloneZones.resolveWPReferences(rawData, theZone, dataTable)
|
||||
end
|
||||
end
|
||||
|
||||
function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
|
||||
--trigger.action.outText("ENTER: Spawn with template " .. theZone.name .. " for spawnZone " .. spawnZone.name, 30)
|
||||
-- theZone is the zoner with the template
|
||||
-- theZone is the cloner with the template
|
||||
-- spawnZone is the spawner with settings
|
||||
--if not spawnZone then spawnZone = theZone end
|
||||
local newCenter = cfxZones.getPoint(spawnZone)
|
||||
@ -265,17 +524,23 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
|
||||
|
||||
local spawnedGroups = {}
|
||||
local spawnedStatics = {}
|
||||
local dataToSpawn = {}
|
||||
|
||||
for idx, aGroupName in pairs(theZone.cloneNames) do
|
||||
local rawData, cat, ctry = cfxMX.getGroupFromDCSbyName(aGroupName)
|
||||
|
||||
if rawData.name == aGroupName then
|
||||
else
|
||||
rawData.CZorigName = rawData.name -- save original group name
|
||||
local origID = rawData.groupId -- save original group ID
|
||||
rawData.CZorigID = origID
|
||||
cloneZones.uniqueIDGroupData(rawData) -- assign unique ID we know
|
||||
cloneZones.uniqueIDUnitData(rawData) -- assign unique ID for units -- saves old unitId as CZorigID
|
||||
rawData.CZTargetID = rawData.groupId -- save
|
||||
if rawData.name ~= aGroupName then
|
||||
trigger.action.outText("Clone: FAILED name check", 30)
|
||||
end
|
||||
|
||||
-- now use raw data to spawn and see if it works outabox
|
||||
local theCat = cfxMX.catText2ID(cat)
|
||||
rawData.CZtheCat = theCat -- save cat
|
||||
|
||||
-- update their position if not spawning to exact same location
|
||||
cloneZones.updateLocationsInGroupData(rawData, zoneDelta, spawnZone.moveRoute)
|
||||
@ -286,29 +551,76 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
|
||||
-- make sure unit and group names are unique
|
||||
cloneZones.uniqueNameGroupData(rawData)
|
||||
|
||||
-- see waht country we spawn for
|
||||
-- see what country we spawn for
|
||||
ctry = cloneZones.resolveOwnership(spawnZone, ctry)
|
||||
|
||||
local theGroup = coalition.addGroup(ctry, theCat, rawData)
|
||||
rawData.CZctry = ctry -- save ctry
|
||||
table.insert(dataToSpawn, rawData)
|
||||
end
|
||||
|
||||
-- now resolve references to other cloned units for all raw data
|
||||
-- we must do this BEFORE we spawn
|
||||
cloneZones.resolveReferences(theZone, dataToSpawn)
|
||||
|
||||
-- now spawn all raw data
|
||||
for idx, rawData in pairs (dataToSpawn) do
|
||||
-- now spawn and save to clones
|
||||
local theGroup = coalition.addGroup(rawData.CZctry, rawData.CZtheCat, rawData)
|
||||
table.insert(spawnedGroups, theGroup)
|
||||
|
||||
--trigger.action.outText("spawned group " .. rawData.name .. "consisting of", 30)
|
||||
|
||||
-- update groupXlate table
|
||||
local newGroupID = theGroup:getID() -- new ID assigned by DCS
|
||||
local origID = rawData.CZorigID -- before we materialized
|
||||
cloneZones.groupXlate[origID] = newGroupID
|
||||
-- now also save all units for references
|
||||
-- and verify assigned vs target ID
|
||||
for idx, aUnit in pairs(rawData.units) do
|
||||
-- access the proposed name
|
||||
local uName = aUnit.name
|
||||
local gUnit = Unit.getByName(uName)
|
||||
if gUnit then
|
||||
-- unit exists. compare planned and assigned ID
|
||||
local uID = tonumber(gUnit:getID())
|
||||
if uID == aUnit.CZTargetID then
|
||||
--trigger.action.outText("unit " .. uName .. "#"..uID, 30)
|
||||
-- all good
|
||||
else
|
||||
trigger.action.outText("clnZ: post-clone verification failed for unit <" .. uName .. ">: ÎD mismatch: " .. uID .. " -- " .. aUnit.CZTargetID, 30)
|
||||
end
|
||||
cloneZones.unitXlate[aUnit.CZorigID] = uID
|
||||
else
|
||||
trigger.action.outText("clnZ: post-clone verifiaction failed for unit <" .. uName .. ">: not found", 30)
|
||||
end
|
||||
end
|
||||
|
||||
-- check if our assigned ID matches the handed out by
|
||||
-- DCS
|
||||
if newGroupID == rawData.CZTargetID then
|
||||
-- we are good
|
||||
else
|
||||
trigger.action.outText("clnZ: MISMATCH " .. rawData.name .. " target ID " .. rawData.CZTargetID .. " does not match " .. newGroupID, 30)
|
||||
end
|
||||
|
||||
cloneZones.invokeCallbacks(theZone, "did spawn group", theGroup)
|
||||
end
|
||||
|
||||
-- static spawns
|
||||
for idx, aStaticName in pairs(theZone.staticNames) do
|
||||
local rawData, cat, ctry, parent = cfxMX.getStaticFromDCSbyName(aStaticName)
|
||||
local rawData, cat, ctry, parent = cfxMX.getStaticFromDCSbyName(aStaticName) -- returns a UNIT data block
|
||||
|
||||
if not rawData then
|
||||
trigger.action.outText("Static Clone: no such group <"..aStaticName .. ">", 30)
|
||||
|
||||
trigger.action.outText("Static Clone: no such group <"..aStaticName .. ">", 30)
|
||||
elseif rawData.name == aStaticName then
|
||||
trigger.action.outText("Static Clone: suxess!!! <".. aStaticName ..">", 30)
|
||||
|
||||
-- all good
|
||||
else
|
||||
trigger.action.outText("Static Clone: FAILED name check for <" .. aStaticName .. ">", 30)
|
||||
end
|
||||
|
||||
local origID = rawData.unitId -- save original unit ID
|
||||
rawData.CZorigID = origID
|
||||
|
||||
-- now use raw data to spawn and see if it works outabox
|
||||
local theCat = cfxMX.catText2ID(cat) -- will be "static"
|
||||
--local theCat = cfxMX.catText2ID(cat) -- will be "static"
|
||||
|
||||
-- move origin
|
||||
rawData.x = rawData.x + zoneDelta.x
|
||||
@ -317,20 +629,56 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
|
||||
-- apply turning
|
||||
dcsCommon.rotateUnitData(rawData, spawnZone.turn, newCenter.x, newCenter.z)
|
||||
|
||||
-- make sure static name is unique
|
||||
-- cloneZones.uniqueNameGroupData(rawData)
|
||||
-- make sure static name is unique and remember original
|
||||
rawData.name = dcsCommon.uuid(rawData.name)
|
||||
rawData.unitID = nil -- simply forget, will be newly issued
|
||||
rawData.unitId = cloneZones.uniqueID()
|
||||
rawData.CZTargetID = rawData.unitId
|
||||
|
||||
-- see waht country we spawn for
|
||||
-- see what country we spawn for
|
||||
ctry = cloneZones.resolveOwnership(spawnZone, ctry)
|
||||
|
||||
-- handle linkUnit if provided
|
||||
if rawData.linkUnit then
|
||||
--trigger.action.outText("has link to " .. rawData.linkUnit, 30)
|
||||
local lU = cloneZones.resolveStaticLinkUnit(rawData.linkUnit)
|
||||
--trigger.action.outText("resolved to " .. lU, 30)
|
||||
rawData.linkUnit = lU
|
||||
if not rawData.offsets then
|
||||
rawData.offsets = {}
|
||||
rawData.offsets.angle = 0
|
||||
rawData.offsets.x = 0
|
||||
rawData.offsets.y = 0
|
||||
--trigger.action.outText("clnZ: link required offset for " .. rawData.name, 30)
|
||||
end
|
||||
rawData.offsets.y = rawData.offsets.y - zoneDelta.z
|
||||
rawData.offsets.x = rawData.offsets.x - zoneDelta.x
|
||||
rawData.offsets.angle = rawData.offsets.angle + spawnZone.turn
|
||||
rawData.linkOffset = true
|
||||
-- trigger.action.outText("zone deltas are " .. zoneDelta.x .. ", " .. zoneDelta.y, 30)
|
||||
end
|
||||
|
||||
local theStatic = coalition.addStaticObject(ctry, rawData)
|
||||
local newStaticID = tonumber(theStatic:getID())
|
||||
table.insert(spawnedStatics, theStatic)
|
||||
-- we don't mix groups with units, so no lookup tables for
|
||||
-- statics
|
||||
if newStaticID == rawData.CZTargetID then
|
||||
-- trigger.action.outText("Static ID OK: " .. newStaticID .. " for " .. rawData.name, 30)
|
||||
else
|
||||
trigger.action.outText("Static ID mismatch: " .. newStaticID .. " vs (target) " .. rawData.CZTargetID .. " for " .. rawData.name, 30)
|
||||
end
|
||||
cloneZones.unitXlate[origID] = newStaticID -- same as units
|
||||
|
||||
cloneZones.invokeCallbacks(theZone, "did spawn static", theStatic)
|
||||
--]]--
|
||||
trigger.action.outText("Static spawn: spawned " .. aStaticName, 30)
|
||||
if cloneZones.verbose then
|
||||
trigger.action.outText("Static spawn: spawned " .. aStaticName, 30)
|
||||
end
|
||||
end
|
||||
|
||||
local args = {}
|
||||
args.groups = spawnedGroups
|
||||
args.statics = spawnedStatics
|
||||
cloneZones.invokeCallbacks(theZone, "spawned", args)
|
||||
return spawnedGroups, spawnedStatics
|
||||
end
|
||||
|
||||
@ -381,6 +729,7 @@ function cloneZones.spawnWithCloner(theZone)
|
||||
-- pre-Wipe?
|
||||
if theZone.preWipe then
|
||||
cloneZones.despawnAll(theZone)
|
||||
cloneZones.invokeCallbacks(theZone, "wiped", {})
|
||||
end
|
||||
|
||||
|
||||
@ -454,6 +803,7 @@ function cloneZones.hasLiveUnits(theZone)
|
||||
return false
|
||||
end
|
||||
|
||||
-- old code, deprecated
|
||||
function cloneZones.pollFlag(flagNum, method)
|
||||
-- we currently ignore method
|
||||
local num = trigger.misc.getUserFlag(flagNum)
|
||||
@ -491,17 +841,24 @@ function cloneZones.update()
|
||||
end
|
||||
end
|
||||
|
||||
-- see if we are empty and should signal
|
||||
if aZone.emptyFlag and aZone.hasClones then
|
||||
if cloneZones.countLiveUnits(aZone) < 1 then
|
||||
-- we are depleted. poll flag once, then remember we have
|
||||
-- polled
|
||||
-- empty handling
|
||||
local isEmpty = cloneZones.countLiveUnits(aZone) < 1 and aZone.hasClones
|
||||
if isEmpty then
|
||||
-- see if we need to bang a flag
|
||||
if aZone.emptyFlag then
|
||||
cloneZones.pollFlag(aZone.emptyFlag)
|
||||
aZone.hasClones = false
|
||||
end
|
||||
|
||||
if aZone.emptyBangFlag then
|
||||
cfxZones.pollFlag(aZone.emptyBangFlag, aZone.method)
|
||||
end
|
||||
-- invoke callbacks
|
||||
cloneZones.invokeCallbacks(aZone, "empty", {})
|
||||
|
||||
-- prevent isEmpty next pass
|
||||
aZone.hasClones = false
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
@ -571,8 +928,25 @@ function cloneZones.start()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
-- let's go!
|
||||
if not cloneZones.start() then
|
||||
trigger.action.outText("cf/x Clone Zones aborted: missing libraries", 30)
|
||||
cloneZones = nil
|
||||
end
|
||||
end
|
||||
|
||||
--[[-- callback testing
|
||||
czcb = {}
|
||||
function czcb.callback(theZone, reason, args)
|
||||
trigger.action.outText("clone CB: " .. theZone.name .. " with " .. reason, 30)
|
||||
end
|
||||
cloneZones.addCallback(czcb.callback)
|
||||
--]]--
|
||||
|
||||
--[[--
|
||||
to resolve tasks
|
||||
|
||||
- AFAC
|
||||
- FAC Assign group
|
||||
- set freq for unit
|
||||
--]]--
|
||||
@ -15,6 +15,7 @@ countDown.requiredLibs = {
|
||||
1.1.0 - Lua interface: callbacks
|
||||
- corrected verbose (erroneously always suppressed)
|
||||
- triggerFlag --> triggerCountFlag
|
||||
1.1.1 - corrected bug in invokeCallback
|
||||
|
||||
--]]--
|
||||
|
||||
@ -56,7 +57,7 @@ function countDown.invokeCallbacks(theZone, val, tminus, zero, belowZero, loopin
|
||||
|
||||
-- invoke anyone who wants to know that a group
|
||||
-- of people was rescued.
|
||||
for idx, cb in pairs(csarManager.csarCompleteCB) do
|
||||
for idx, cb in pairs(countDown.callbacks) do
|
||||
cb(theZone, val, tminus, zero, belowZero, looping)
|
||||
end
|
||||
end
|
||||
@ -94,7 +95,7 @@ function countDown.createCountDownWithZone(theZone)
|
||||
end
|
||||
|
||||
if theZone.triggerCountFlag then
|
||||
theZone.lastTriggerValue = trigger.misc.getUserFlag(theZone.triggerCountFlag) -- save last value
|
||||
theZone.lastCountTriggerValue = trigger.misc.getUserFlag(theZone.triggerCountFlag) -- save last value
|
||||
end
|
||||
|
||||
-- zero! bang
|
||||
@ -184,13 +185,13 @@ function countDown.update()
|
||||
-- make sure to re-start before reading time limit
|
||||
if aZone.triggerCountFlag then
|
||||
local currTriggerVal = trigger.misc.getUserFlag(aZone.triggerCountFlag)
|
||||
if currTriggerVal ~= aZone.lastTriggerValue
|
||||
if currTriggerVal ~= aZone.lastCountTriggerValue
|
||||
then
|
||||
if countDown.verbose then
|
||||
trigger.action.outText("+++cntD: triggered on in?", 30)
|
||||
end
|
||||
countDown.isTriggered(aZone)
|
||||
aZone.lastTriggerValue = trigger.misc.getUserFlag(aZone.triggerCountFlag) -- save last value
|
||||
aZone.lastCountTriggerValue = trigger.misc.getUserFlag(aZone.triggerCountFlag) -- save last value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
dcsCommon = {}
|
||||
dcsCommon.version = "2.5.4"
|
||||
dcsCommon.version = "2.5.5"
|
||||
--[[-- VERSION HISTORY
|
||||
2.2.6 - compassPositionOfARelativeToB
|
||||
- clockPositionOfARelativeToB
|
||||
@ -62,6 +62,9 @@ dcsCommon.version = "2.5.4"
|
||||
- removed forced error in failed pickRandom
|
||||
2.5.4 - rotateUnitData()
|
||||
- randomBetween()
|
||||
2.5.5 - stringStartsWithDigit()
|
||||
- stringStartsWithLetter()
|
||||
- stringIsPositiveNumber()
|
||||
|
||||
--]]--
|
||||
|
||||
@ -1700,7 +1703,31 @@ dcsCommon.version = "2.5.4"
|
||||
return trimmedArray
|
||||
end
|
||||
|
||||
-- same as cfxZones, this is the commonly used, may need to remove from zones
|
||||
function dcsCommon.stringIsPositiveNumber(theString)
|
||||
-- only full integer positive numbers supported
|
||||
if not theString then return false end
|
||||
-- if theString == "" then return false end
|
||||
for i = 1, #theString do
|
||||
local c = theString:sub(i,i)
|
||||
if c < "0" or c > "9" then return false end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function dcsCommon.stringStartsWithDigit(theString)
|
||||
if #theString < 1 then return false end
|
||||
local c = string.sub(theString, 1, 1)
|
||||
return c >= "0" and c <= "9"
|
||||
end
|
||||
|
||||
function dcsCommon.stringStartsWithLetter(theString)
|
||||
if #theString < 1 then return false end
|
||||
local c = string.sub(theString, 1, 1)
|
||||
if c >= "a" and c <= "z" then return true end
|
||||
if c >= "A" and c <= "Z" then return true end
|
||||
return false
|
||||
end
|
||||
|
||||
function dcsCommon.stringStartsWith(theString, thePrefix)
|
||||
return theString:find(thePrefix) == 1
|
||||
end
|
||||
@ -2109,8 +2136,8 @@ end
|
||||
function dcsCommon.init()
|
||||
cbID = 0
|
||||
dcsCommon.uuIdent = 0
|
||||
if (dcsCommon.verbose) then
|
||||
trigger.action.outText("dcsCommon v" .. dcsCommon.version .. " loaded successfully", 10)
|
||||
if (dcsCommon.verbose) or true then
|
||||
trigger.action.outText("dcsCommon v" .. dcsCommon.version .. " loaded", 10)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
delayFlag = {}
|
||||
delayFlag.version = "1.0.2"
|
||||
delayFlag.version = "1.0.4"
|
||||
delayFlag.verbose = false
|
||||
delayFlag.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
@ -20,7 +20,9 @@ delayFlag.flags = {}
|
||||
- using cfxZones for polling
|
||||
- removed pollFlag
|
||||
1.0.3 - bug fix for config zone name
|
||||
- removed message attribute, moved to own module
|
||||
- removed message attribute, moved to own module
|
||||
- triggerFlag --> triggerDelayFlag
|
||||
1.0.4 - startDelay
|
||||
|
||||
--]]--
|
||||
|
||||
@ -55,15 +57,19 @@ function delayFlag.createTimerWithZone(theZone)
|
||||
|
||||
-- trigger flag
|
||||
if cfxZones.hasProperty(theZone, "f?") then
|
||||
theZone.triggerFlag = cfxZones.getStringFromZoneProperty(theZone, "f?", "none")
|
||||
theZone.triggerDelayFlag = cfxZones.getStringFromZoneProperty(theZone, "f?", "none")
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(theZone, "in?") then
|
||||
theZone.triggerFlag = cfxZones.getStringFromZoneProperty(theZone, "in?", "none")
|
||||
theZone.triggerDelayFlag = cfxZones.getStringFromZoneProperty(theZone, "in?", "none")
|
||||
end
|
||||
|
||||
if theZone.triggerFlag then
|
||||
theZone.lastTriggerValue = trigger.misc.getUserFlag(theZone.triggerFlag) -- save last value
|
||||
if cfxZones.hasProperty(theZone, "startDelay?") then
|
||||
theZone.triggerDelayFlag = cfxZones.getStringFromZoneProperty(theZone, "startDelay?", "none")
|
||||
end
|
||||
|
||||
if theZone.triggerDelayFlag then
|
||||
theZone.lastDelayTriggerValue = trigger.misc.getUserFlag(theZone.triggerDelayFlag) -- save last value
|
||||
end
|
||||
|
||||
|
||||
@ -79,10 +85,6 @@ function delayFlag.createTimerWithZone(theZone)
|
||||
theZone.onStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", false)
|
||||
end
|
||||
|
||||
-- message
|
||||
if cfxZones.hasProperty(theZone, "message") then
|
||||
theZone.myMessage = cfxZones.getStringZoneProperty(theZone, "message", "<none>")
|
||||
end
|
||||
|
||||
-- init
|
||||
theZone.running = false
|
||||
@ -128,9 +130,9 @@ function delayFlag.update()
|
||||
|
||||
for idx, aZone in pairs(delayFlag.flags) do
|
||||
-- make sure to re-start before reading time limit
|
||||
if aZone.triggerFlag then
|
||||
local currTriggerVal = trigger.misc.getUserFlag(aZone.triggerFlag)
|
||||
if currTriggerVal ~= aZone.lastTriggerValue
|
||||
if aZone.triggerDelayFlag then
|
||||
local currTriggerVal = trigger.misc.getUserFlag(aZone.triggerDelayFlag)
|
||||
if currTriggerVal ~= aZone.lastDelayTriggerValue
|
||||
then
|
||||
if delayFlag.verbose then
|
||||
if aZone.running then
|
||||
@ -140,7 +142,7 @@ function delayFlag.update()
|
||||
end
|
||||
end
|
||||
delayFlag.startDelay(aZone) -- we restart even if running
|
||||
aZone.lastTriggerValue = currTriggerVal
|
||||
aZone.lastDelayTriggerValue = currTriggerVal
|
||||
end
|
||||
end
|
||||
|
||||
@ -152,9 +154,9 @@ function delayFlag.update()
|
||||
-- poll flag
|
||||
cfxZones.pollFlag(aZone.outFlag, aZone.method)
|
||||
-- say message
|
||||
if aZone.myMessage then
|
||||
trigger.action.outText(aZone.myMessage, 30)
|
||||
end
|
||||
--if aZone.myMessage then
|
||||
-- trigger.action.outText(aZone.myMessage, 30)
|
||||
--end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
messenger = {}
|
||||
messenger.version = "1.0.0"
|
||||
messenger.version = "1.0.1"
|
||||
messenger.verbose = false
|
||||
messenger.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
@ -9,6 +9,8 @@ messenger.messengers = {}
|
||||
--[[--
|
||||
Version History
|
||||
1.0.0 - initial version
|
||||
1.0.1 - messageOut? synonym
|
||||
- spelling types in about
|
||||
|
||||
--]]--
|
||||
|
||||
@ -53,6 +55,10 @@ function messenger.createMessengerDownWithZone(theZone)
|
||||
theZone.triggerMessagerFlag = cfxZones.getStringFromZoneProperty(theZone, "in?", "none")
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(theZone, "messageOut?") then
|
||||
theZone.triggerMessagerFlag = cfxZones.getStringFromZoneProperty(theZone, "messageOut?", "none")
|
||||
end
|
||||
|
||||
if theZone.triggerMessagerFlag then
|
||||
theZone.lastMessageTriggerValue = trigger.misc.getUserFlag(theZone.triggerMessagerFlag) -- save last value
|
||||
end
|
||||
@ -125,10 +131,10 @@ end
|
||||
function messenger.start()
|
||||
-- lib check
|
||||
if not dcsCommon.libCheck then
|
||||
trigger.action.outText("cfx Count Down requires dcsCommon", 30)
|
||||
trigger.action.outText("cfx Messenger requires dcsCommon", 30)
|
||||
return false
|
||||
end
|
||||
if not dcsCommon.libCheck("cfx Count Down", messenger.requiredLibs) then
|
||||
if not dcsCommon.libCheck("cfx Messenger", messenger.requiredLibs) then
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
pulseFlags = {}
|
||||
pulseFlags.version = "1.0.2"
|
||||
pulseFlags.version = "1.0.3"
|
||||
pulseFlags.verbose = false
|
||||
pulseFlags.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
@ -14,6 +14,10 @@ pulseFlags.requiredLibs = {
|
||||
- 1.0.0 Initial version
|
||||
- 1.0.1 pause behavior debugged
|
||||
- 1.0.2 zero pulse optional initial pulse suppress
|
||||
- 1.0.3 pollFlag switched to cfxZones
|
||||
uses randomDelayFromPositiveRange
|
||||
flag! now is string
|
||||
WARNING: still needs full alphaNum flag upgrade
|
||||
|
||||
--]]--
|
||||
|
||||
@ -28,7 +32,7 @@ end
|
||||
--
|
||||
|
||||
function pulseFlags.createPulseWithZone(theZone)
|
||||
theZone.flag = cfxZones.getNumberFromZoneProperty(theZone, "flag!", -1) -- the flag to pulse
|
||||
theZone.flag = cfxZones.getStringFromZoneProperty(theZone, "flag!", -1) -- the flag to pulse
|
||||
|
||||
-- time can be number, or number-number range
|
||||
theZone.minTime, theZone.time = cfxZones.getPositiveRangeFromZoneProperty(theZone, "time", 1)
|
||||
@ -68,42 +72,6 @@ end
|
||||
--
|
||||
-- update
|
||||
--
|
||||
function pulseFlags.pollFlag(theFlag, method)
|
||||
if pulseFlags.verbose then
|
||||
trigger.action.outText("+++PulF: polling flag " .. theFlag .. " with " .. method, 30)
|
||||
end
|
||||
|
||||
method = method:lower()
|
||||
local currVal = trigger.misc.getUserFlag(theFlag)
|
||||
if method == "inc" or method == "f+1" then
|
||||
trigger.action.setUserFlag(theFlag, currVal + 1)
|
||||
|
||||
elseif method == "dec" or method == "f-1" then
|
||||
trigger.action.setUserFlag(theFlag, currVal - 1)
|
||||
|
||||
elseif method == "off" or method == "f=0" then
|
||||
trigger.action.setUserFlag(theFlag, 0)
|
||||
|
||||
elseif method == "flip" or method == "xor" then
|
||||
if currVal ~= 0 then
|
||||
trigger.action.setUserFlag(theFlag, 0)
|
||||
else
|
||||
trigger.action.setUserFlag(theFlag, 1)
|
||||
end
|
||||
|
||||
else
|
||||
if method ~= "on" and method ~= "f=1" then
|
||||
trigger.action.outText("+++PulF: unknown method <" .. method .. "> - using 'on'", 30)
|
||||
end
|
||||
-- default: on.
|
||||
trigger.action.setUserFlag(theFlag, 1)
|
||||
end
|
||||
|
||||
local newVal = trigger.misc.getUserFlag(theFlag)
|
||||
if pulseFlags.verbose then
|
||||
trigger.action.outText("+++PulF: flag <" .. theFlag .. "> changed from " .. currVal .. " to " .. newVal, 30)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function pulseFlags.doPulse(args)
|
||||
@ -118,7 +86,7 @@ function pulseFlags.doPulse(args)
|
||||
-- do a poll on flags
|
||||
-- first, we only do an initial pulse if zeroPulse is set
|
||||
if theZone.hasPulsed or theZone.zeroPulse then
|
||||
pulseFlags.pollFlag(theZone.flag, theZone.method)
|
||||
cfxZones.pollFlag(theZone.flag, theZone.method, theZone)
|
||||
|
||||
-- decrease count
|
||||
if theZone.pulses > 0 then
|
||||
@ -149,6 +117,7 @@ function pulseFlags.doPulse(args)
|
||||
theZone.hasPulsed = true -- we are past initial pulse
|
||||
|
||||
-- if we get here, schedule next pulse
|
||||
--[[--
|
||||
local delay = theZone.time
|
||||
if theZone.minTime > 0 and theZone.minTime < delay then
|
||||
-- we want a randomized from time from minTime .. delay
|
||||
@ -156,6 +125,8 @@ function pulseFlags.doPulse(args)
|
||||
varPart = dcsCommon.smallRandom(varPart) - 1
|
||||
delay = theZone.minTime + varPart
|
||||
end
|
||||
--]]--
|
||||
local delay = cfxZones.randomDelayFromPositiveRange(theZone.minTime, theZone.time)
|
||||
|
||||
--trigger.action.outText("***PulF: pulse <" .. theZone.name .. "> scheduled in ".. delay .."!", 30)
|
||||
|
||||
|
||||
137
modules/raiseFlag.lua
Normal file
137
modules/raiseFlag.lua
Normal file
@ -0,0 +1,137 @@
|
||||
raiseFlag = {}
|
||||
raiseFlag.version = "1.0.0"
|
||||
raiseFlag.verbose = false
|
||||
raiseFlag.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
"cfxZones", -- Zones, of course
|
||||
}
|
||||
raiseFlag.flags = {}
|
||||
--[[--
|
||||
Raise A Flag module -- (c) 2022 by Christian Franz and cf/x AG
|
||||
|
||||
Version History
|
||||
1.0.0 - initial release
|
||||
--]]--
|
||||
function raiseFlag.addRaiseFlag(theZone)
|
||||
table.insert(raiseFlag.flags, theZone)
|
||||
end
|
||||
|
||||
function raiseFlag.getRaiseFlagByName(aName)
|
||||
for idx, aZone in pairs(raiseFlag.flags) do
|
||||
if aName == aZone.name then return aZone end
|
||||
end
|
||||
if raiseFlag.verbose then
|
||||
trigger.action.outText("+++rFlg: no raiseFlag with name <" .. aName ..">", 30)
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--
|
||||
-- read attributes
|
||||
--
|
||||
function raiseFlag.createRaiseFlagWithZone(theZone)
|
||||
-- get flag from faiseFlag itself
|
||||
theZone.raiseFlag = cfxZones.getStringFromZoneProperty(theZone, "raiseFlag", "<none>") -- the flag to raise
|
||||
|
||||
theZone.flagValue = cfxZones.getNumberFromZoneProperty(theZone, "value", 1) -- value to set to
|
||||
|
||||
theZone.minAfterTime, theZone.maxAfterTime = cfxZones.getPositiveRangeFromZoneProperty(theZone, "afterTime", -1)
|
||||
|
||||
if cfxZones.hasProperty(theZone, "stopFlag?") then
|
||||
theZone.triggerStopFlag = cfxZones.getStringFromZoneProperty(theZone, "stopFlag?", "none")
|
||||
theZone.lastTriggerStopValue = cfxZones.getFlagValue(theZone.triggerStopFlag, theZone) -- save last value
|
||||
end
|
||||
|
||||
theZone.scheduleID = nil
|
||||
theZone.raiseStopped = false
|
||||
|
||||
-- now simply schedule for invocation
|
||||
local args = {}
|
||||
args.theZone = theZone
|
||||
if theZone.minAfterTime < 1 then
|
||||
timer.scheduleFunction(raiseFlag.triggered, args, timer.getTime() + 0.5)
|
||||
else
|
||||
local delay = cfxZones.randomDelayFromPositiveRange(theZone.minAfterTime, theZone.maxAfterTime)
|
||||
timer.scheduleFunction(raiseFlag.triggered, args, timer.getTime() + delay)
|
||||
end
|
||||
end
|
||||
|
||||
function raiseFlag.triggered(args)
|
||||
local theZone = args.theZone
|
||||
if theZone.raiseStopped then return end
|
||||
-- if we get here, we aren't stopped and do the flag pull
|
||||
cfxZones.setFlagValue(theZone.raiseFlag, theZone.flagValue, theZone)
|
||||
end
|
||||
|
||||
--
|
||||
-- update
|
||||
--
|
||||
function raiseFlag.update()
|
||||
-- call me in a second to poll triggers
|
||||
timer.scheduleFunction(raiseFlag.update, {}, timer.getTime() + 1)
|
||||
|
||||
for idx, aZone in pairs(raiseFlag.flags) do
|
||||
-- make sure to re-start before reading time limit
|
||||
if aZone.triggerStopFlag then
|
||||
local currTriggerVal = cfxZones.getFlagValue(aZone.triggerStopFlag, theZone)
|
||||
if currTriggerVal ~= aZone.lastTriggerStopValue
|
||||
then
|
||||
theZone.raiseStopped = true -- we are done, no flag!
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- config & go!
|
||||
--
|
||||
|
||||
function raiseFlag.readConfigZone()
|
||||
local theZone = cfxZones.getZoneByName("raiseFlagConfig")
|
||||
if not theZone then
|
||||
if raiseFlag.verbose then
|
||||
trigger.action.outText("+++rFlg: NO config zone!", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
raiseFlag.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
|
||||
|
||||
if raiseFlag.verbose then
|
||||
trigger.action.outText("+++rFlg: read config", 30)
|
||||
end
|
||||
end
|
||||
|
||||
function raiseFlag.start()
|
||||
-- lib check
|
||||
if not dcsCommon.libCheck then
|
||||
trigger.action.outText("cfx raise flag requires dcsCommon", 30)
|
||||
return false
|
||||
end
|
||||
if not dcsCommon.libCheck("cfx Count Down", raiseFlag.requiredLibs) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- read config
|
||||
raiseFlag.readConfigZone()
|
||||
|
||||
-- process cloner Zones
|
||||
local attrZones = cfxZones.getZonesWithAttributeNamed("raiseFlag")
|
||||
for k, aZone in pairs(attrZones) do
|
||||
raiseFlag.createRaiseFlagWithZone(aZone) -- process attributes
|
||||
raiseFlag.addRaiseFlag(aZone) -- add to list
|
||||
end
|
||||
|
||||
-- start update
|
||||
raiseFlag.update()
|
||||
|
||||
trigger.action.outText("cfx raiseFlag v" .. raiseFlag.version .. " started.", 30)
|
||||
return true
|
||||
end
|
||||
|
||||
-- let's go!
|
||||
if not raiseFlag.start() then
|
||||
trigger.action.outText("cfx Raise Flag aborted: missing libraries", 30)
|
||||
raiseFlag = nil
|
||||
end
|
||||
BIN
tutorial & demo missions/demo - Clone Relations.miz
Normal file
BIN
tutorial & demo missions/demo - Clone Relations.miz
Normal file
Binary file not shown.
Binary file not shown.
BIN
tutorial & demo missions/demo - flag fun.miz
Normal file
BIN
tutorial & demo missions/demo - flag fun.miz
Normal file
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user