mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 2.3.5
WHpersistence
This commit is contained in:
parent
a70fadc550
commit
0c1eb53a89
Binary file not shown.
Binary file not shown.
96
modules/WHpersistence.lua
Normal file
96
modules/WHpersistence.lua
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
WHpersistence = {}
|
||||||
|
WHpersistence.version = "1.0.0"
|
||||||
|
WHpersistence.requiredLibs = {
|
||||||
|
"dcsCommon",
|
||||||
|
"cfxZones",
|
||||||
|
"persistence",
|
||||||
|
}
|
||||||
|
--
|
||||||
|
-- load / save (game data)
|
||||||
|
--
|
||||||
|
function WHpersistence.saveData()
|
||||||
|
local theData = {}
|
||||||
|
local theWH = {}
|
||||||
|
-- generate all WH data from all my airfields
|
||||||
|
local allMyBase = world:getAirbases()
|
||||||
|
for idx, theBase in pairs(allMyBase) do
|
||||||
|
local name = theBase:getName()
|
||||||
|
local WH = theBase:getWarehouse()
|
||||||
|
local inv = WH:getInventory()
|
||||||
|
theWH[name] = inv
|
||||||
|
end
|
||||||
|
theData.theWH = theWH
|
||||||
|
return theData, WHpersistence.sharedData -- second val currently nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function WHpersistence.loadData()
|
||||||
|
if not persistence then return end
|
||||||
|
local shared = nil
|
||||||
|
local theData = persistence.getSavedDataForModule("WHpersistence")
|
||||||
|
if (not theData) or not (theData.theWH) then
|
||||||
|
if WHpersistence.verbose then
|
||||||
|
trigger.action.outText("+++WHp: no save date received, skipping.", 30)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- set up all warehouses from data loaded
|
||||||
|
for name, inv in pairs(theData.theWH) do
|
||||||
|
trigger.action.outText("+++restoring <" .. name .. ">", 30)
|
||||||
|
local theBase = Airbase.getByName(name)
|
||||||
|
if theBase then
|
||||||
|
local theWH = theBase:getWarehouse()
|
||||||
|
if theWH then
|
||||||
|
-- we go through weapon, liquids and aircraft
|
||||||
|
for idx, liq in pairs(inv.liquids) do
|
||||||
|
theWH:setLiquidAmount(idx, liq)
|
||||||
|
trigger.action.outText(name .. ": Liq <" .. idx .. "> : <" .. liq .. ">", 30)
|
||||||
|
end
|
||||||
|
for ref, num in pairs(inv.weapon) do
|
||||||
|
theWH:setItem(ref, num)
|
||||||
|
end
|
||||||
|
for ref, num in pairs(inv.aircraft) do
|
||||||
|
theWH:setItem(ref, num)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
trigger.action.outText(name .. ": no warehouse")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
trigger.action.outText(name .. ": no airbase")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
--
|
||||||
|
-- config
|
||||||
|
--
|
||||||
|
function WHpersistence.readConfigZone()
|
||||||
|
local theZone = cfxZones.getZoneByName("WHpersistenceConfig")
|
||||||
|
if not theZone then
|
||||||
|
theZone = cfxZones.createSimpleZone("WHpersistenceConfig")
|
||||||
|
end
|
||||||
|
WHpersistence.verbose = theZone.verbose
|
||||||
|
end
|
||||||
|
--
|
||||||
|
-- GO
|
||||||
|
--
|
||||||
|
function WHpersistence.start()
|
||||||
|
if not dcsCommon.libCheck then
|
||||||
|
trigger.action.outText("cfx WHpersistence requires dcsCommon", 30)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
if not dcsCommon.libCheck("cfx Raise Flag", WHpersistence.requiredLibs)then return false end
|
||||||
|
WHpersistence.readConfigZone()
|
||||||
|
if persistence then
|
||||||
|
callbacks = {}
|
||||||
|
callbacks.persistData = WHpersistence.saveData
|
||||||
|
persistence.registerModule("WHpersistence", callbacks)
|
||||||
|
-- now load my data
|
||||||
|
WHpersistence.loadData()
|
||||||
|
end
|
||||||
|
trigger.action.outText("cfx WHpersistence v" .. WHpersistence.version .. " started.", 30)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if not WHpersistence.start() then
|
||||||
|
trigger.action.outText("cfx WHpersistence aborted: missing libraries", 30)
|
||||||
|
WHpersistence = nil
|
||||||
|
end
|
||||||
@ -1,5 +1,5 @@
|
|||||||
airfield = {}
|
airfield = {}
|
||||||
airfield.version = "2.2.0"
|
airfield.version = "2.3.0"
|
||||||
airfield.requiredLibs = {
|
airfield.requiredLibs = {
|
||||||
"dcsCommon",
|
"dcsCommon",
|
||||||
"cfxZones",
|
"cfxZones",
|
||||||
@ -22,6 +22,12 @@ airfield.allAirfields = {} -- inexed by af name, db entries: base, cat
|
|||||||
2.1.0 - added support for makeNeutral?
|
2.1.0 - added support for makeNeutral?
|
||||||
2.1.1 - bug fixing for DCS 2.9x airfield retrofit
|
2.1.1 - bug fixing for DCS 2.9x airfield retrofit
|
||||||
2.2.0 - dmlZone:getCoalition() / masterowner adaptation for owner
|
2.2.0 - dmlZone:getCoalition() / masterowner adaptation for owner
|
||||||
|
2.3.0 - increased verbosity on persistence
|
||||||
|
- airfield delayed release after data load
|
||||||
|
- locked owner on start
|
||||||
|
- release after start
|
||||||
|
- redrawing airfields when releasing
|
||||||
|
- cleanup
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
-- init all airfields DB
|
-- init all airfields DB
|
||||||
@ -31,7 +37,6 @@ function airfield.collectAll()
|
|||||||
local dropped = 0
|
local dropped = 0
|
||||||
for idx, aBase in pairs(allBases) do
|
for idx, aBase in pairs(allBases) do
|
||||||
local entry = {}
|
local entry = {}
|
||||||
--local cat = Airbase.getCategory(aBase) -- DCS 2.9 hardened
|
|
||||||
-- ho! dcs 2.9.x retrofit screwed with Airfield.getCategory.
|
-- ho! dcs 2.9.x retrofit screwed with Airfield.getCategory.
|
||||||
local cat = aBase:getDesc().category
|
local cat = aBase:getDesc().category
|
||||||
-- cats: 0 = airfield, 1 = farp, 2 = ship
|
-- cats: 0 = airfield, 1 = farp, 2 = ship
|
||||||
@ -44,20 +49,18 @@ function airfield.collectAll()
|
|||||||
count = count + 1
|
count = count + 1
|
||||||
else
|
else
|
||||||
dropped = dropped + 1
|
dropped = dropped + 1
|
||||||
-- trigger.action.outText("***dropped airbase <" .. aBase:getName() .. ">, cat = <" .. cat .. ">", 30)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if airfield.verbose then
|
if airfield.verbose then
|
||||||
trigger.action.outText("+++airF: init - count = <" .. count .. ">, dropped = <" .. dropped .. ">", 30)
|
trigger.action.outText("+++airF: init - count = <" .. count .. ">, dropped = <" .. dropped .. ">", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- setting up airfield
|
-- setting up airfield
|
||||||
--
|
--
|
||||||
|
airfield.collector = {}
|
||||||
function airfield.createAirFieldFromZone(theZone)
|
function airfield.createAirFieldFromZone(theZone)
|
||||||
theZone.farps = theZone:getBoolFromZoneProperty("farps", false)
|
theZone.farps = theZone:getBoolFromZoneProperty("farps", false)
|
||||||
|
|
||||||
local filterCat = 0
|
local filterCat = 0
|
||||||
if (theZone.farps) then filterCat = {0, 1} end -- bases and farps
|
if (theZone.farps) then filterCat = {0, 1} end -- bases and farps
|
||||||
local p = theZone:getPoint()
|
local p = theZone:getPoint()
|
||||||
@ -65,17 +68,15 @@ function airfield.createAirFieldFromZone(theZone)
|
|||||||
theZone.airfield = theBase
|
theZone.airfield = theBase
|
||||||
theZone.afName = theBase:getName()
|
theZone.afName = theBase:getName()
|
||||||
|
|
||||||
-- set zone's owner
|
-- set zone's owner
|
||||||
theZone.owner = theBase:getCoalition()
|
theZone.owner = theBase:getCoalition()
|
||||||
theZone.mismatchCount = airfield.gracePeriod
|
theZone.mismatchCount = airfield.gracePeriod
|
||||||
if theZone.verbose or airfield.verbose then
|
if theZone.verbose or airfield.verbose then
|
||||||
trigger.action.outText("+++airF: airfield zone <" .. theZone.name .. "> associates with <" .. theZone.afName .. ">, current owner is <" .. theZone.owner .. ">", 30)
|
trigger.action.outText("+++airF: airfield zone <" .. theZone.name .. "> associates with <" .. theZone.afName .. ">, current owner is <" .. theZone.owner .. ">", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- methods
|
|
||||||
theZone.method = theZone:getStringFromZoneProperty("method", "inc")
|
theZone.method = theZone:getStringFromZoneProperty("method", "inc")
|
||||||
theZone.triggerMethod = theZone:getStringFromZoneProperty("triggerMethod", "change")
|
theZone.triggerMethod = theZone:getStringFromZoneProperty("triggerMethod", "change")
|
||||||
|
|
||||||
if theZone:hasProperty("red!") then
|
if theZone:hasProperty("red!") then
|
||||||
theZone.redCap = theZone:getStringFromZoneProperty("red!")
|
theZone.redCap = theZone:getStringFromZoneProperty("red!")
|
||||||
end
|
end
|
||||||
@ -92,23 +93,20 @@ function airfield.createAirFieldFromZone(theZone)
|
|||||||
theZone.makeBlue = theZone:getStringFromZoneProperty("makeBlue?", "<none>")
|
theZone.makeBlue = theZone:getStringFromZoneProperty("makeBlue?", "<none>")
|
||||||
theZone.lastMakeBlue = trigger.misc.getUserFlag(theZone.makeBlue)
|
theZone.lastMakeBlue = trigger.misc.getUserFlag(theZone.makeBlue)
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone:hasProperty("makeNeutral?") then
|
if theZone:hasProperty("makeNeutral?") then
|
||||||
theZone.makeNeutral = theZone:getStringFromZoneProperty("makeNeutral?", "<none>")
|
theZone.makeNeutral = theZone:getStringFromZoneProperty("makeNeutral?", "<none>")
|
||||||
theZone.lastMakeNeutral = trigger.misc.getUserFlag(theZone.makeNeutral)
|
theZone.lastMakeNeutral = trigger.misc.getUserFlag(theZone.makeNeutral)
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone:hasProperty("autoCap?") then
|
if theZone:hasProperty("autoCap?") then
|
||||||
theZone.autoCap = theZone:getStringFromZoneProperty("autoCap?", "<none>")
|
theZone.autoCap = theZone:getStringFromZoneProperty("autoCap?", "<none>")
|
||||||
theZone.lastAutoCap = trigger.misc.getUserFlag(theZone.autoCap)
|
theZone.lastAutoCap = trigger.misc.getUserFlag(theZone.autoCap)
|
||||||
end
|
end
|
||||||
|
|
||||||
theZone.directControl = theZone:getBoolFromZoneProperty("directControl", false)
|
theZone.directControl = theZone:getBoolFromZoneProperty("directControl", false)
|
||||||
|
|
||||||
if theZone.directControl then
|
if theZone.directControl then
|
||||||
airfield.assumeControl(theZone)
|
airfield.assumeControl(theZone)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- if fixed attribute, we switch to that color and keep it fixed.
|
-- if fixed attribute, we switch to that color and keep it fixed.
|
||||||
-- can be overridden by either makeXX or autoCap.
|
-- can be overridden by either makeXX or autoCap.
|
||||||
if theZone:hasProperty("fixed") then
|
if theZone:hasProperty("fixed") then
|
||||||
@ -144,6 +142,14 @@ function airfield.createAirFieldFromZone(theZone)
|
|||||||
|
|
||||||
airfield.showAirfield(theZone)
|
airfield.showAirfield(theZone)
|
||||||
|
|
||||||
|
theBase:autoCapture(false) -- lock down owner to avoid contested at beginning
|
||||||
|
-- set up collector to free ownership later
|
||||||
|
if theZone:hasProperty("fixed") then
|
||||||
|
airfield.collector[theBase] = false -- autocap off after delay
|
||||||
|
else
|
||||||
|
airfield.collector[theBase] = true
|
||||||
|
end
|
||||||
|
|
||||||
-- now mark this zone as handled
|
-- now mark this zone as handled
|
||||||
local entry = airfield.allAirfields[theZone.afName]
|
local entry = airfield.allAirfields[theZone.afName]
|
||||||
if not entry then
|
if not entry then
|
||||||
@ -179,7 +185,6 @@ function airfield.showAirfield(theZone)
|
|||||||
theZone.ownerMark = nil
|
theZone.ownerMark = nil
|
||||||
end
|
end
|
||||||
if not theZone.show then return end -- we don't show in map
|
if not theZone.show then return end -- we don't show in map
|
||||||
|
|
||||||
local lineColor = theZone.redLine -- {1.0, 0, 0, 1.0} -- red
|
local lineColor = theZone.redLine -- {1.0, 0, 0, 1.0} -- red
|
||||||
local fillColor = theZone.redFill -- {1.0, 0, 0, 0.2} -- red
|
local fillColor = theZone.redFill -- {1.0, 0, 0, 0.2} -- red
|
||||||
local owner = theZone:getCoalition() -- .owner
|
local owner = theZone:getCoalition() -- .owner
|
||||||
@ -190,10 +195,7 @@ function airfield.showAirfield(theZone)
|
|||||||
lineColor = theZone.neutralLine -- {0.8, 0.8, 0.8, 1.0}
|
lineColor = theZone.neutralLine -- {0.8, 0.8, 0.8, 1.0}
|
||||||
fillColor = theZone.neutralFill -- {0.8, 0.8, 0.8, 0.2}
|
fillColor = theZone.neutralFill -- {0.8, 0.8, 0.8, 0.2}
|
||||||
end
|
end
|
||||||
|
|
||||||
theZone.ownerMark = airfield.markAirfieldOnMap(theZone.airfield, lineColor, fillColor)
|
theZone.ownerMark = airfield.markAirfieldOnMap(theZone.airfield, lineColor, fillColor)
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function airfield.assumeControl(theZone)
|
function airfield.assumeControl(theZone)
|
||||||
@ -211,7 +213,6 @@ function airfield.relinquishControl(theZone)
|
|||||||
end
|
end
|
||||||
theBase:autoCapture(true) -- turn off autocap
|
theBase:autoCapture(true) -- turn off autocap
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- event handling
|
-- event handling
|
||||||
--
|
--
|
||||||
@ -252,7 +253,6 @@ function airfield.airfieldCaptured(theBase)
|
|||||||
if theZone.verbose or airfield.verbose then
|
if theZone.verbose or airfield.verbose then
|
||||||
trigger.action.outText("+++airF: capturing <" .. bName .. "> for zone <" .. theZone.name .. ">", 30)
|
trigger.action.outText("+++airF: capturing <" .. bName .. "> for zone <" .. theZone.name .. ">", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
local newCoa = theBase:getCoalition()
|
local newCoa = theBase:getCoalition()
|
||||||
theZone.owner = newCoa
|
theZone.owner = newCoa
|
||||||
|
|
||||||
@ -272,7 +272,6 @@ function airfield.airfieldCaptured(theBase)
|
|||||||
if theZone.blueCap and newCoa == 2 then
|
if theZone.blueCap and newCoa == 2 then
|
||||||
theZone:pollFlag(theZone.blueCap, theZone.method)
|
theZone:pollFlag(theZone.blueCap, theZone.method)
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function airfield:onEvent(event)
|
function airfield:onEvent(event)
|
||||||
@ -347,7 +346,6 @@ function airfield.update()
|
|||||||
end
|
end
|
||||||
theZone.owner = 0
|
theZone.owner = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
if theZone.autoCap and theZone:testZoneFlag(theZone.autoCap, theZone.triggerMethod, "lastAutoCap") then
|
if theZone.autoCap and theZone:testZoneFlag(theZone.autoCap, theZone.triggerMethod, "lastAutoCap") then
|
||||||
if theAirfield:autoCaptureIsOn() then
|
if theAirfield:autoCaptureIsOn() then
|
||||||
@ -386,16 +384,12 @@ function airfield.GC()
|
|||||||
trigger.action.outText("+++airF: corrected ownership after grace period", 30)
|
trigger.action.outText("+++airF: corrected ownership after grace period", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- LOAD / SAVE
|
-- LOAD / SAVE
|
||||||
--
|
--
|
||||||
|
|
||||||
function airfield.saveData()
|
function airfield.saveData()
|
||||||
local theData = {}
|
local theData = {}
|
||||||
local allAF = {}
|
local allAF = {}
|
||||||
@ -411,6 +405,21 @@ function airfield.saveData()
|
|||||||
return theData
|
return theData
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function airfield.releaseFields(releaseMe)
|
||||||
|
for theAF, rel in pairs(releaseMe) do
|
||||||
|
theAF:autoCapture(rel)
|
||||||
|
if airfield.verbose then
|
||||||
|
trigger.action.outText("+++airF: releasing AF <" .. theAF:getName() .. "> to saved cap state <" .. dcsCommon.bool2Text(rel) .. ">", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for name, theZone in pairs(airfield.myAirfields) do
|
||||||
|
airfield.showAirfield(theZone)
|
||||||
|
if airfield.verbose or theZone.verbose then
|
||||||
|
trigger.action.outText("+++airF: redrawing <" .. theZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function airfield.loadData()
|
function airfield.loadData()
|
||||||
if not persistence then return end
|
if not persistence then return end
|
||||||
local theData = persistence.getSavedDataForModule("airfield")
|
local theData = persistence.getSavedDataForModule("airfield")
|
||||||
@ -418,6 +427,7 @@ function airfield.loadData()
|
|||||||
if airfield.verbose then
|
if airfield.verbose then
|
||||||
trigger.action.outText("+++airF persistence: no save data received, skipping.", 30)
|
trigger.action.outText("+++airF persistence: no save data received, skipping.", 30)
|
||||||
end
|
end
|
||||||
|
timer.scheduleFunction(airfield.releaseFields, airfield.collector, timer.getTime() + 2)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -426,9 +436,12 @@ function airfield.loadData()
|
|||||||
if airfield.verbose then
|
if airfield.verbose then
|
||||||
trigger.action.outText("+++airF persistence: no airfield data, skipping", 30)
|
trigger.action.outText("+++airF persistence: no airfield data, skipping", 30)
|
||||||
end
|
end
|
||||||
|
timer.scheduleFunction(airfield.releaseFields, airfield.collector, timer.getTime() + 2)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
airfield.collector = {} -- overwrite existing
|
||||||
|
|
||||||
for theName, AFData in pairs(allAF) do
|
for theName, AFData in pairs(allAF) do
|
||||||
local theZone = airfield.myAirfields[theName]
|
local theZone = airfield.myAirfields[theName]
|
||||||
if theZone then
|
if theZone then
|
||||||
@ -438,20 +451,22 @@ function airfield.loadData()
|
|||||||
theAirfield:autoCapture(false)
|
theAirfield:autoCapture(false)
|
||||||
theAirfield:setCoalition(AFData.owner)
|
theAirfield:setCoalition(AFData.owner)
|
||||||
theZone.owner = AFData.owner
|
theZone.owner = AFData.owner
|
||||||
|
if airfield.verbose or theZone.verbose then
|
||||||
|
trigger.action.outText("+++airF: setting AF Zone <" .. theZone.name .. ">, owner from file to <" .. theZone.owner .. ">", 30)
|
||||||
|
end
|
||||||
-- set ownedBy#
|
-- set ownedBy#
|
||||||
if theZone.ownedBy then
|
if theZone.ownedBy then
|
||||||
trigger.action.setUserFlag(theZone.ownedBy, theZone.owner)
|
trigger.action.setUserFlag(theZone.ownedBy, theZone.owner)
|
||||||
end
|
end
|
||||||
-- set owning mode: autocap or direct
|
-- set owning mode: autocap or direct
|
||||||
theAirfield:autoCapture(AFData.autocapActive)
|
--theAirfield:autoCapture(AFData.autocapActive)
|
||||||
|
airfield.collector[theAirfield] = AFData.autocapActive
|
||||||
else
|
else
|
||||||
trigger.action.outText("+++airF persistence: cannot synch airfield <" .. theName .. ">, skipping", 40)
|
trigger.action.outText("+++airF persistence: cannot synch airfield <" .. theName .. ">, skipping", 40)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
timer.scheduleFunction(airfield.releaseFields, airfield.collector, timer.getTime() + 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- start up
|
-- start up
|
||||||
--
|
--
|
||||||
@ -460,9 +475,7 @@ function airfield.readConfig()
|
|||||||
if not theZone then
|
if not theZone then
|
||||||
theZone = cfxZones.createSimpleZone("airfieldConfig")
|
theZone = cfxZones.createSimpleZone("airfieldConfig")
|
||||||
end
|
end
|
||||||
airfield.verbose = theZone.verbose
|
airfield.verbose = theZone.verbose
|
||||||
-- airfield.farps = theZone:getBoolFromZoneProperty("farps", false)
|
|
||||||
|
|
||||||
-- colors for line and fill
|
-- colors for line and fill
|
||||||
airfield.redLine = theZone:getRGBAVectorFromZoneProperty("redLine", {1.0, 0, 0, 1.0})
|
airfield.redLine = theZone:getRGBAVectorFromZoneProperty("redLine", {1.0, 0, 0, 1.0})
|
||||||
airfield.redFill = theZone:getRGBAVectorFromZoneProperty("redFill", {1.0, 0, 0, 0.2})
|
airfield.redFill = theZone:getRGBAVectorFromZoneProperty("redFill", {1.0, 0, 0, 0.2})
|
||||||
@ -470,7 +483,6 @@ function airfield.readConfig()
|
|||||||
airfield.blueFill = theZone:getRGBAVectorFromZoneProperty("blueFill", {0.0, 0, 1.0, 0.2})
|
airfield.blueFill = theZone:getRGBAVectorFromZoneProperty("blueFill", {0.0, 0, 1.0, 0.2})
|
||||||
airfield.neutralLine = theZone:getRGBAVectorFromZoneProperty("neutralLine", {0.8, 0.8, 0.8, 1.0})
|
airfield.neutralLine = theZone:getRGBAVectorFromZoneProperty("neutralLine", {0.8, 0.8, 0.8, 1.0})
|
||||||
airfield.neutralFill = theZone:getRGBAVectorFromZoneProperty("neutralFill", {0.8, 0.8, 0.8, 0.2})
|
airfield.neutralFill = theZone:getRGBAVectorFromZoneProperty("neutralFill", {0.8, 0.8, 0.8, 0.2})
|
||||||
|
|
||||||
airfield.showAll = theZone:getBoolFromZoneProperty("show", false)
|
airfield.showAll = theZone:getBoolFromZoneProperty("show", false)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -485,13 +497,10 @@ end
|
|||||||
function airfield.start()
|
function airfield.start()
|
||||||
if not dcsCommon.libCheck("cfx airfield", airfield.requiredLibs)
|
if not dcsCommon.libCheck("cfx airfield", airfield.requiredLibs)
|
||||||
then return false end
|
then return false end
|
||||||
|
|
||||||
-- set up DB
|
-- set up DB
|
||||||
airfield.collectAll()
|
airfield.collectAll()
|
||||||
|
|
||||||
-- read config
|
-- read config
|
||||||
airfield.readConfig()
|
airfield.readConfig()
|
||||||
|
|
||||||
-- read bases
|
-- read bases
|
||||||
local abZones = cfxZones.zonesWithProperty("airfield")
|
local abZones = cfxZones.zonesWithProperty("airfield")
|
||||||
for idx, aZone in pairs(abZones) do
|
for idx, aZone in pairs(abZones) do
|
||||||
@ -512,6 +521,8 @@ function airfield.start()
|
|||||||
persistence.registerModule("airfield", callbacks)
|
persistence.registerModule("airfield", callbacks)
|
||||||
-- now load my data
|
-- now load my data
|
||||||
airfield.loadData()
|
airfield.loadData()
|
||||||
|
else
|
||||||
|
timer.scheduleFunction(airfield.releaseFields, airfield.collector, timer.getTime() + 2) -- release airfields when not loaded from storage
|
||||||
end
|
end
|
||||||
|
|
||||||
-- start update in 1 second
|
-- start update in 1 second
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
autoCSAR = {}
|
autoCSAR = {}
|
||||||
autoCSAR.version = "2.2.0"
|
autoCSAR.version = "2.2.1"
|
||||||
autoCSAR.requiredLibs = {
|
autoCSAR.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
"cfxZones", -- Zones, of course
|
"cfxZones", -- Zones, of course
|
||||||
@ -19,7 +19,8 @@ autoCSAR.trackedEjects = {} -- we start tracking on eject
|
|||||||
2.1.0 - persistence support
|
2.1.0 - persistence support
|
||||||
2.2.0 - new noExploit option in config
|
2.2.0 - new noExploit option in config
|
||||||
- no csar mission if pilot lands too close to airbase or farp
|
- no csar mission if pilot lands too close to airbase or farp
|
||||||
and noExploit is on
|
and noExploit is on
|
||||||
|
2.2.1 - DCS hardening for isExist
|
||||||
--]]--
|
--]]--
|
||||||
autoCSAR.forbidden = {} -- indexed by name, contains point
|
autoCSAR.forbidden = {} -- indexed by name, contains point
|
||||||
autoCSAR.killDist = 2100 -- meters from center of forbidden
|
autoCSAR.killDist = 2100 -- meters from center of forbidden
|
||||||
@ -173,7 +174,9 @@ function autoCSAR:onEvent(event)
|
|||||||
local coa = event.initiator:getCoalition()
|
local coa = event.initiator:getCoalition()
|
||||||
-- see if pilot has ejector seat and prepare to connect one with the other
|
-- see if pilot has ejector seat and prepare to connect one with the other
|
||||||
local info = nil
|
local info = nil
|
||||||
if event.target and event.target:isExist() then
|
if event.target
|
||||||
|
and event.target.isExist
|
||||||
|
and event.target:isExist() then -- DCS hardening
|
||||||
info = {}
|
info = {}
|
||||||
info.coa = coa
|
info.coa = coa
|
||||||
info.seat = event.target
|
info.seat = event.target
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cloneZones = {}
|
cloneZones = {}
|
||||||
cloneZones.version = "2.4.0"
|
cloneZones.version = "2.5.0"
|
||||||
cloneZones.verbose = false
|
cloneZones.verbose = false
|
||||||
cloneZones.requiredLibs = {
|
cloneZones.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
@ -57,6 +57,8 @@ cloneZones.respawnOnGroupID = true
|
|||||||
path) with wiper module
|
path) with wiper module
|
||||||
- using "wipe?" will now create a warning
|
- using "wipe?" will now create a warning
|
||||||
2.4.0 - reworked masterOwner to fit with dmlZone
|
2.4.0 - reworked masterOwner to fit with dmlZone
|
||||||
|
2.5.0 - re-establish spawn zone in persistence to provide
|
||||||
|
empty! detection through saves (missed hasClones)
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -90,7 +92,6 @@ function cloneZones.invokeCallbacks(theZone, reason, args)
|
|||||||
if not theZone then return end
|
if not theZone then return end
|
||||||
if not reason then reason = "<none>" end
|
if not reason then reason = "<none>" end
|
||||||
if not args then args = {} end
|
if not args then args = {} end
|
||||||
|
|
||||||
-- invoke anyone who wants to know that a group
|
-- invoke anyone who wants to know that a group
|
||||||
-- of people was rescued.
|
-- of people was rescued.
|
||||||
for idx, cb in pairs(cloneZones.callbacks) do
|
for idx, cb in pairs(cloneZones.callbacks) do
|
||||||
@ -105,7 +106,6 @@ function cloneZones.partOfGroupDataInZone(theZone, theUnits)
|
|||||||
local zP = cfxZones.getPoint(theZone)
|
local zP = cfxZones.getPoint(theZone)
|
||||||
zP = theZone:getDCSOrigin() -- don't use getPoint now.
|
zP = theZone:getDCSOrigin() -- don't use getPoint now.
|
||||||
zP.y = 0
|
zP.y = 0
|
||||||
|
|
||||||
for idx, aUnit in pairs(theUnits) do
|
for idx, aUnit in pairs(theUnits) do
|
||||||
local uP = {}
|
local uP = {}
|
||||||
uP.x = aUnit.x
|
uP.x = aUnit.x
|
||||||
@ -197,7 +197,6 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
|||||||
table.insert(theZone.myStatics, aStatic)
|
table.insert(theZone.myStatics, aStatic)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
cloneZones.despawnAll(theZone)
|
cloneZones.despawnAll(theZone)
|
||||||
if (#theZone.cloneNames + #theZone.staticNames) < 1 then
|
if (#theZone.cloneNames + #theZone.staticNames) < 1 then
|
||||||
if cloneZones.verbose then
|
if cloneZones.verbose then
|
||||||
@ -210,18 +209,12 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
|||||||
trigger.action.outText(theZone.name .. " clone template saved", 30)
|
trigger.action.outText(theZone.name .. " clone template saved", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- declutter
|
|
||||||
theZone.declutter = theZone:getBoolFromZoneProperty("declutter", false)
|
theZone.declutter = theZone:getBoolFromZoneProperty("declutter", false)
|
||||||
|
|
||||||
-- watchflags
|
|
||||||
theZone.cloneTriggerMethod = theZone:getStringFromZoneProperty("triggerMethod", "change")
|
theZone.cloneTriggerMethod = theZone:getStringFromZoneProperty("triggerMethod", "change")
|
||||||
|
|
||||||
if theZone:hasProperty("cloneTriggerMethod") then
|
if theZone:hasProperty("cloneTriggerMethod") then
|
||||||
theZone.cloneTriggerMethod = theZone:getStringFromZoneProperty("cloneTriggerMethod", "change")
|
theZone.cloneTriggerMethod = theZone:getStringFromZoneProperty("cloneTriggerMethod", "change")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- f? and spawn? and other synonyms map to the same
|
|
||||||
if theZone:hasProperty("f?") then
|
if theZone:hasProperty("f?") then
|
||||||
theZone.spawnFlag = theZone:getStringFromZoneProperty("f?", "none")
|
theZone.spawnFlag = theZone:getStringFromZoneProperty("f?", "none")
|
||||||
elseif theZone:hasProperty("in?") then
|
elseif theZone:hasProperty("in?") then
|
||||||
@ -231,12 +224,10 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
|||||||
elseif theZone:hasProperty("clone?") then
|
elseif theZone:hasProperty("clone?") then
|
||||||
theZone.spawnFlag = theZone:getStringFromZoneProperty("clone?", "none")
|
theZone.spawnFlag = theZone:getStringFromZoneProperty("clone?", "none")
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone.spawnFlag then
|
if theZone.spawnFlag then
|
||||||
theZone.lastSpawnValue = theZone:getFlagValue(theZone.spawnFlag)
|
theZone.lastSpawnValue = theZone:getFlagValue(theZone.spawnFlag)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- deSpawn?
|
|
||||||
if theZone:hasProperty("deSpawn?") then
|
if theZone:hasProperty("deSpawn?") then
|
||||||
theZone.deSpawnFlag = theZone:getStringFromZoneProperty( "deSpawn?", "none")
|
theZone.deSpawnFlag = theZone:getStringFromZoneProperty( "deSpawn?", "none")
|
||||||
elseif theZone:hasProperty("deClone?") then
|
elseif theZone:hasProperty("deClone?") then
|
||||||
@ -259,7 +250,7 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
|||||||
theZone.onStart = theZone:getBoolFromZoneProperty("onStart", false)
|
theZone.onStart = theZone:getBoolFromZoneProperty("onStart", false)
|
||||||
theZone.moveRoute = theZone:getBoolFromZoneProperty("moveRoute", false)
|
theZone.moveRoute = theZone:getBoolFromZoneProperty("moveRoute", false)
|
||||||
theZone.preWipe = theZone:getBoolFromZoneProperty("preWipe", false)
|
theZone.preWipe = theZone:getBoolFromZoneProperty("preWipe", false)
|
||||||
|
|
||||||
if theZone:hasProperty("empty!") then
|
if theZone:hasProperty("empty!") then
|
||||||
theZone.emptyBangFlag = theZone:getStringFromZoneProperty("empty!", "<None>") -- note string on number default
|
theZone.emptyBangFlag = theZone:getStringFromZoneProperty("empty!", "<None>") -- note string on number default
|
||||||
end
|
end
|
||||||
@ -267,30 +258,7 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
|||||||
theZone.cloneMethod = theZone:getStringFromZoneProperty("cloneMethod", "inc")
|
theZone.cloneMethod = theZone:getStringFromZoneProperty("cloneMethod", "inc")
|
||||||
if theZone:hasProperty("method") then
|
if theZone:hasProperty("method") then
|
||||||
theZone.cloneMethod = theZone:getStringFromZoneProperty("method", "inc") -- note string on number default
|
theZone.cloneMethod = theZone:getStringFromZoneProperty("method", "inc") -- note string on number default
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[--
|
|
||||||
if theZone:hasProperty("masterOwner") then
|
|
||||||
theZone.masterOwner = theZone:getStringFromZoneProperty( "masterOwner", "*")
|
|
||||||
theZone.masterOwner = dcsCommon.trim(theZone.masterOwner)
|
|
||||||
if theZone.masterOwner == "*" then
|
|
||||||
theZone.masterOwner = theZone.name
|
|
||||||
if theZone.verbose then
|
|
||||||
trigger.action.outText("+++clnZ: masterOwner for <" .. theZone.name .. "> set successfully to to itself, currently owned by faction <" .. theZone.owner .. ">", 30)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if theZone.verbose or cloneZones.verbose then
|
|
||||||
trigger.action.outText("+++clnZ: ownership of <" .. theZone.name .. "> tied to zone <" .. theZone.masterOwner .. ">", 30)
|
|
||||||
end
|
|
||||||
-- check that the zone exists in DCS
|
|
||||||
local theMaster = cfxZones.getZoneByName(theZone.masterOwner)
|
|
||||||
if not theMaster then
|
|
||||||
trigger.action.outText("clnZ: WARNING: cloner's <" .. theZone.name .. "> master owner named <" .. theZone.masterOwner .. "> does not exist!", 30)
|
|
||||||
end
|
|
||||||
theZone.masterOwner = theMaster
|
|
||||||
end
|
|
||||||
--]]--
|
|
||||||
|
|
||||||
theZone.turn = theZone:getNumberFromZoneProperty("turn", 0)
|
theZone.turn = theZone:getNumberFromZoneProperty("turn", 0)
|
||||||
|
|
||||||
-- interface to groupTracker
|
-- interface to groupTracker
|
||||||
@ -329,7 +297,6 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
|||||||
theZone.inBuiltup = theZone:getNumberFromZoneProperty("inBuiltup", 10) -- 10 meter radius must be free -- small houses
|
theZone.inBuiltup = theZone:getNumberFromZoneProperty("inBuiltup", 10) -- 10 meter radius must be free -- small houses
|
||||||
end
|
end
|
||||||
theZone.rndHeading = theZone:getBoolFromZoneProperty("rndHeading", false)
|
theZone.rndHeading = theZone:getBoolFromZoneProperty("rndHeading", false)
|
||||||
|
|
||||||
theZone.onRoad = theZone:getBoolFromZoneProperty("onRoad", false)
|
theZone.onRoad = theZone:getBoolFromZoneProperty("onRoad", false)
|
||||||
theZone.onPerimeter = theZone:getBoolFromZoneProperty("onPerimeter", false)
|
theZone.onPerimeter = theZone:getBoolFromZoneProperty("onPerimeter", false)
|
||||||
|
|
||||||
@ -338,15 +305,12 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
|||||||
theZone.identical = theZone:getBoolFromZoneProperty("identical", false)
|
theZone.identical = theZone:getBoolFromZoneProperty("identical", false)
|
||||||
if theZone.identical == false then theZone.identical = nil end
|
if theZone.identical == false then theZone.identical = nil end
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone:hasProperty("nameScheme") then
|
if theZone:hasProperty("nameScheme") then
|
||||||
theZone.nameScheme = theZone:getStringFromZoneProperty( "nameScheme", "<o>-<uid>") -- default to [<original name> "-" <uuid>]
|
theZone.nameScheme = theZone:getStringFromZoneProperty( "nameScheme", "<o>-<uid>") -- default to [<original name> "-" <uuid>]
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone:hasProperty("groupScheme") then
|
if theZone:hasProperty("groupScheme") then
|
||||||
theZone.groupScheme = theZone:getStringFromZoneProperty("groupScheme", "<o>-<uid>")
|
theZone.groupScheme = theZone:getStringFromZoneProperty("groupScheme", "<o>-<uid>")
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone.identical and theZone.nameScheme then
|
if theZone.identical and theZone.nameScheme then
|
||||||
trigger.action.outText("+++clnZ: WARNING - clone zone <" .. theZone.name .. "> has both IDENTICAL and NAMESCHEME/GROUPSCHEME attributes. nameScheme is ignored.", 30)
|
trigger.action.outText("+++clnZ: WARNING - clone zone <" .. theZone.name .. "> has both IDENTICAL and NAMESCHEME/GROUPSCHEME attributes. nameScheme is ignored.", 30)
|
||||||
theZone.nameScheme = nil
|
theZone.nameScheme = nil
|
||||||
@ -539,7 +503,6 @@ function cloneZones.updateLocationsInGroupData(theData, zoneDelta, adjustAllWayp
|
|||||||
-- now process departing slot if given
|
-- now process departing slot if given
|
||||||
if departFromAerodrome then
|
if departFromAerodrome then
|
||||||
-- we may need alt from land to add here, maybe later
|
-- we may need alt from land to add here, maybe later
|
||||||
|
|
||||||
-- now process parking slots, and choose closest slot
|
-- now process parking slots, and choose closest slot
|
||||||
-- per unit's location
|
-- per unit's location
|
||||||
if fromParking then
|
if fromParking then
|
||||||
@ -658,11 +621,9 @@ function cloneZones.uniqueNameStaticData(theData, theCloneZone, sourcename)
|
|||||||
if theCloneZone and theCloneZone.nameScheme then
|
if theCloneZone and theCloneZone.nameScheme then
|
||||||
local schema = theCloneZone.nameScheme
|
local schema = theCloneZone.nameScheme
|
||||||
newName, iterCount = cloneZones.nameFromSchema(schema, theData.name, theCloneZone, sourceName, iterCount)
|
newName, iterCount = cloneZones.nameFromSchema(schema, theData.name, theCloneZone, sourceName, iterCount)
|
||||||
|
|
||||||
if theCloneZone.verbose then
|
if theCloneZone.verbose then
|
||||||
trigger.action.outText("clnZ: zone <" .. theCloneZone.name .. "> static schema <" .. schema .. ">: <" .. theData.name .. "> --> <" .. newName .. ">", 30)
|
trigger.action.outText("clnZ: zone <" .. theCloneZone.name .. "> static schema <" .. schema .. ">: <" .. theData.name .. "> --> <" .. newName .. ">", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
theData.name = newName -- dcsCommon.uuid(theData.name)
|
theData.name = newName -- dcsCommon.uuid(theData.name)
|
||||||
else
|
else
|
||||||
-- default naming scheme: <name>-<uuid>
|
-- default naming scheme: <name>-<uuid>
|
||||||
@ -697,19 +658,6 @@ end
|
|||||||
|
|
||||||
function cloneZones.resolveOwnership(spawnZone, ctry)
|
function cloneZones.resolveOwnership(spawnZone, ctry)
|
||||||
if not spawnZone.masterOwner then return ctry end -- old code
|
if not spawnZone.masterOwner then return ctry end -- old code
|
||||||
--[[--
|
|
||||||
local masterZone = cfxZones.getZoneByName(spawnZone.masterOwner)
|
|
||||||
if not masterZone then
|
|
||||||
trigger.action.outText("+++clnZ: cloner " .. spawnZone.name .. " could not find master owner <" .. spawnZone.masterOwner .. ">", 30)
|
|
||||||
return ctry
|
|
||||||
end
|
|
||||||
|
|
||||||
if not masterZone.owner then
|
|
||||||
return ctry
|
|
||||||
end
|
|
||||||
--]]--
|
|
||||||
|
|
||||||
-- ctry = dcsCommon.getACountryForCoalition(masterZone.owner)
|
|
||||||
ctry = dcsCommon.getACountryForCoalition(spawnZone:getCoalition())
|
ctry = dcsCommon.getACountryForCoalition(spawnZone:getCoalition())
|
||||||
return ctry
|
return ctry
|
||||||
end
|
end
|
||||||
@ -1249,6 +1197,8 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
|
|||||||
|
|
||||||
-- clone for persistence
|
-- clone for persistence
|
||||||
local theData = dcsCommon.clone(rawData)
|
local theData = dcsCommon.clone(rawData)
|
||||||
|
-- remember the zone that spawned this particular group
|
||||||
|
theData.CZspawner = spawnZone.name
|
||||||
cloneZones.allClones[rawData.name] = theData
|
cloneZones.allClones[rawData.name] = theData
|
||||||
|
|
||||||
if cloneZones.verbose or spawnZone.verbose then
|
if cloneZones.verbose or spawnZone.verbose then
|
||||||
@ -1273,7 +1223,6 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
|
|||||||
info.timeLimit = now + timeLimit
|
info.timeLimit = now + timeLimit
|
||||||
info.cloneZone = spawnZone
|
info.cloneZone = spawnZone
|
||||||
table.insert(cloneZones.despawnPlan, info)
|
table.insert(cloneZones.despawnPlan, info)
|
||||||
-- trigger.action.outText("+++clne: scheduled auto-despawn for <" .. info.name .. "> in <" .. timeLimit .. "> secs", 30)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- turn off AI if disabled
|
-- turn off AI if disabled
|
||||||
@ -1446,6 +1395,7 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
|
|||||||
rawData.cty = ctry
|
rawData.cty = ctry
|
||||||
-- save for persistence
|
-- save for persistence
|
||||||
local theData = dcsCommon.clone(rawData)
|
local theData = dcsCommon.clone(rawData)
|
||||||
|
theData.CZspawner = spawnZone.name -- remember spawner
|
||||||
cloneZones.allCObjects[rawData.name] = theData
|
cloneZones.allCObjects[rawData.name] = theData
|
||||||
|
|
||||||
if cloneZones.verbose or spawnZone.verbose then
|
if cloneZones.verbose or spawnZone.verbose then
|
||||||
@ -1466,7 +1416,6 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
|
|||||||
info.timeLimit = now + timeLimit
|
info.timeLimit = now + timeLimit
|
||||||
info.cloneZone = spawnZone
|
info.cloneZone = spawnZone
|
||||||
table.insert(cloneZones.despawnPlan, info)
|
table.insert(cloneZones.despawnPlan, info)
|
||||||
-- trigger.action.outText("+++clne: scheduled auto-despawn for OBJECT <" .. info.name .. "> in <" .. timeLimit .. "> secs", 30)
|
|
||||||
end
|
end
|
||||||
-- we don't mix groups with units, so no lookup tables for
|
-- we don't mix groups with units, so no lookup tables for
|
||||||
-- statics
|
-- statics
|
||||||
@ -1528,9 +1477,7 @@ end
|
|||||||
function cloneZones.spawnWithSpawner(theZone)
|
function cloneZones.spawnWithSpawner(theZone)
|
||||||
-- analog to cfxSpawnZones.spawnWithSpawner(theSpawner)
|
-- analog to cfxSpawnZones.spawnWithSpawner(theSpawner)
|
||||||
-- glue code for helo troops and other modules
|
-- glue code for helo troops and other modules
|
||||||
|
|
||||||
-- we may want to check if cloner isn't emtpy first
|
-- we may want to check if cloner isn't emtpy first
|
||||||
|
|
||||||
cloneZones.spawnWithCloner(theZone)
|
cloneZones.spawnWithCloner(theZone)
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1702,15 +1649,6 @@ end
|
|||||||
|
|
||||||
function cloneZones.resolveOwningCoalition(theZone)
|
function cloneZones.resolveOwningCoalition(theZone)
|
||||||
return theZone:getCoalition()
|
return theZone:getCoalition()
|
||||||
--[[--
|
|
||||||
if not theZone.masterOwner then return theZone.owner end
|
|
||||||
local masterZone = cfxZones.getZoneByName(theZone.masterOwner)
|
|
||||||
if not masterZone then
|
|
||||||
trigger.action.outText("+++clnZ: cloner " .. theZone.name .. " could not find master owner <" .. theZone.masterOwner .. ">", 30)
|
|
||||||
return theZone.owner
|
|
||||||
end
|
|
||||||
return masterZone.owner
|
|
||||||
--]]--
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function cloneZones.getRequestableClonersInRange(aPoint, aRange, aSide)
|
function cloneZones.getRequestableClonersInRange(aPoint, aRange, aSide)
|
||||||
@ -1821,7 +1759,6 @@ function cloneZones.update()
|
|||||||
local filtered = {}
|
local filtered = {}
|
||||||
for idx, theInfo in pairs(cloneZones.despawnPlan) do
|
for idx, theInfo in pairs(cloneZones.despawnPlan) do
|
||||||
if theInfo.timeLimit < now then
|
if theInfo.timeLimit < now then
|
||||||
-- trigger.action.outText("+++clne: auto-despawning <" .. theInfo.name .. ">", 30)
|
|
||||||
if theInfo.isObject then
|
if theInfo.isObject then
|
||||||
-- dealloc static object
|
-- dealloc static object
|
||||||
local theObject = theInfo.theGroup
|
local theObject = theInfo.theGroup
|
||||||
@ -1857,7 +1794,6 @@ function cloneZones.doOnStart()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Regular GC and housekeeping
|
-- Regular GC and housekeeping
|
||||||
--
|
--
|
||||||
@ -1884,7 +1820,6 @@ function cloneZones.GC()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
cloneZones.allClones = filteredAttackers
|
cloneZones.allClones = filteredAttackers
|
||||||
|
|
||||||
filteredAttackers = {}
|
filteredAttackers = {}
|
||||||
for gName, gData in pairs (cloneZones.allCObjects) do
|
for gName, gData in pairs (cloneZones.allCObjects) do
|
||||||
-- all we need to do is get the group of that name
|
-- all we need to do is get the group of that name
|
||||||
@ -1904,8 +1839,6 @@ function cloneZones.houseKeeping()
|
|||||||
timer.scheduleFunction(cloneZones.houseKeeping, {}, timer.getTime() + 5 * 60) -- every 5 minutes
|
timer.scheduleFunction(cloneZones.houseKeeping, {}, timer.getTime() + 5 * 60) -- every 5 minutes
|
||||||
cloneZones.GC()
|
cloneZones.GC()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- LOAD / SAVE
|
-- LOAD / SAVE
|
||||||
--
|
--
|
||||||
@ -1969,7 +1902,7 @@ function cloneZones.saveData()
|
|||||||
cData.myUniqueCounter = theCloner.myUniqueCounter
|
cData.myUniqueCounter = theCloner.myUniqueCounter
|
||||||
cData.oSize = theCloner.oSize
|
cData.oSize = theCloner.oSize
|
||||||
cData.lastSize = theCloner.lastSize
|
cData.lastSize = theCloner.lastSize
|
||||||
-- mySpawns: all groups i'm curently observing for empty!
|
-- mySpawns: all groups I'm curently observing for empty!
|
||||||
-- myStatics: dto for objects
|
-- myStatics: dto for objects
|
||||||
local mySpawns = {}
|
local mySpawns = {}
|
||||||
for idx, aGroup in pairs(theCloner.mySpawns) do
|
for idx, aGroup in pairs(theCloner.mySpawns) do
|
||||||
@ -2071,6 +2004,7 @@ function cloneZones.loadData()
|
|||||||
local theGroup = Group.getByName(aName)
|
local theGroup = Group.getByName(aName)
|
||||||
if theGroup then
|
if theGroup then
|
||||||
table.insert(mySpawns, theGroup)
|
table.insert(mySpawns, theGroup)
|
||||||
|
theCloner.hasClones = true -- was missing!
|
||||||
else
|
else
|
||||||
trigger.action.outText("+++clnZ - persistence: can't reconnect cloner <" .. cName .. "> with clone group <".. aName .. ">", 30)
|
trigger.action.outText("+++clnZ - persistence: can't reconnect cloner <" .. cName .. "> with clone group <".. aName .. ">", 30)
|
||||||
end
|
end
|
||||||
@ -2082,6 +2016,7 @@ function cloneZones.loadData()
|
|||||||
local theStatic = StaticObject.getByName(aName)
|
local theStatic = StaticObject.getByName(aName)
|
||||||
if theStatic then
|
if theStatic then
|
||||||
table.insert(myStatics, theStatic)
|
table.insert(myStatics, theStatic)
|
||||||
|
theCloner.hasClones = true -- was missing!S
|
||||||
else
|
else
|
||||||
trigger.action.outText("+++clnZ - persistence: can't reconnect cloner <" .. cName .. "> with static <".. aName .. ">", 30)
|
trigger.action.outText("+++clnZ - persistence: can't reconnect cloner <" .. cName .. "> with static <".. aName .. ">", 30)
|
||||||
end
|
end
|
||||||
@ -2115,24 +2050,16 @@ function cloneZones.readConfigZone()
|
|||||||
end
|
end
|
||||||
theZone = cfxZones.createSimpleZone("cloneZonesConfig")
|
theZone = cfxZones.createSimpleZone("cloneZonesConfig")
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone:hasProperty("uniqueCount") then
|
if theZone:hasProperty("uniqueCount") then
|
||||||
cloneZones.uniqueCounter = theZone:getNumberFromZoneProperty("uniqueCount", cloneZone.uniqueCounter)
|
cloneZones.uniqueCounter = theZone:getNumberFromZoneProperty("uniqueCount", cloneZone.uniqueCounter)
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone:hasProperty("localCount") then
|
if theZone:hasProperty("localCount") then
|
||||||
cloneZones.lclUniqueCounter = theZone:getNumberFromZoneProperty("localCount", cloneZone.lclUniqueCounter)
|
cloneZones.lclUniqueCounter = theZone:getNumberFromZoneProperty("localCount", cloneZone.lclUniqueCounter)
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone:hasProperty("globalCount") then
|
if theZone:hasProperty("globalCount") then
|
||||||
cloneZones.globalCounter = theZone:getNumberFromZoneProperty("globalCount", cloneZone.globalCounter)
|
cloneZones.globalCounter = theZone:getNumberFromZoneProperty("globalCount", cloneZone.globalCounter)
|
||||||
end
|
end
|
||||||
|
cloneZones.verbose = theZone.verbose
|
||||||
cloneZones.verbose = theZone:getBoolFromZoneProperty("verbose", false)
|
|
||||||
|
|
||||||
if cloneZones.verbose then
|
|
||||||
trigger.action.outText("+++clnZ: read config", 30)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function cloneZones.start()
|
function cloneZones.start()
|
||||||
@ -2201,4 +2128,5 @@ end
|
|||||||
make example where transport can be different plane types but have same name
|
make example where transport can be different plane types but have same name
|
||||||
|
|
||||||
support 'orders' to complete replace routes, and pass to groundCommander like spawner. only for ground troops
|
support 'orders' to complete replace routes, and pass to groundCommander like spawner. only for ground troops
|
||||||
|
maxCycles - maximum number of clone cycles. emulate with countdown?
|
||||||
--]]--
|
--]]--
|
||||||
@ -1,5 +1,5 @@
|
|||||||
cfxHeloTroops = {}
|
cfxHeloTroops = {}
|
||||||
cfxHeloTroops.version = "3.1.3"
|
cfxHeloTroops.version = "3.1.5"
|
||||||
cfxHeloTroops.verbose = false
|
cfxHeloTroops.verbose = false
|
||||||
cfxHeloTroops.autoDrop = true
|
cfxHeloTroops.autoDrop = true
|
||||||
cfxHeloTroops.autoPickup = false
|
cfxHeloTroops.autoPickup = false
|
||||||
@ -23,7 +23,8 @@ cfxHeloTroops.requestRange = 500 -- meters
|
|||||||
3.1.3 - decycled structures (destination zone) on save
|
3.1.3 - decycled structures (destination zone) on save
|
||||||
- upcycled structures (destination) on load
|
- upcycled structures (destination) on load
|
||||||
- loadSound and disembarkSound
|
- loadSound and disembarkSound
|
||||||
|
3.1.4 - guarding destination access in save
|
||||||
|
3.1.5 - more guarding of destination access
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
|
|
||||||
@ -926,9 +927,14 @@ function cfxHeloTroops.saveData()
|
|||||||
for gName, gData in pairs(cfxHeloTroops.deployedTroops) do
|
for gName, gData in pairs(cfxHeloTroops.deployedTroops) do
|
||||||
local sData = dcsCommon.clone(gData)
|
local sData = dcsCommon.clone(gData)
|
||||||
dcsCommon.synchGroupData(sData.groupData)
|
dcsCommon.synchGroupData(sData.groupData)
|
||||||
if sData.destination then
|
if sData.destination then
|
||||||
net.log("cfxHeloTroops: decycling troop 'destination' for <" .. sData.destination:getName() .. ">")
|
if type(sData.destination) == "table" and (sData.destination.name) then
|
||||||
sData.destination = sData.destination:getName()
|
net.log("cfxHeloTroops: decycling troop 'destination' for <" .. sData.destination.name .. ">")
|
||||||
|
sData.destination = sData.destination.name
|
||||||
|
else
|
||||||
|
sData.destination = nil
|
||||||
|
net.log("cfxHeloTroops: decycling deployed troops 'destination' nilling for safety")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
allTroopData[gName] = sData
|
allTroopData[gName] = sData
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
impostors={}
|
impostors={}
|
||||||
|
|
||||||
impostors.version = "1.1.0"
|
impostors.version = "1.2.0"
|
||||||
impostors.verbose = false
|
impostors.verbose = false
|
||||||
impostors.ups = 1
|
impostors.ups = 1
|
||||||
impostors.requiredLibs = {
|
impostors.requiredLibs = {
|
||||||
@ -21,7 +21,7 @@ impostors.uniqueCounter = 8200000 -- clones start at 9200000
|
|||||||
1.1.0 - filtered dead units during spawns
|
1.1.0 - filtered dead units during spawns
|
||||||
cleanup
|
cleanup
|
||||||
some performance boost for mx lookup
|
some performance boost for mx lookup
|
||||||
|
1.2.0 - filters dead groups entirely
|
||||||
LIMITATIONS:
|
LIMITATIONS:
|
||||||
must be on ground (or would be very silly
|
must be on ground (or would be very silly
|
||||||
does not work with any units deployed on ships
|
does not work with any units deployed on ships
|
||||||
@ -296,7 +296,7 @@ function impostors.spawnGroupsFromImpostor(theZone)
|
|||||||
|
|
||||||
local deadUnits = {} -- collect all dead units for immediate delete
|
local deadUnits = {} -- collect all dead units for immediate delete
|
||||||
-- after spawning
|
-- after spawning
|
||||||
|
local filtered = {}
|
||||||
for idx, groupName in pairs(theZone.groupNames) do
|
for idx, groupName in pairs(theZone.groupNames) do
|
||||||
-- get my group data from MX based on my name
|
-- get my group data from MX based on my name
|
||||||
-- we get from MX so we get all path and order info
|
-- we get from MX so we get all path and order info
|
||||||
@ -306,67 +306,75 @@ function impostors.spawnGroupsFromImpostor(theZone)
|
|||||||
local cat = cfxMX.groupCatByName[groupName]
|
local cat = cfxMX.groupCatByName[groupName]
|
||||||
local ctry = cfxMX.countryByName[groupName]
|
local ctry = cfxMX.countryByName[groupName]
|
||||||
local impostorGroup = theZone.myImpostors[groupName]
|
local impostorGroup = theZone.myImpostors[groupName]
|
||||||
local relinkZones = {}
|
if impostorGroup then
|
||||||
-- now iterate all units in that group, and remove their impostors
|
table.insert(filtered, groupName)
|
||||||
for idy, theUnit in pairs(rawData.units) do
|
local relinkZones = {}
|
||||||
if theUnit and theUnit.name then
|
-- now iterate all units in that group, and remove their impostors
|
||||||
local impName = impostorGroup[theUnit.name]
|
for idy, theUnit in pairs(rawData.units) do
|
||||||
if not impName then
|
if theUnit and theUnit.name then
|
||||||
if theZone.verbose then
|
local impName = impostorGroup[theUnit.name]
|
||||||
trigger.action.outText("group <" .. groupName .. ">: no impostor for <" .. theUnit.name .. ">", 30)
|
if not impName then
|
||||||
end
|
if theZone.verbose then
|
||||||
else
|
trigger.action.outText("group <" .. groupName .. ">: no impostor for <" .. theUnit.name .. ">", 30)
|
||||||
local impStat = StaticObject.getByName(impName)
|
end
|
||||||
if impStat and impStat:isExist() and impStat:getLife() > 1 then
|
|
||||||
-- still alive. read x, y and heading
|
|
||||||
local sp = impStat:getPoint()
|
|
||||||
theUnit.x = sp.x
|
|
||||||
theUnit.y = sp.z -- !!!
|
|
||||||
theUnit.heading = dcsCommon.getUnitHeading(impStat) -- should also work for statics
|
|
||||||
-- should automatically handle ["livery_id"]
|
|
||||||
relinkZones[theUnit.name] = cfxZones.zonesLinkedToUnit(impStat)
|
|
||||||
else
|
else
|
||||||
-- dead
|
local impStat = StaticObject.getByName(impName)
|
||||||
table.insert(deadUnits, theUnit.name)
|
if impStat and impStat:isExist() and impStat:getLife() > 1 then
|
||||||
end
|
-- still alive. read x, y and heading
|
||||||
-- destroy imp
|
local sp = impStat:getPoint()
|
||||||
if impStat and impStat:isExist() then
|
theUnit.x = sp.x
|
||||||
impStat:destroy()
|
theUnit.y = sp.z -- !!!
|
||||||
|
theUnit.heading = dcsCommon.getUnitHeading(impStat) -- should also work for statics
|
||||||
|
-- should automatically handle ["livery_id"]
|
||||||
|
relinkZones[theUnit.name] = cfxZones.zonesLinkedToUnit(impStat)
|
||||||
|
else
|
||||||
|
-- dead
|
||||||
|
table.insert(deadUnits, theUnit.name)
|
||||||
|
end
|
||||||
|
-- destroy imp
|
||||||
|
if impStat and impStat:isExist() then
|
||||||
|
impStat:destroy()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
-- destroy impostor info
|
||||||
-- destroy impostor info
|
theZone.myImpostors[groupName] = nil
|
||||||
theZone.myImpostors[groupName] = nil
|
theZone.impostor = false -- is this good?
|
||||||
theZone.impostor = false
|
|
||||||
|
-- now create the group
|
||||||
-- now create the group
|
if theZone.blinkTime <= 0 then
|
||||||
if theZone.blinkTime <= 0 then
|
-- immediate spawn
|
||||||
-- immediate spawn
|
--local newGroup = coalition.addGroup(ctry, cfxMX.catText2ID(cat), rawData)
|
||||||
--local newGroup = coalition.addGroup(ctry, cfxMX.catText2ID(cat), rawData)
|
local newGroup = coalition.addGroup(ctry, cat, rawData)
|
||||||
local newGroup = coalition.addGroup(ctry, cat, rawData)
|
impostors.relinkZonesForGroup(relinkZones, newGroup)
|
||||||
impostors.relinkZonesForGroup(relinkZones, newGroup)
|
if theZone.trackWith and groupTracker.addGroupToTrackerNamed then
|
||||||
if theZone.trackWith and groupTracker.addGroupToTrackerNamed then
|
-- add these groups to the group tracker
|
||||||
-- add these groups to the group tracker
|
if theZone.verbose or impostors.verbose then
|
||||||
if theZone.verbose or impostors.verbose then
|
trigger.action.outText("+++ipst: attempting to add group <" .. newGroup:getName() .. "> to tracker <" .. theZone.trackWith .. ">", 30)
|
||||||
trigger.action.outText("+++ipst: attempting to add group <" .. newGroup:getName() .. "> to tracker <" .. theZone.trackWith .. ">", 30)
|
end
|
||||||
end
|
groupTracker.addGroupToTrackerNamed(newGroup, theZone.trackWith)
|
||||||
groupTracker.addGroupToTrackerNamed(newGroup, theZone.trackWith)
|
end
|
||||||
|
else
|
||||||
|
-- scheduled spawn
|
||||||
|
theZone.blinkCount = theZone.blinkCount + 1 -- so healthcheck avoids false positives
|
||||||
|
local args = {}
|
||||||
|
args.ctry = ctry
|
||||||
|
args.cat = cat -- cfxMX.catText2ID(cat)
|
||||||
|
args.rawData = rawData
|
||||||
|
args.theZone = theZone
|
||||||
|
args.relinkZones = relinkZones
|
||||||
|
timer.scheduleFunction(impostors.delayedSpawn, args, timer.getTime() + theZone.blinkTime)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- scheduled spawn
|
if theZone.verbose or impostors.verbose then
|
||||||
theZone.blinkCount = theZone.blinkCount + 1 -- so healthcheck avoids false positives
|
trigger.action.outText("No impostor group named <" .. groupName .. "> any more, skipped.", 30)
|
||||||
local args = {}
|
end
|
||||||
args.ctry = ctry
|
-- theZone.myImpostors[groupName] = nil
|
||||||
args.cat = cat -- cfxMX.catText2ID(cat)
|
|
||||||
args.rawData = rawData
|
|
||||||
args.theZone = theZone
|
|
||||||
args.relinkZones = relinkZones
|
|
||||||
timer.scheduleFunction(impostors.delayedSpawn, args, timer.getTime() + theZone.blinkTime)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
theZone.groupNames = filtered -- filter out non-existing
|
||||||
-- now remove all dead units
|
-- now remove all dead units
|
||||||
if theZone.blinkTime <= 0 then
|
if theZone.blinkTime <= 0 then
|
||||||
for idx, unitName in pairs(deadUnits) do
|
for idx, unitName in pairs(deadUnits) do
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
noGap = {}
|
noGap = {}
|
||||||
noGap.version = "1.0.1"
|
noGap.version = "1.3.1"
|
||||||
|
|
||||||
noGap.verbose = false
|
noGap.verbose = false
|
||||||
noGap.ignoreMe = "-ng" -- ignore altogether
|
noGap.ignoreMe = "-ng" -- ignore altogether
|
||||||
@ -20,11 +20,7 @@ noGap.requiredLibs = {
|
|||||||
works on unit-level (stop-Gap works on group level)
|
works on unit-level (stop-Gap works on group level)
|
||||||
Advantage: multiple-ship player groups look better, less code
|
Advantage: multiple-ship player groups look better, less code
|
||||||
Disadvantage: incompatibe with SSB/slotBlock
|
Disadvantage: incompatibe with SSB/slotBlock
|
||||||
|
|
||||||
What it does:
|
|
||||||
Replace all player units with static aircraft until the first time
|
|
||||||
that a player slots into that plane. Static is then replaced with live player unit.
|
|
||||||
|
|
||||||
DOES NOT SUPPORT SHIP-BASED AIRCRAFT
|
DOES NOT SUPPORT SHIP-BASED AIRCRAFT
|
||||||
|
|
||||||
For multiplayer, NoGapGUI must run on the server (only server)
|
For multiplayer, NoGapGUI must run on the server (only server)
|
||||||
@ -38,12 +34,18 @@ noGap.requiredLibs = {
|
|||||||
Version History
|
Version History
|
||||||
1.0.0 - Initial version
|
1.0.0 - Initial version
|
||||||
1.0.1 - added "from runway"
|
1.0.1 - added "from runway"
|
||||||
|
1.3.1 - in line with stopGap 1.3.0
|
||||||
|
- allNeutral attribute
|
||||||
|
- DCS dynamic player spawn compatibility
|
||||||
|
- shallow water also qualifies as carrier based
|
||||||
|
- noParking
|
||||||
|
- kickTheDead
|
||||||
|
- refreshInterval, reinforced guards
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
noGap.standInUnits = {} -- static replacement, if filled; indexed by name
|
noGap.standInUnits = {} -- static replacement, if filled; indexed by name
|
||||||
noGap.liveUnits = {} -- live in-game units, checked regularly
|
noGap.liveUnits = {} -- live in-game units, checked regularly
|
||||||
noGap.allPlayerUnits = {} -- for update check to get server notification
|
noGap.allPlayerUnits = {} -- for update check to get server notification, excludes dynamically spawned units
|
||||||
noGap.noGapZones = {} -- DML only
|
noGap.noGapZones = {} -- DML only
|
||||||
|
|
||||||
function noGap.staticMXFromUnitMX(theGroup, theUnit)
|
function noGap.staticMXFromUnitMX(theGroup, theUnit)
|
||||||
@ -57,6 +59,12 @@ function noGap.staticMXFromUnitMX(theGroup, theUnit)
|
|||||||
theStatic.type = theUnit.type
|
theStatic.type = theUnit.type
|
||||||
theStatic.name = theUnit.name -- same as ME unit
|
theStatic.name = theUnit.name -- same as ME unit
|
||||||
theStatic.cty = cfxMX.countryByName[theGroup.name]
|
theStatic.cty = cfxMX.countryByName[theGroup.name]
|
||||||
|
theStatic.payload = theUnit.payload -- not supported (yet) by DCS
|
||||||
|
theStatic.onboard_num = theUnit.onboard_num -- not supported
|
||||||
|
-- DML only: allNeutral
|
||||||
|
if noGap.allNeutral then
|
||||||
|
theStatic.cty = dcsCommon.getACountryForCoalition(0)
|
||||||
|
end
|
||||||
return theStatic
|
return theStatic
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -82,10 +90,20 @@ function noGap.isGroundStart(theGroup)
|
|||||||
if action == "Turning Point" then return false end
|
if action == "Turning Point" then return false end
|
||||||
if action == "Landing" then return false end
|
if action == "Landing" then return false end
|
||||||
if action == "From Runway" then return false end
|
if action == "From Runway" then return false end
|
||||||
|
if noGap.noParking then
|
||||||
|
local loAct = string.lower(action)
|
||||||
|
if loAct == "from parking area" or
|
||||||
|
loAct == "from parking area hot" then
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("StopG: Player Group <" .. theGroup.name .. "> NOPARKING: [" .. action .. "] must be skipped.", 30)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
-- aircraft is on the ground - but is it in water (carrier)?
|
-- aircraft is on the ground - but is it in water (carrier)?
|
||||||
local u1 = theGroup.units[1]
|
local u1 = theGroup.units[1]
|
||||||
local sType = land.getSurfaceType(u1) -- has fields x and y
|
local sType = land.getSurfaceType(u1) -- has fields x and y
|
||||||
if sType == 3 then return false end
|
if sType == 3 or sType == 2 then return false end
|
||||||
if noGap.verbose then
|
if noGap.verbose then
|
||||||
trigger.action.outText("noG: Player Group <" .. theGroup.name .. "> GROUND BASED: " .. action .. ", land type " .. sType, 30)
|
trigger.action.outText("noG: Player Group <" .. theGroup.name .. "> GROUND BASED: " .. action .. ", land type " .. sType, 30)
|
||||||
end
|
end
|
||||||
@ -107,7 +125,7 @@ function noGap.ignoreMXUnit(theUnit) -- DML-only
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function noGap.createStandInForMXData(group, theUnit) -- group, theUnit are MX data blocks
|
function noGap.createStandInForMXData(group, theUnit) -- WARNING: group and theUnit are MX data blocks
|
||||||
local sgMatch = theUnit.name:sub(-#noGap.ignoreMe) == noGap.ignoreMe or group.name:sub(-#noGap.ignoreMe) == noGap.ignoreMe
|
local sgMatch = theUnit.name:sub(-#noGap.ignoreMe) == noGap.ignoreMe or group.name:sub(-#noGap.ignoreMe) == noGap.ignoreMe
|
||||||
local spMatch = theUnit.name:sub(-#noGap.spIgnore) == noGap.spIgnore or group.name:sub(-#noGap.spIgnore) == noGap.spIgnore
|
local spMatch = theUnit.name:sub(-#noGap.spIgnore) == noGap.spIgnore or group.name:sub(-#noGap.spIgnore) == noGap.spIgnore
|
||||||
local zoneIgnore = noGap.ignoreMXUnit(theUnit)
|
local zoneIgnore = noGap.ignoreMXUnit(theUnit)
|
||||||
@ -139,7 +157,6 @@ function noGap.createStandInForMXData(group, theUnit) -- group, theUnit are MX d
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function noGap.fillGaps()
|
function noGap.fillGaps()
|
||||||
@ -175,6 +192,7 @@ function noGap.turnOff()
|
|||||||
StaticObject.destroy(standIn)
|
StaticObject.destroy(standIn)
|
||||||
end
|
end
|
||||||
noGap.standInUnits = {}
|
noGap.standInUnits = {}
|
||||||
|
noGap.running = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function noGap.turnOn()
|
function noGap.turnOn()
|
||||||
@ -183,6 +201,23 @@ function noGap.turnOn()
|
|||||||
end
|
end
|
||||||
-- populate all empty (non-taken) slots with stand-ins
|
-- populate all empty (non-taken) slots with stand-ins
|
||||||
noGap.fillGaps()
|
noGap.fillGaps()
|
||||||
|
noGap.running = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function noGap.refreshAll() -- restore all statics
|
||||||
|
if noGap.refreshInterval > 0 then
|
||||||
|
-- re-schedule invocation
|
||||||
|
timer.scheduleFunction(noGap.refreshAll, {}, timer.getTime() + noGap.refreshInterval)
|
||||||
|
if not noGap.enabled then return end
|
||||||
|
if noGap.running then
|
||||||
|
noGap.turnOff() -- kill all statics
|
||||||
|
-- turn back on in half a second
|
||||||
|
timer.scheduleFunction(noGap.turnOn, {}, timer.getTime() + 0.5)
|
||||||
|
end
|
||||||
|
if stopGap.verbose then
|
||||||
|
noGap.action.outText("+++noG: refreshing all static", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -193,11 +228,18 @@ function noGap:onEvent(event)
|
|||||||
if not event.id then return end
|
if not event.id then return end
|
||||||
if not event.initiator then return end
|
if not event.initiator then return end
|
||||||
local theUnit = event.initiator
|
local theUnit = event.initiator
|
||||||
|
if (not theUnit.getPlayerName) or (not theUnit:getPlayerName()) then
|
||||||
|
return
|
||||||
|
end -- no player unit.
|
||||||
|
if cfxMX.isDynamicPlayer(theUnit) then
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++noG: unit <" .. theUnit:getName() .. "> controlled by <" .. theUnit:getPlayerName() .. "> is dynamically spawned, ignoring.", 30)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end -- ignore all dynamically spawned aircraft
|
||||||
|
|
||||||
if event.id == 15 then -- we act on player unit birth
|
if event.id == 15 then -- we act on player unit birth
|
||||||
if (not theUnit.getPlayerName) or (not theUnit:getPlayerName()) then
|
|
||||||
return
|
|
||||||
end -- no player unit.
|
|
||||||
local uName = theUnit:getName()
|
local uName = theUnit:getName()
|
||||||
|
|
||||||
if noGap.standInUnits[uName] then
|
if noGap.standInUnits[uName] then
|
||||||
@ -208,11 +250,35 @@ function noGap:onEvent(event)
|
|||||||
trigger.action.outText("+++noG: removed static for <" ..uName .. ">, player inbound", 30)
|
trigger.action.outText("+++noG: removed static for <" ..uName .. ">, player inbound", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
noGap.liveUnits[uName] = theUnit
|
noGap.liveUnits[uName] = theUnit -- dynamic never show up here
|
||||||
-- reset noGapGUI flag, it has done its job. Unit is live
|
-- reset noGapGUI flag, it has done its job. Unit is live
|
||||||
-- we can reset it for next iteration
|
-- we can reset it for next iteration
|
||||||
trigger.action.setUserFlag("NG"..uName, 0)
|
trigger.action.setUserFlag("NG"..uName, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if id == 6 then -- eject, ignore for now
|
||||||
|
end
|
||||||
|
if (id == 9) or (id == 30) or (id == 5) then -- dead, lost, crash
|
||||||
|
local pName = theUnit:getPlayerName()
|
||||||
|
timer.scheduleFunction(noGap.kickplayer, pName, timer.getTime() + 1)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
noGap.kicks = {}
|
||||||
|
function noGap.kickplayer(args)
|
||||||
|
if not noGap.kickTheDead then return end
|
||||||
|
local pName = args
|
||||||
|
for i,slot in pairs(net.get_player_list()) do
|
||||||
|
local nn = net.get_name(slot)
|
||||||
|
if nn == pName then
|
||||||
|
if noGap.kicks[nn] then
|
||||||
|
if timer.getTime() < noGap.kicks[nn] then return end
|
||||||
|
end
|
||||||
|
net.force_player_slot(slot, 0, '')
|
||||||
|
noGap.kicks[nn] = timer.getTime() + 5 -- avoid too many kicks in 5 seconds
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -312,7 +378,7 @@ function noGap.update()
|
|||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- read stopGapZone (DML only)
|
-- read noGap Zone (DML only)
|
||||||
--
|
--
|
||||||
function noGap.createNoGapZone(theZone)
|
function noGap.createNoGapZone(theZone)
|
||||||
local ng = theZone:getBoolFromZoneProperty("noGap", true)
|
local ng = theZone:getBoolFromZoneProperty("noGap", true)
|
||||||
@ -331,8 +397,11 @@ noGap.name = "noGapConfig" -- cfxZones compatibility here
|
|||||||
function noGap.readConfigZone(theZone)
|
function noGap.readConfigZone(theZone)
|
||||||
-- currently nothing to do
|
-- currently nothing to do
|
||||||
noGap.verbose = theZone.verbose
|
noGap.verbose = theZone.verbose
|
||||||
|
noGap.ssbEnabled = theZone:getBoolFromZoneProperty("ssb", true)
|
||||||
noGap.enabled = theZone:getBoolFromZoneProperty("onStart", true)
|
noGap.enabled = theZone:getBoolFromZoneProperty("onStart", true)
|
||||||
noGap.timeOut = theZone:getNumberFromZoneProperty("timeOut", 0) -- default to off
|
noGap.timeOut = theZone:getNumberFromZoneProperty("timeOut", 0) -- default to off
|
||||||
|
noGap.noParking = theZone:getBoolFromZoneProperty("noParking", false)
|
||||||
|
|
||||||
if theZone:hasProperty("on?") then
|
if theZone:hasProperty("on?") then
|
||||||
noGap.turnOnFlag = theZone:getStringFromZoneProperty("on?", "*<none>")
|
noGap.turnOnFlag = theZone:getStringFromZoneProperty("on?", "*<none>")
|
||||||
noGap.lastTurnOnFlag = trigger.misc.getUserFlag(noGap.turnOnFlag)
|
noGap.lastTurnOnFlag = trigger.misc.getUserFlag(noGap.turnOnFlag)
|
||||||
@ -350,6 +419,10 @@ function noGap.readConfigZone(theZone)
|
|||||||
trigger.action.outText("+++noG: turned off", 30)
|
trigger.action.outText("+++noG: turned off", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
noGap.refreshInterval = theZone:getNumberFromZoneProperty("refresh", -1) -- default: no refresh
|
||||||
|
noGap.kickTheDead = theZone:getBoolFromZoneProperty("kickDead", true)
|
||||||
|
noGap.allNeutral = theZone:getBoolFromZoneProperty("allNeutral", false)
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -394,6 +467,11 @@ function noGap.start()
|
|||||||
-- start update in 1 second
|
-- start update in 1 second
|
||||||
timer.scheduleFunction(noGap.update, {}, timer.getTime() + 1)
|
timer.scheduleFunction(noGap.update, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
|
-- start refresh cycle if refresh (>0)
|
||||||
|
if noGap.refreshInterval > 0 then
|
||||||
|
timer.scheduleFunction(noGap.refreshAll, {}, timer.getTime() + noGap.refreshInterval)
|
||||||
|
end
|
||||||
|
|
||||||
-- say hi!
|
-- say hi!
|
||||||
local mp = " (SP - <" .. sgDetect .. ">)"
|
local mp = " (SP - <" .. sgDetect .. ">)"
|
||||||
if sgDetect > 0 then mp = " -- MP GUI Detected (" .. sgDetect .. ")!" end
|
if sgDetect > 0 then mp = " -- MP GUI Detected (" .. sgDetect .. ")!" end
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
radioMenu = {}
|
radioMenu = {}
|
||||||
radioMenu.version = "4.0.1"
|
radioMenu.version = "4.0.2"
|
||||||
radioMenu.verbose = false
|
radioMenu.verbose = false
|
||||||
radioMenu.ups = 1
|
radioMenu.ups = 1
|
||||||
radioMenu.requiredLibs = {
|
radioMenu.requiredLibs = {
|
||||||
@ -19,7 +19,8 @@ radioMenu.lateGroups = {} -- dict by ID
|
|||||||
detect cyclic references
|
detect cyclic references
|
||||||
4.0.0 - added infrastructure for dynamic players (DCS 2.9.6)
|
4.0.0 - added infrastructure for dynamic players (DCS 2.9.6)
|
||||||
- added dynamic player support
|
- added dynamic player support
|
||||||
4.0.1 - MX no longer optional, so ask for it
|
4.0.1 - MX no longer optional, so ask for it
|
||||||
|
4.0.2 - ackSnd now also broadcasts to all if no group
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
function radioMenu.addRadioMenu(theZone)
|
function radioMenu.addRadioMenu(theZone)
|
||||||
@ -770,7 +771,11 @@ function radioMenu.doMenuX(args)
|
|||||||
radioMenu.radioOutMsg(ack, gid, theZone)
|
radioMenu.radioOutMsg(ack, gid, theZone)
|
||||||
end
|
end
|
||||||
if ackSnd then
|
if ackSnd then
|
||||||
trigger.action.outSoundForGroup(gid, ackSnd)
|
if (not gid) or gid == 0 then
|
||||||
|
trigger.action.outSound(ackSnd)
|
||||||
|
else
|
||||||
|
trigger.action.outSoundForGroup(gid, ackSnd)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,107 +1,144 @@
|
|||||||
raiseFlag = {}
|
raiseFlag = {}
|
||||||
raiseFlag.version = "2.0.0"
|
raiseFlag.version = "3.0.0"
|
||||||
raiseFlag.verbose = false
|
|
||||||
raiseFlag.requiredLibs = {
|
raiseFlag.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
"cfxZones", -- Zones, of course
|
"cfxZones", -- Zones, of course
|
||||||
}
|
}
|
||||||
raiseFlag.flags = {}
|
raiseFlag.flags = {} -- my minions
|
||||||
--[[--
|
--[[--
|
||||||
Raise A Flag module -- (c) 2022-23 by Christian Franz and cf/x AG
|
(c) 2022-23 by Christian Franz and cf/x AG
|
||||||
|
|
||||||
Version History
|
Version History
|
||||||
1.0.0 - initial release
|
3.0.0 - switched to polling
|
||||||
1.0.1 - synonym "raiseFlag!"
|
- remains# attribute
|
||||||
1.1.0 - DML update
|
- support for persistence
|
||||||
1.2.0 - Watchflag update
|
- zone-individual verbosity
|
||||||
1.2.1 - support for 'inc', 'dec', 'flip'
|
- code cleanup, removed deprecated attributes
|
||||||
2.0.0 - dmlZones
|
|
||||||
- full method support
|
|
||||||
- full DML upgrade
|
|
||||||
- method attribute (synonym to 'value')
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
function raiseFlag.addRaiseFlag(theZone)
|
function raiseFlag.addRaiseFlag(theZone)
|
||||||
table.insert(raiseFlag.flags, theZone)
|
raiseFlag.flags[theZone.name] = theZone
|
||||||
end
|
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
|
-- read attributes
|
||||||
--
|
--
|
||||||
function raiseFlag.createRaiseFlagWithZone(theZone)
|
function raiseFlag.createRaiseFlagWithZone(theZone)
|
||||||
-- get flag from faiseFlag itself
|
theZone.raiseFlag = theZone:getStringFromZoneProperty("raiseFlag!", "<none>") -- the flag to raise
|
||||||
if theZone:hasProperty("raiseFlag") then
|
theZone.flagValue = theZone:getStringFromZoneProperty("method", "inc")
|
||||||
theZone.raiseFlag = theZone:getStringFromZoneProperty("raiseFlag", "<none>") -- the flag to raise
|
|
||||||
else
|
|
||||||
theZone.raiseFlag = theZone:getStringFromZoneProperty("raiseFlag!", "<none>") -- the flag to raise
|
|
||||||
end
|
|
||||||
|
|
||||||
-- pre-method DML raiseFlag is now upgraded to method.
|
|
||||||
-- flagValue now carries the method
|
|
||||||
if theZone:hasProperty("value") then -- backward compatibility
|
|
||||||
theZone.flagValue = theZone:getStringFromZoneProperty("value", "inc") -- value to set to. default is command 'inc'
|
|
||||||
else
|
|
||||||
theZone.flagValue = theZone:getStringFromZoneProperty("method", "inc")
|
|
||||||
end
|
|
||||||
theZone.flagValue = theZone.flagValue:lower()
|
theZone.flagValue = theZone.flagValue:lower()
|
||||||
theZone.minAfterTime, theZone.maxAfterTime = theZone:getPositiveRangeFromZoneProperty("afterTime", -1)
|
theZone.minAfterTime, theZone.maxAfterTime = theZone:getPositiveRangeFromZoneProperty("afterTime", -1)
|
||||||
theZone.raiseTriggerMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
|
theZone.raiseTriggerMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
|
||||||
if theZone:hasProperty("raiseTriggerMethod") then
|
if theZone:hasProperty("raiseTriggerMethod") then
|
||||||
theZone.raiseTriggerMethod = theZone:getStringFromZoneProperty("raiseTriggerMethod", "change")
|
theZone.raiseTriggerMethod = theZone:getStringFromZoneProperty("raiseTriggerMethod", "change")
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone:hasProperty("stopFlag?") then
|
if theZone:hasProperty("stopFlag?") then
|
||||||
theZone.triggerStopFlag = theZone:getStringFromZoneProperty( "stopFlag?", "none")
|
theZone.triggerStopFlag = theZone:getStringFromZoneProperty( "stopFlag?", "none")
|
||||||
theZone.lastTriggerStopValue = theZone:getFlagValue(theZone.triggerStopFlag) -- save last value
|
theZone.lastTriggerStopValue = theZone:getFlagValue(theZone.triggerStopFlag) -- save last value
|
||||||
end
|
end
|
||||||
theZone.scheduleID = nil
|
if theZone:hasProperty("timeLeft#") then
|
||||||
|
theZone.timeLeft = theZone:getStringFromZoneProperty("timeLeft#", "none")
|
||||||
|
end
|
||||||
theZone.raiseStopped = false
|
theZone.raiseStopped = false
|
||||||
|
|
||||||
-- now simply schedule for invocation
|
-- now simply schedule for invocation
|
||||||
local args = {}
|
|
||||||
args.theZone = theZone
|
|
||||||
if theZone.minAfterTime < 1 then
|
if theZone.minAfterTime < 1 then
|
||||||
timer.scheduleFunction(raiseFlag.triggered, args, timer.getTime() + 0.5)
|
theZone.deadLine = -1 -- will always trigger
|
||||||
else
|
else
|
||||||
local delay = cfxZones.randomDelayFromPositiveRange(theZone.minAfterTime, theZone.maxAfterTime)
|
local delay = cfxZones.randomDelayFromPositiveRange(theZone.minAfterTime, theZone.maxAfterTime)
|
||||||
timer.scheduleFunction(raiseFlag.triggered, args, timer.getTime() + delay)
|
theZone.deadLine = timer.getTime() + delay
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function raiseFlag.triggered(args)
|
function raiseFlag.triggered(theZone)
|
||||||
local theZone = args.theZone
|
if theZone.raiseStopped then return end -- should be filtered
|
||||||
if theZone.raiseStopped then return end
|
|
||||||
-- if we get here, we aren't stopped and do the flag pull
|
|
||||||
local command = theZone.flagValue
|
local command = theZone.flagValue
|
||||||
theZone:pollFlag(theZone.raiseFlag, command)
|
theZone:pollFlag(theZone.raiseFlag, command)
|
||||||
if raiseFlag.verbose or theZone.verbose then
|
if raiseFlag.verbose or theZone.verbose then
|
||||||
trigger.action.outText("+++rFlg - raising <" .. theZone.raiseFlag .. "> with method '" .. command .. "'" ,30)
|
trigger.action.outText("+++rFlg - raising <" .. theZone.raiseFlag .. "> with method '" .. command .. "'" .. " for zone <" .. theZone.name .. ">" ,30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- update
|
-- update
|
||||||
--
|
--
|
||||||
function raiseFlag.update()
|
function raiseFlag.update(firstUpdate)
|
||||||
-- call me in a second to poll triggers
|
local now = timer.getTime()
|
||||||
timer.scheduleFunction(raiseFlag.update, {}, timer.getTime() + 1)
|
timer.scheduleFunction(raiseFlag.update, false, now + 1) -- we always beat on .5 offset!
|
||||||
for idx, aZone in pairs(raiseFlag.flags) do
|
local filtered = {}
|
||||||
-- make sure to re-start before reading time limit
|
for zName, theZone in pairs(raiseFlag.flags) do
|
||||||
if aZone:testZoneFlag(aZone.triggerStopFlag, aZone.raiseTriggerMethod, "lastTriggerStopValue") then
|
-- see if this timer has run out
|
||||||
theZone.raiseStopped = true -- we are done, no flag!
|
if theZone.deadLine < now then
|
||||||
|
if theZone.verbose then
|
||||||
|
trigger.action.outText("+++rFlg: will raise flag <" .. theZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
raiseFlag.triggered(theZone)
|
||||||
|
if theZone.timeLeft then theZone:setFlagValue(theZone.timeLeft, 0) end
|
||||||
|
theZone.raiseStopped = true -- will filter
|
||||||
|
elseif theZone.timeLeft then
|
||||||
|
local rem = theZone.deadLine - now
|
||||||
|
theZone:setFlagValue(theZone.timeLeft, rem)
|
||||||
|
if theZone.verbose then
|
||||||
|
trigger.action.outText("+++rFlg: time left on <" .. theZone.name .. ">:" .. math.floor(rem) .. " secs", 30)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if theZone:testZoneFlag(theZone.triggerStopFlag, theZone.raiseTriggerMethod, "lastTriggerStopValue") then
|
||||||
|
theZone.raiseStopped = true -- filter
|
||||||
|
end
|
||||||
|
|
||||||
|
if not theZone.raiseStopped then
|
||||||
|
filtered[theZone.name] = theZone
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
raiseFlag.flags = filtered
|
||||||
|
end
|
||||||
|
--
|
||||||
|
-- load / save (game data)
|
||||||
|
--
|
||||||
|
function raiseFlag.saveData()
|
||||||
|
local theData = {}
|
||||||
|
local theFlags = {}
|
||||||
|
local now = timer.getTime()
|
||||||
|
for name, theZone in pairs (raiseFlag.flags) do
|
||||||
|
-- note: we only process existing!
|
||||||
|
theFlags[name] = theZone.deadLine - now
|
||||||
|
end
|
||||||
|
-- save current deadlines
|
||||||
|
theData.theFlags = theFlags
|
||||||
|
return theData, raiseFlag.sharedData -- second val currently nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function raiseFlag.loadData()
|
||||||
|
if not persistence then return end
|
||||||
|
local shared = nil
|
||||||
|
local theData = persistence.getSavedDataForModule("raiseFlag")
|
||||||
|
if (not theData) then
|
||||||
|
if raiseFlag.verbose then
|
||||||
|
trigger.action.outText("+++rFlg: no save date received, skipping.", 30)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local theFlags = theData.theFlags
|
||||||
|
-- filter and reset timers
|
||||||
|
local filtered = {}
|
||||||
|
local now = timer.getTime()
|
||||||
|
for name, deadLine in pairs(theFlags) do
|
||||||
|
local theZone = raiseFlag.flags[name]
|
||||||
|
if theZone then
|
||||||
|
theZone.deadLine = now + deadLine
|
||||||
|
filtered[name] = theZone
|
||||||
|
if theZone.verbose then
|
||||||
|
trigger.action.outText("+++rFlg: (persistence) reset zone <" .. name .. "> to <" .. theZone.deadLine .. "> (<" .. deadLine .. ">)", 30)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
trigger.action.outText("+++rFlag: (persistence) filtered <" .. name .. ">, does not exist in miz.", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for name, theZone in pairs(raiseFlag.flags) do
|
||||||
|
if not filtered[name] and theZone.verbose then
|
||||||
|
trigger.action.outText("+++rFlg: (persistence) filtered spent/non-saved <" .. name .. ">.", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
raiseFlag.flags = filtered
|
||||||
|
end
|
||||||
--
|
--
|
||||||
-- config & go!
|
-- config & go!
|
||||||
--
|
--
|
||||||
@ -117,39 +154,30 @@ function raiseFlag.readConfigZone()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function raiseFlag.start()
|
function raiseFlag.start()
|
||||||
-- lib check
|
|
||||||
if not dcsCommon.libCheck then
|
if not dcsCommon.libCheck then
|
||||||
trigger.action.outText("cfx raise flag requires dcsCommon", 30)
|
trigger.action.outText("cfx raise flag requires dcsCommon", 30)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
if not dcsCommon.libCheck("cfx Raise Flag", raiseFlag.requiredLibs) then
|
if not dcsCommon.libCheck("cfx Raise Flag", raiseFlag.requiredLibs)then return false end
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- read config
|
|
||||||
raiseFlag.readConfigZone()
|
raiseFlag.readConfigZone()
|
||||||
|
|
||||||
-- process raise Flags 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
|
|
||||||
-- try synonym
|
|
||||||
attrZones = cfxZones.getZonesWithAttributeNamed("raiseFlag!")
|
attrZones = cfxZones.getZonesWithAttributeNamed("raiseFlag!")
|
||||||
for k, aZone in pairs(attrZones) do
|
for k, aZone in pairs(attrZones) do
|
||||||
raiseFlag.createRaiseFlagWithZone(aZone) -- process attributes
|
raiseFlag.createRaiseFlagWithZone(aZone) -- process attributes
|
||||||
raiseFlag.addRaiseFlag(aZone) -- add to list
|
raiseFlag.addRaiseFlag(aZone) -- add to list
|
||||||
end
|
end
|
||||||
|
if persistence then
|
||||||
-- start update
|
callbacks = {}
|
||||||
raiseFlag.update()
|
callbacks.persistData = raiseFlag.saveData
|
||||||
|
persistence.registerModule("raiseFlag", callbacks)
|
||||||
|
-- now load my data
|
||||||
|
raiseFlag.loadData()
|
||||||
|
end
|
||||||
|
-- start update at 0.5 secs mark
|
||||||
|
timer.scheduleFunction(raiseFlag.update, true, timer.getTime() + 0.5)
|
||||||
trigger.action.outText("cfx raiseFlag v" .. raiseFlag.version .. " started.", 30)
|
trigger.action.outText("cfx raiseFlag v" .. raiseFlag.version .. " started.", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- let's go!
|
|
||||||
if not raiseFlag.start() then
|
if not raiseFlag.start() then
|
||||||
trigger.action.outText("cfx Raise Flag aborted: missing libraries", 30)
|
trigger.action.outText("cfx Raise Flag aborted: missing libraries", 30)
|
||||||
raiseFlag = nil
|
raiseFlag = nil
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
slotty = {}
|
slotty = {}
|
||||||
slotty.version = "1.1.0"
|
slotty.version = "1.2.0"
|
||||||
--[[--
|
--[[--
|
||||||
Single-player slot blocking and slot blocking fallback
|
Single-player slot blocking and slot blocking fallback
|
||||||
for multiplayer when SSB is not installed on server.
|
for multiplayer when SSB is not installed on server.
|
||||||
@ -12,7 +12,7 @@ slotty.version = "1.1.0"
|
|||||||
Version history
|
Version history
|
||||||
1.0.0 - Initial version
|
1.0.0 - Initial version
|
||||||
1.1.0 - "noSlotty" global disable flag, anti-mirror SSB flag
|
1.1.0 - "noSlotty" global disable flag, anti-mirror SSB flag
|
||||||
1.2.0 - better (delayed) nilling for cfxSSB ocupied clients to
|
1.2.0 - better (delayed) nilling for cfxSSB occupied clients to
|
||||||
- avoid a race condition
|
- avoid a race condition
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|||||||
@ -58,7 +58,7 @@ stopGap.requiredLibs = {
|
|||||||
required
|
required
|
||||||
1.3.0 - carriers in shallow waters also no longer handled as viable
|
1.3.0 - carriers in shallow waters also no longer handled as viable
|
||||||
- noParking option
|
- noParking option
|
||||||
|
1.3.1 - stronger guards on refresh
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
stopGap.standInGroups = {} -- idx by name, if set has a static
|
stopGap.standInGroups = {} -- idx by name, if set has a static
|
||||||
@ -239,6 +239,7 @@ function stopGap.refreshAll() -- restore all statics
|
|||||||
if stopGap.refreshInterval > 0 then
|
if stopGap.refreshInterval > 0 then
|
||||||
-- re-schedule invocation
|
-- re-schedule invocation
|
||||||
timer.scheduleFunction(stopGap.refreshAll, {}, timer.getTime() + stopGap.refreshInterval)
|
timer.scheduleFunction(stopGap.refreshAll, {}, timer.getTime() + stopGap.refreshInterval)
|
||||||
|
if not stopGap.enabled then return end -- why do we have enabled and running?
|
||||||
if stopGap.running then
|
if stopGap.running then
|
||||||
stopGap.turnOff() -- kill all statics
|
stopGap.turnOff() -- kill all statics
|
||||||
-- turn back on in half a second
|
-- turn back on in half a second
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user