Version 1.4.6

ownAll
This commit is contained in:
Christian Franz 2023-10-19 08:21:35 +02:00
parent 28830f1378
commit 08527a515d
12 changed files with 677 additions and 357 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
airfield = {}
airfield.version = "1.1.0"
airfield.version = "1.1.2"
airfield.requiredLibs = {
"dcsCommon",
"cfxZones",
@ -7,7 +7,7 @@ airfield.requiredLibs = {
airfield.verbose = false
airfield.myAirfields = {} -- indexed by name
airfield.farps = false
airfield.gracePeriod = 3
--[[--
This module generates signals when the nearest airfield changes hands,
can force the coalition of an airfield, and always provides the
@ -20,12 +20,17 @@ airfield.farps = false
- allow zone.local farps designation
- always checks farp cap events
- added verbosity
1.1.1 - GC grace period correction of ownership
1.1.2 - 'show' attribute
line color attributes per zone
line color defaults in config
--]]--
--
-- setting up airfield
--
function airfield.createAirFieldFromZone(theZone)
--trigger.action.outText("Enter airfield for <" .. theZone.name .. ">", 30)
theZone.farps = theZone:getBoolFromZoneProperty("farps", false)
local filterCat = 0
@ -34,17 +39,18 @@ function airfield.createAirFieldFromZone(theZone)
local theBase = dcsCommon.getClosestAirbaseTo(p, filterCat)
theZone.airfield = theBase
theZone.afName = theBase:getName()
if airfield.verbose then
trigger.action.outText("+++airF: zone <" .. theZone:getName() .. "> associates with <" .. theZone.afName .. ">", 30)
-- set zone's owner
theZone.owner = theBase:getCoalition()
theZone.mismatchCount = airfield.gracePeriod
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)
end
-- methods
theZone.method = theZone:getStringFromZoneProperty("method", "inc")
theZone.triggerMethod = theZone:getStringFromZoneProperty("triggerMethod", "change")
-- set zone's owner
theZone.owner = theBase:getCoalition()
if theZone:hasProperty("red!") then
theZone.redCap = theZone:getStringFromZoneProperty("red!")
end
@ -90,14 +96,77 @@ function airfield.createAirFieldFromZone(theZone)
-- index by name, and warn if duplicate associate
if airfield.myAirfields[theZone.afName] then
trigger.action.outText("+++airF: WARNING - zone <" .. theZone:getName() .. "> redefines airfield <" .. theZone.afName .. ">, discarded!", 30)
trigger.action.outText("+++airF: WARNING - zone <" .. theZone.name .. "> redefines airfield <" .. theZone.afName .. ">, discarded!", 30)
else
airfield.myAirfields[theZone.afName] = theZone
end
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)
theZone.show = theZone:getBoolFromZoneProperty("show", false)
theZone.ownerMark = nil
-- individual colors, else default from config
theZone.redLine = theZone:getRGBAVectorFromZoneProperty("redLine", airfield.redLine)
theZone.redFill = theZone:getRGBAVectorFromZoneProperty("redFill", airfield.redFill)
theZone.blueLine = theZone:getRGBAVectorFromZoneProperty("blueLine", airfield.blueLine)
theZone.blueFill = theZone:getRGBAVectorFromZoneProperty("blueFill", airfield.blueFill)
theZone.neutralLine = theZone:getRGBAVectorFromZoneProperty("neutralLine", airfield.neutralLine)
theZone.neutralFill = theZone:getRGBAVectorFromZoneProperty("neutralFill", airfield.neutralFill)
airfield.showAirfield(theZone)
--trigger.action.outText("Exit airfield for <" .. theZone.name .. ">", 30)
end
function airfield.showAirfield(theZone)
if not theZone then return end
if theZone.ownerMark then
-- remove previous mark
trigger.action.removeMark(theZone.ownerMark)
theZone.ownerMark = nil
end
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 fillColor = theZone.redFill -- {1.0, 0, 0, 0.2} -- red
local owner = theZone.owner
if owner == 2 then
lineColor = theZone.blueLine -- {0.0, 0, 1.0, 1.0}
fillColor = theZone.blueFill -- {0.0, 0, 1.0, 0.2}
elseif owner == 0 or owner == 3 then
lineColor = theZone.neutralLine -- {0.8, 0.8, 0.8, 1.0}
fillColor = theZone.neutralFill -- {0.8, 0.8, 0.8, 0.2}
end
-- always center on airfield, always 2km radius
local markID = dcsCommon.numberUUID()
local radius = 2000 -- meters
local p = theZone.airfield:getPoint()
-- if there are runways, we center on first runway
local rws = theZone.airfield:getRunways()
if rws then -- all airfields and farps have runways, but that array isnt filled for FARPS
local rw1 = rws[1]
if rw1 then
p.x = rw1.position.x
p.z = rw1.position.z
if airfield.verbose or theZone.verbose then
trigger.action.outText("+++airF: zone <" .. theZone.name .. "> assoc airfield <" .. theZone.afName .. "> has rw1, x=" .. p.x .. ", z=" .. p.z, 30)
end
else
if airfield.verbose or theZone.verbose then
trigger.action.outText("+++airF: zone <" .. theZone.name .. "> assoc airfield <" .. theZone.afName .. "> has no rw1", 30)
end
end
else
if airfield.verbose or theZone.verbose then
trigger.action.outText("+++airF: zone <" .. theZone.name .. "> assoc airfield <" .. theZone.afName .. "> has no runways", 30)
end
end
p.y = 0
trigger.action.circleToAll(-1, markID, p, radius, lineColor, fillColor, 1, true, "")
theZone.ownerMark = markID
end
function airfield.assumeControl(theZone)
@ -132,6 +201,8 @@ function airfield.airfieldCaptured(theBase)
trigger.action.outText("+++airF: handling capture event/command for airfield <" .. bName .. "> with zone <" .. theZone:getName() .. ">", 30)
end
airfield.showAirfield(theZone) -- show if enabled
-- outputs
if theZone.ownedBy then
trigger.action.setUserFlag(theZone.ownedBy, theZone.owner)
@ -218,6 +289,39 @@ function airfield.update()
end
end
function airfield.GC()
timer.scheduleFunction(airfield.GC, {}, timer.getTime() + 2)
for afName, theZone in pairs(airfield.myAirfields) do
local theAirfield = theZone.airfield
local afOwner = theAirfield:getCoalition()
if afOwner == theZone.owner then
theZone.mismatchCount = airfield.gracePeriod
-- all quiet
elseif afOwner == 3 then
-- contested
if theZone.verbose or airfield.verbose then
trigger.action.outText("+++airF: airfield <" .. theZone.name .. ">: ownership is contested.", 30)
end
else
if theZone.mismatchCount > 0 then
if theZone.verbose or airfield.verbose then
trigger.action.outText("we have a problem with owner for <" .. theZone.name .. ">: afO = <" .. afOwner .. ">, zo = <" .. theZone.owner .. ">, grace count = <" .. theZone.mismatchCount..">", 30)
end
theZone.mismatchCount = theZone.mismatchCount - 1
else
airfield.airfieldCaptured(theAirfield)
theZone.mismatchCount = airfield.gracePeriod
if theZone.verbose or airfield.verbose then
trigger.action.outText("+++airF: corrected ownership after grace period", 30)
end
end
end
end
end
--
-- LOAD / SAVE
--
@ -289,6 +393,13 @@ function airfield.readConfig()
airfield.verbose = theZone.verbose
airfield.farps = theZone:getBoolFromZoneProperty("farps", false)
-- colors for line and fill
airfield.redLine = theZone:getRGBAVectorFromZoneProperty("redLine", {1.0, 0, 0, 1.0})
airfield.redFill = theZone:getRGBAVectorFromZoneProperty("redFill", {1.0, 0, 0, 0.2})
airfield.blueLine = theZone:getRGBAVectorFromZoneProperty("blueLine", {0.0, 0, 1.0, 1.0})
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.neutralFill = theZone:getRGBAVectorFromZoneProperty("neutralFill", {0.8, 0.8, 0.8, 0.2})
end
function airfield.start()
@ -320,6 +431,9 @@ function airfield.start()
-- start update in 1 second
timer.scheduleFunction(airfield.update, {}, timer.getTime() + 1)
-- start GC
timer.scheduleFunction(airfield.GC, {}, timer.getTime() + 2)
trigger.action.outText("cfx airfield v" .. airfield.version .. " loaded.", 30)
return true
end

View File

@ -1,5 +1,5 @@
cfxOwnedZones = {}
cfxOwnedZones.version = "2.0.1"
cfxOwnedZones.version = "2.1.0"
cfxOwnedZones.verbose = false
cfxOwnedZones.announcer = true
cfxOwnedZones.name = "cfxOwnedZones"
@ -22,6 +22,13 @@ cfxOwnedZones.name = "cfxOwnedZones"
- fixWingCap option
- filter water owned zones for groundTroops
2.0.1 - RGBA colors can be entered hex style #ff340799
2.1.0 - dmlZones
- full support for multiple out flags
- "Neutral (C)" returned for ownership if contested owner
- corrected some typos in output text
- method support for individual owned zones
- method support for global (config) output
- moved drawZone to cfxZones
--]]--
cfxOwnedZones.requiredLibs = {
@ -72,6 +79,7 @@ end
function cfxOwnedZones.side2name(theSide)
if theSide == 1 then return "REDFORCE" end
if theSide == 2 then return "BLUEFORCE" end
if theSide == 3 then return "Neutral (C)" end
return "Neutral"
end
@ -79,7 +87,7 @@ function cfxOwnedZones.conqTemplate(aZone, newOwner, lastOwner)
if true then return end -- do not output
if lastOwner == 0 then
trigger.action.outText(cfxOwnedZones.side2name(newOwner) .. " have taken possession zone " .. aZone.name, 30)
trigger.action.outText(cfxOwnedZones.side2name(newOwner) .. " have taken possession of zone " .. aZone.name, 30)
return
end
@ -107,18 +115,8 @@ function cfxOwnedZones.drawZoneInMap(aZone)
lineColor = aZone.neutralLine -- {0.8, 0.8, 0.8, 1.0}
fillColor = aZone.neutralFill -- {0.8, 0.8, 0.8, 0.2}
end
-- local theShape = 2 -- circle
local markID = dcsCommon.numberUUID()
if aZone.isCircle then
trigger.action.circleToAll(-1, markID, aZone.point, aZone.radius, lineColor, fillColor, 1, true, "")
else
local poly = aZone.poly
trigger.action.quadToAll(-1, markID, poly[4], poly[3], poly[2], poly[1], lineColor, fillColor, 1, true, "") -- note: left winding to get fill color
end
aZone.markID = markID
aZone.markID = aZone:drawZone(lineColor, fillColor) -- markID
end
function cfxOwnedZones.getOwnedZoneByName(zName)
@ -129,44 +127,46 @@ function cfxOwnedZones.getOwnedZoneByName(zName)
end
function cfxOwnedZones.addOwnedZone(aZone)
local owner = aZone.owner --cfxZones.getCoalitionFromZoneProperty(aZone, "owner", 0) -- is already read
local owner = aZone.owner
if cfxZones.hasProperty(aZone, "conquered!") then
aZone.conqueredFlag = cfxZones.getStringFromZoneProperty(aZone, "conquered!", "*<cfxnone>")
if aZone:hasProperty("conquered!") then
aZone.conqueredFlag = aZone:getStringFromZoneProperty("conquered!", "*<cfxnone>")
end
if cfxZones.hasProperty(aZone, "redCap!") then
aZone.redCap = cfxZones.getStringFromZoneProperty(aZone, "redCap!", "none")
if aZone:hasProperty("redCap!") then
aZone.redCap = aZone:getStringFromZoneProperty("redCap!", "none")
end
if cfxZones.hasProperty(aZone, "redLost!") then
aZone.redLost = cfxZones.getStringFromZoneProperty(aZone, "redLost!", "none")
if aZone:hasProperty("redLost!") then
aZone.redLost = aZone:getStringFromZoneProperty("redLost!", "none")
end
if cfxZones.hasProperty(aZone, "blueCap!") then
aZone.blueCap = cfxZones.getStringFromZoneProperty(aZone, "blueCap!", "none")
if aZone:hasProperty("blueCap!") then
aZone.blueCap = aZone:getStringFromZoneProperty("blueCap!", "none")
end
if cfxZones.hasProperty(aZone, "blueLost!") then
aZone.blueLost = cfxZones.getStringFromZoneProperty(aZone, "blueLost!", "none")
if aZone:hasProperty("blueLost!") then
aZone.blueLost = aZone:getStringFromZoneProperty("blueLost!", "none")
end
if cfxZones.hasProperty(aZone, "neutral!") then
aZone.neutralCap = cfxZones.getStringFromZoneProperty(aZone, "neutral!", "none")
if aZone:hasProperty("neutral!") then
aZone.neutralCap = aZone:getStringFromZoneProperty("neutral!", "none")
end
if cfxZones.hasProperty(aZone, "ownedBy#") then
aZone.ownedBy = cfxZones.getStringFromZoneProperty(aZone, "ownedBy#", "none")
elseif cfxZones.hasProperty(aZone, "ownedBy") then
aZone.ownedBy = cfxZones.getStringFromZoneProperty(aZone, "ownedBy", "none")
if aZone:hasProperty("ownedBy#") then
aZone.ownedBy = aZone:getStringFromZoneProperty("ownedBy#", "none")
elseif aZone:hasProperty("ownedBy") then
aZone.ownedBy = aZone:getStringFromZoneProperty("ownedBy", "none")
end
aZone.unbeatable = cfxZones.getBoolFromZoneProperty(aZone, "unbeatable", false)
aZone.untargetable = cfxZones.getBoolFromZoneProperty(aZone, "untargetable", false)
aZone.unbeatable = aZone:getBoolFromZoneProperty("unbeatable", false)
aZone.untargetable = aZone:getBoolFromZoneProperty("untargetable", false)
aZone.hidden = cfxZones.getBoolFromZoneProperty(aZone, "hidden", false)
aZone.hidden = aZone:getBoolFromZoneProperty("hidden", false)
-- individual colors, else default from config
aZone.redLine = cfxZones.getRGBAVectorFromZoneProperty(aZone, "redLine", cfxOwnedZones.redLine)
aZone.redFill = cfxZones.getRGBAVectorFromZoneProperty(aZone, "redFill", cfxOwnedZones.redFill)
aZone.blueLine = cfxZones.getRGBAVectorFromZoneProperty(aZone, "blueLine", cfxOwnedZones.blueLine)
aZone.blueFill = cfxZones.getRGBAVectorFromZoneProperty(aZone, "blueFill", cfxOwnedZones.blueFill)
aZone.neutralLine = cfxZones.getRGBAVectorFromZoneProperty(aZone, "neutralLine", cfxOwnedZones.neutralLine)
aZone.neutralFill = cfxZones.getRGBAVectorFromZoneProperty(aZone, "neutralFill", cfxOwnedZones.neutralFill)
aZone.redLine = aZone:getRGBAVectorFromZoneProperty("redLine", cfxOwnedZones.redLine)
aZone.redFill = aZone:getRGBAVectorFromZoneProperty("redFill", cfxOwnedZones.redFill)
aZone.blueLine = aZone:getRGBAVectorFromZoneProperty("blueLine", cfxOwnedZones.blueLine)
aZone.blueFill = aZone:getRGBAVectorFromZoneProperty("blueFill", cfxOwnedZones.blueFill)
aZone.neutralLine = aZone:getRGBAVectorFromZoneProperty("neutralLine", cfxOwnedZones.neutralLine)
aZone.neutralFill = aZone:getRGBAVectorFromZoneProperty("neutralFill", cfxOwnedZones.neutralFill)
aZone.method = aZone:getStringFromZoneProperty("method", "inc")
cfxOwnedZones.zones[aZone] = aZone
cfxOwnedZones.drawZoneInMap(aZone)
@ -178,32 +178,36 @@ end
function cfxOwnedZones.bangNeutral(value)
if not cfxOwnedZones.neutralTriggerFlag then return end
local newVal = trigger.misc.getUserFlag(cfxOwnedZones.neutralTriggerFlag) + value
trigger.action.setUserFlag(cfxOwnedZones.neutralTriggerFlag, newVal)
--local newVal = trigger.misc.getUserFlag(cfxOwnedZones.neutralTriggerFlag) + value
--trigger.action.setUserFlag(cfxOwnedZones.neutralTriggerFlag, newVal)
cfxZones.pollFlag(cfxOwnedZones.neutralTriggerFlag, cfxOwnedZones.method, cfxOwnedZones)
end
function cfxOwnedZones.bangRed(value)
function cfxOwnedZones.bangRed(value, theZone)
if not cfxOwnedZones.redTriggerFlag then return end
local newVal = trigger.misc.getUserFlag(cfxOwnedZones.redTriggerFlag) + value
trigger.action.setUserFlag(cfxOwnedZones.redTriggerFlag, newVal)
--local newVal = trigger.misc.getUserFlag(cfxOwnedZones.redTriggerFlag) + value
--trigger.action.setUserFlag(cfxOwnedZones.redTriggerFlag, newVal)
cfxZones.pollFlag(cfxOwnedZones.redTriggerFlag, cfxOwnedZones.method, cfxOwnedZones)
end
function cfxOwnedZones.bangBlue(value)
function cfxOwnedZones.bangBlue(value, theZone)
if not cfxOwnedZones.blueTriggerFlag then return end
local newVal = trigger.misc.getUserFlag(cfxOwnedZones.blueTriggerFlag) + value
trigger.action.setUserFlag(cfxOwnedZones.blueTriggerFlag, newVal)
-- trigger.action.setUserFlag(cfxOwnedZones.blueTriggerFlag, newVal)
-- cfxZones.setFlagValue(cfxOwnedZones.blueTriggerFlag, newVal, cfxOwnedZones)
cfxZones.pollFlag(cfxOwnedZones.blueTriggerFlag, cfxOwnedZones.method, cfxOwnedZones)
end
function cfxOwnedZones.bangSide(theSide, value)
function cfxOwnedZones.bangSide(theSide, value, theZone)
if theSide == 2 then
cfxOwnedZones.bangBlue(value)
cfxOwnedZones.bangBlue(value, theZone)
return
end
if theSide == 1 then
cfxOwnedZones.bangRed(value)
cfxOwnedZones.bangRed(value, theZone)
return
end
cfxOwnedZones.bangNeutral(value)
cfxOwnedZones.bangNeutral(value, theZone)
end
function cfxOwnedZones.zoneConquered(aZone, theSide, formerOwner) -- 0 = neutral 1 = RED 2 = BLUE
@ -231,35 +235,35 @@ function cfxOwnedZones.zoneConquered(aZone, theSide, formerOwner) -- 0 = neutral
end
if aZone.conqueredFlag then
cfxZones.pollFlag(aZone.conqueredFlag, "inc", aZone)
aZone:pollFlag(aZone.conqueredFlag, aZone.method)
end
if theSide == 1 and aZone.redCap then
cfxZones.pollFlag(aZone.redCap, "inc", aZone)
aZone:pollFlag(aZone.redCap, aZone.method)
end
if formerOwner == 1 and aZone.redLost then
cfxZones.pollFlag(aZone.redLost, "inc", aZone)
aZone:pollFlag(aZone.redLost, aZone.method)
end
if theSide == 2 and aZone.blueCap then
cfxZones.pollFlag(aZone.blueCap, "inc", aZone)
aZone:pollFlag(aZone.blueCap, aZone.method)
end
if formerOwner == 2 and aZone.blueLost then
cfxZones.pollFlag(aZone.blueLost, "inc", aZone)
aZone:pollFlag(aZone.blueLost, aZone.method)
end
if theSide == 0 and aZone.neutralCap then
cfxZones.pollFlag(aZone.neutralCap, "inc", aZone)
aZone:pollFlag(aZone.neutralCap, aZone.method)
end
-- invoke callbacks now
cfxOwnedZones.invokeConqueredCallbacks(aZone, theSide, formerOwner)
-- bang! flag support
cfxOwnedZones.bangSide(theSide, 1) -- winner
cfxOwnedZones.bangSide(formerOwner, -1) -- loser
cfxOwnedZones.bangSide(theSide, 1, aZone) -- winner
cfxOwnedZones.bangSide(formerOwner, -1, aZone) -- loser
-- update map
cfxOwnedZones.drawZoneInMap(aZone) -- update status in map. will erase previous version
@ -313,13 +317,13 @@ function cfxOwnedZones.update()
if cfxOwnedZones.fastEval then
-- we only check first unit that is alive
local theUnit = dcsCommon.getGroupUnit(aGroup)
if theUnit and (not theUnit:inAir()) and cfxZones.unitInZone(theUnit, theZone) then
if theUnit and (not theUnit:inAir()) and theZone:unitInZone(theUnit) then
theZone.numRed = theZone.numRed + aGroup:getSize()
end
else
local allUnits = aGroup:getUnits()
for idy, theUnit in pairs(allUnits) do
if (not theUnit:inAir()) and cfxZones.unitInZone(theUnit, theZone) then
if (not theUnit:inAir()) and theZone:unitInZone(theUnit) then
theZone.numRed = theZone.numRed + 1
end
end
@ -332,13 +336,13 @@ function cfxOwnedZones.update()
if cfxOwnedZones.fastEval then
-- we only check first unit that is alive
local theUnit = dcsCommon.getGroupUnit(aGroup)
if theUnit and (not theUnit:inAir()) and cfxZones.unitInZone(theUnit, theZone) then
if theUnit and (not theUnit:inAir()) and theZone:unitInZone(theUnit) then
theZone.numBlue = theZone.numBlue + aGroup:getSize()
end
else
local allUnits = aGroup:getUnits()
for idy, theUnit in pairs(allUnits) do
if (not theUnit:inAir()) and cfxZones.unitInZone(theUnit, theZone) then
if (not theUnit:inAir()) and theZone:unitInZone(theUnit) then
theZone.numBlue = theZone.numBlue + 1
end
end
@ -423,7 +427,7 @@ function cfxOwnedZones.update()
-- update ownership flag if exists
if theZone.ownedBy then
cfxZones.setFlagValueMult(theZone.ownedBy, theZone.owner, theZone)
theZone:setFlagValue(theZone.ownedBy, theZone.owner)
end
-- now add this zone to relevant side
@ -440,30 +444,30 @@ function cfxOwnedZones.update()
-- update totals
if cfxOwnedZones.redOwned then
cfxZones.setFlagValueMult(cfxOwnedZones.redOwned, redZoneNum, cfxOwnedZones)
cfxZones.setFlagValue(cfxOwnedZones.redOwned, redZoneNum, cfxOwnedZones)
end
if cfxOwnedZones.blueOwned then
cfxZones.setFlagValueMult(cfxOwnedZones.blueOwned, blueZoneNum, cfxOwnedZones)
cfxZones.setFlagValue(cfxOwnedZones.blueOwned, blueZoneNum, cfxOwnedZones)
end
if cfxOwnedZones.neutralOwned then
cfxZones.setFlagValueMult(cfxOwnedZones.neutralOwned, greyZoneNum, cfxOwnedZones)
cfxZones.setFlagValue(cfxOwnedZones.neutralOwned, greyZoneNum, cfxOwnedZones)
end
if cfxOwnedZones.totalOwnedZones then
cfxZones.setFlagValueMult(cfxOwnedZones.totalOwnedZones, totalZoneNum, cfxOwnedZones)
cfxZones.setFlagValue(cfxOwnedZones.totalOwnedZones, totalZoneNum, cfxOwnedZones)
end
-- see if one side owns all and bang the flags if requiredLibs
if cfxOwnedZones.allBlue and not cfxOwnedZones.hasAllBlue then
if cfxOwnedZones.sideOwnsAll(2) then
cfxZones.pollFlag(cfxOwnedZones.allBlue, "inc", cfxOwnedZones)
cfxZones.pollFlag(cfxOwnedZones.allBlue, cfxOwnedZones.method, cfxOwnedZones)
cfxOwnedZones.hasAllBlue = true
end
end
if cfxOwnedZones.allRed and not cfxOwnedZones.hasAllRed then
if cfxOwnedZones.sideOwnsAll(1) then
cfxZones.pollFlag(cfxOwnedZones.allRed, "inc", cfxOwnedZones)
cfxZones.pollFlag(cfxOwnedZones.allRed, cfxOwnedZones.method, cfxOwnedZones)
cfxOwnedZones.hasAllRed = true
end
end
@ -501,7 +505,7 @@ function cfxOwnedZones.collectZones(mode)
if mode == "land" then
local landZones = {}
for idx, theZone in pairs(cfxOwnedZones.zones) do
p = cfxZones.getPoint(theZone)
p = theZone:getPoint()
p.y = p.z
local surfType = land.getSurfaceType(p)
if surfType == 3 then
@ -539,7 +543,7 @@ function cfxOwnedZones.getNearestOwnedZoneToPoint(aPoint)
local allZones = cfxOwnedZones.collectZones()
for zKey, aZone in pairs(allZones) do
local zPoint = cfxZones.getPoint(aZone)
local zPoint = aZone:getPoint()
currDist = dcsCommon.dist(zPoint, aPoint)
if aZone.untargetable ~= true and
currDist < shortestDist then
@ -554,10 +558,10 @@ end
function cfxOwnedZones.getNearestOwnedZone(theZone)
local shortestDist = math.huge
local closestZone = nil
local aPoint = cfxZones.getPoint(theZone)
local aPoint = theZone:getPoint()
local allZones = cfxOwnedZones.collectZones()
for zKey, aZone in pairs(allZones) do
local zPoint = cfxZones.getPoint(aZone)
local zPoint = aZone:getPoint()
currDist = dcsCommon.dist(zPoint, aPoint)
if aZone.untargetable ~= true and currDist < shortestDist then
shortestDist = currDist
@ -575,13 +579,13 @@ function cfxOwnedZones.getNearestEnemyOwnedZone(theZone, targetNeutral)
local allZones = cfxOwnedZones.collectZones()
local ourEnemy = dcsCommon.getEnemyCoalitionFor(theZone.owner)
if not ourEnemy then return nil end -- we called for a neutral zone. they have no enemies
local zPoint = cfxZones.getPoint(theZone)
local zPoint = theZone:getPoint()
for zKey, aZone in pairs(allZones) do
if targetNeutral then
-- return all zones that do not belong to us
if aZone.owner ~= theZone.owner then
local aPoint = cfxZones.getPoint(aZone)
local aPoint = aZone:getPoint()
currDist = dcsCommon.dist(aPoint, zPoint)
if aZone.untargetable ~= true and currDist < shortestDist then
shortestDist = currDist
@ -591,7 +595,7 @@ function cfxOwnedZones.getNearestEnemyOwnedZone(theZone, targetNeutral)
else
-- return zones that are taken by the Enenmy
if aZone.owner == ourEnemy then -- only check own zones
local aPoint = cfxZones.getPoint(aZone)
local aPoint = aZone:getPoint()
currDist = dcsCommon.dist(zPoint, aPoint)
if aZone.untargetable ~= true and currDist < shortestDist then
shortestDist = currDist
@ -610,14 +614,14 @@ function cfxOwnedZones.getNearestFriendlyZone(theZone, targetNeutral)
local closestZone = nil
local ourEnemy = dcsCommon.getEnemyCoalitionFor(theZone.owner)
if not ourEnemy then return nil end -- we called for a neutral zone. they have no enemies nor friends, all zones would be legal.
local zPoint = cfxZones.getPoint(theZone)
local zPoint = theZone:getPoint()
local allZones = cfxOwnedZones.collectZones()
for zKey, aZone in pairs(allZones) do
if targetNeutral then
-- target all zones that do not belong to the enemy
if aZone.owner ~= ourEnemy then
local aPoint = cfxZones.getPoint(aZone)
local aPoint = aZone:getPoint()
currDist = dcsCommon.dist(zPoint, aPoint)
if aZone.untargetable ~= true and currDist < shortestDist then
shortestDist = currDist
@ -627,7 +631,7 @@ function cfxOwnedZones.getNearestFriendlyZone(theZone, targetNeutral)
else
-- only target zones that are taken by us
if aZone.owner == theZone.owner then -- only check own zones
local aPoint = cfxZones.getPoint(aZone)
local aPoint = aZone:getPoint()
currDist = dcsCommon.dist(zPoint, aPoint)
if aZone.untargetable ~= true and currDist < shortestDist then
shortestDist = currDist
@ -659,7 +663,7 @@ function cfxOwnedZones.saveData()
local zoneData = {}
if theZone.conqueredFlag then
zoneData.conquered = cfxZones.getFlagValue(theZone.conqueredFlag, theZone)
zoneData.conquered = theZone:getFlagValue(theZone.conqueredFlag)
end
zoneData.owner = theZone.owner
@ -700,7 +704,7 @@ function cfxOwnedZones.loadData()
if theZone then
theZone.owner = zData.owner
if zData.conquered then
cfxZones.setFlagValue(theZone.conqueredFlag, zData.conquered, theZone)
theZone:setFlagValue(theZone.conqueredFlag, zData.conquered)
end
-- update mark in map
cfxOwnedZones.drawZoneInMap(theZone)
@ -724,72 +728,73 @@ function cfxOwnedZones.readConfigZone(theZone)
if not theZone then theZone = cfxZones.createSimpleZone("ownedZonesConfig") end
cfxOwnedZones.name = "cfxOwnedZones" -- just in case, so we can access with cfxZones
cfxOwnedZones.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
cfxOwnedZones.announcer = cfxZones.getBoolFromZoneProperty(theZone, "announcer", true)
cfxOwnedZones.verbose = theZone.verbose -- cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
cfxOwnedZones.announcer = theZone:getBoolFromZoneProperty("announcer", true)
if cfxZones.hasProperty(theZone, "r!") then
cfxOwnedZones.redTriggerFlag = cfxZones.getStringFromZoneProperty(theZone, "r!", "*<cfxnone>")
if theZone:hasProperty("r!") then
cfxOwnedZones.redTriggerFlag = theZone:getStringFromZoneProperty("r!", "*<cfxnone>")
else
cfxOwnedZones.redTriggerFlag = cfxZones.getStringFromZoneProperty(theZone, "r#", "*<cfxnone>")
cfxOwnedZones.redTriggerFlag = theZone:getStringFromZoneProperty("r#", "*<cfxnone>")
end
if cfxZones.hasProperty(theZone, "b!") then
cfxOwnedZones.redTriggerFlag = cfxZones.getStringFromZoneProperty(theZone, "b!", "*<cfxnone>")
if theZone:hasProperty("b!") then
cfxOwnedZones.redTriggerFlag = theZone:getStringFromZoneProperty("b!", "*<cfxnone>")
else
cfxOwnedZones.blueTriggerFlag = cfxZones.getStringFromZoneProperty(theZone, "b#", "*<cfxnone>")
cfxOwnedZones.blueTriggerFlag = theZone:getStringFromZoneProperty("b#", "*<cfxnone>")
end
if cfxZones.hasProperty(theZone, "n!") then
cfxOwnedZones.redTriggerFlag = cfxZones.getStringFromZoneProperty(theZone, "n!", "*<cfxnone>")
if theZone:hasProperty("n!") then
cfxOwnedZones.redTriggerFlag = theZone:getStringFromZoneProperty("n!", "*<cfxnone>")
else
cfxOwnedZones.neutralTriggerFlag = cfxZones.getStringFromZoneProperty(theZone, "n#", "*<cfxnone>")
cfxOwnedZones.neutralTriggerFlag = theZone:getStringFromZoneProperty("n#", "*<cfxnone>")
end
-- allXXX flags
if cfxZones.hasProperty(theZone, "allBlue!") then
cfxOwnedZones.allBlue = cfxZones.getStringFromZoneProperty(theZone, "allBlue!", "*<cfxnone>")
if theZone:hasProperty("allBlue!") then
cfxOwnedZones.allBlue = theZone:getStringFromZoneProperty( "allBlue!", "*<cfxnone>")
cfxOwnedZones.hasAllBlue = nil
end
if cfxZones.hasProperty(theZone, "allRed!") then
cfxOwnedZones.allRed = cfxZones.getStringFromZoneProperty(theZone, "allRed!", "*<cfxnone>")
if theZone:hasProperty("allRed!") then
cfxOwnedZones.allRed = theZone:getStringFromZoneProperty("allRed!", "*<cfxnone>")
cfxOwnedZones.hasAllRed = nil
end
if cfxZones.hasProperty(theZone, "redOwned#") then
cfxOwnedZones.redOwned = cfxZones.getStringFromZoneProperty(theZone, "redOwned#", "*<cfxnone>")
if theZone:hasProperty("redOwned#") then
cfxOwnedZones.redOwned = theZone:getStringFromZoneProperty("redOwned#", "*<cfxnone>")
end
if cfxZones.hasProperty(theZone, "blueOwned#") then
cfxOwnedZones.blueOwned = cfxZones.getStringFromZoneProperty(theZone, "blueOwned#", "*<cfxnone>")
if theZone:hasProperty("blueOwned#") then
cfxOwnedZones.blueOwned = theZone:getStringFromZoneProperty( "blueOwned#", "*<cfxnone>")
end
if cfxZones.hasProperty(theZone, "neutralOwned#") then
cfxOwnedZones.neutralOwned = cfxZones.getStringFromZoneProperty(theZone, "neutralOwned#", "*<cfxnone>")
if theZone:hasProperty("neutralOwned#") then
cfxOwnedZones.neutralOwned = theZone:getStringFromZoneProperty("neutralOwned#", "*<cfxnone>")
end
if cfxZones.hasProperty(theZone, "totalZones#") then
cfxOwnedZones.totalOwnedZones = cfxZones.getStringFromZoneProperty(theZone, "totalZones#", "*<cfxnone>")
if theZone:hasProperty("totalZones#") then
cfxOwnedZones.totalOwnedZones = theZone:getStringFromZoneProperty("totalZones#", "*<cfxnone>")
end
-- numKeep, numCap, fastEval, easyContest
cfxOwnedZones.numCap = cfxZones.getNumberFromZoneProperty(theZone, "numCap", 1) -- minimal number of units required to cap zone
cfxOwnedZones.numKeep = cfxZones.getNumberFromZoneProperty(theZone, "numKeep", 0) -- number required to keep zone
cfxOwnedZones.fastEval = cfxZones.getBoolFromZoneProperty(theZone, "fastEval", true)
cfxOwnedZones.easyContest = cfxZones.getBoolFromZoneProperty(theZone, "easyContest", false)
cfxOwnedZones.numCap = theZone:getNumberFromZoneProperty("numCap", 1) -- minimal number of units required to cap zone
cfxOwnedZones.numKeep = theZone:getNumberFromZoneProperty("numKeep", 0) -- number required to keep zone
cfxOwnedZones.fastEval = theZone:getBoolFromZoneProperty("fastEval", true)
cfxOwnedZones.easyContest = theZone:getBoolFromZoneProperty("easyContest", false)
-- winSound, loseSound
cfxOwnedZones.winSound = cfxZones.getStringFromZoneProperty(theZone, "winSound", "Quest Snare 3.wav" )
cfxOwnedZones.loseSound = cfxZones.getStringFromZoneProperty(theZone, "loseSound", "Death BRASS.wav")
cfxOwnedZones.winSound = theZone:getStringFromZoneProperty("winSound", "Quest Snare 3.wav")
cfxOwnedZones.loseSound = theZone:getStringFromZoneProperty("loseSound", "Death BRASS.wav")
-- capture options
cfxOwnedZones.groundCap = cfxZones.getBoolFromZoneProperty(theZone, "groundCap", true)
cfxOwnedZones.navalCap = cfxZones.getBoolFromZoneProperty(theZone, "navalCap", false)
cfxOwnedZones.heloCap = cfxZones.getBoolFromZoneProperty(theZone, "heloCap")
cfxOwnedZones.fixWingCap = cfxZones.getBoolFromZoneProperty(theZone, "fixWingCap")
cfxOwnedZones.groundCap = theZone:getBoolFromZoneProperty("groundCap", true)
cfxOwnedZones.navalCap = theZone:getBoolFromZoneProperty("navalCap", false)
cfxOwnedZones.heloCap = theZone:getBoolFromZoneProperty("heloCap")
cfxOwnedZones.fixWingCap = theZone:getBoolFromZoneProperty("fixWingCap")
-- colors for line and fill
cfxOwnedZones.redLine = cfxZones.getRGBAVectorFromZoneProperty(theZone, "redLine", {1.0, 0, 0, 1.0})
cfxOwnedZones.redFill = cfxZones.getRGBAVectorFromZoneProperty(theZone, "redFill", {1.0, 0, 0, 0.2})
cfxOwnedZones.blueLine = cfxZones.getRGBAVectorFromZoneProperty(theZone, "blueLine", {0.0, 0, 1.0, 1.0})
cfxOwnedZones.blueFill = cfxZones.getRGBAVectorFromZoneProperty(theZone, "blueFill", {0.0, 0, 1.0, 0.2})
cfxOwnedZones.neutralLine = cfxZones.getRGBAVectorFromZoneProperty(theZone, "neutralLine", {0.8, 0.8, 0.8, 1.0})
cfxOwnedZones.neutralFill = cfxZones.getRGBAVectorFromZoneProperty(theZone, "neutralFill", {0.8, 0.8, 0.8, 0.2})
cfxOwnedZones.redLine = theZone:getRGBAVectorFromZoneProperty("redLine", {1.0, 0, 0, 1.0})
cfxOwnedZones.redFill = theZone:getRGBAVectorFromZoneProperty("redFill", {1.0, 0, 0, 0.2})
cfxOwnedZones.blueLine = theZone:getRGBAVectorFromZoneProperty("blueLine", {0.0, 0, 1.0, 1.0})
cfxOwnedZones.blueFill = theZone:getRGBAVectorFromZoneProperty("blueFill", {0.0, 0, 1.0, 0.2})
cfxOwnedZones.neutralLine = theZone:getRGBAVectorFromZoneProperty("neutralLine", {0.8, 0.8, 0.8, 1.0})
cfxOwnedZones.neutralFill = theZone:getRGBAVectorFromZoneProperty("neutralFill", {0.8, 0.8, 0.8, 0.2})
cfxOwnedZones.method = theZone:getStringFromZoneProperty("method", "inc")
end
function cfxOwnedZones.init()

View File

@ -1444,11 +1444,11 @@ function cfxPlayerScore.start()
-- identify and process a score table zones
local theZone = cfxZones.getZoneByName("playerScoreTable")
if not theZone then
trigger.action.outText("+++scr: no score table!", 30)
-- trigger.action.outText("+++scr: no score table!", 30)
else
-- read all into my types registry, replacing whatever is there
cfxPlayerScore.typeScore = cfxZones.getAllZoneProperties(theZone)
trigger.action.outText("+++scr: read score table", 30)
-- trigger.action.outText("+++scr: read score table", 30)
end
-- read score tiggers and values
@ -1486,7 +1486,7 @@ function cfxPlayerScore.start()
-- now read my config zone
local theZone = cfxZones.getZoneByName("playerScoreConfig")
if not theZone then
trigger.action.outText("+++pScr: no config!", 30)
-- trigger.action.outText("+++pScr: no config!", 30)
theZone = cfxZones.createSimpleZone("playerScoreConfig")
end
cfxPlayerScore.readConfigZone(theZone)

View File

@ -1,5 +1,5 @@
cfxSpawnZones = {}
cfxSpawnZones.version = "2.0.0"
cfxSpawnZones.version = "2.0.1"
cfxSpawnZones.requiredLibs = {
"dcsCommon", -- common is of course needed for everything
-- pretty stupid to check for this since we
@ -72,6 +72,7 @@ cfxSpawnZones.spawnedGroups = {}
- moved "types" to spawner
- baseName defaults to zone name, as it is safe for naming
- spawnWithSpawner direct link in spawner to spawnZones
2.0.1 - fix in verifySpawnOwnership() when not master zone found
--]]--
cfxSpawnZones.allSpawners = {}
@ -275,6 +276,7 @@ function cfxSpawnZones.verifySpawnOwnership(spawner)
local masterZone = cfxZones.getZoneByName(spawner.masterZoneName)
if not masterZone then
trigger.action.outText("spawner " .. spawner.name .. " DID NOT FIND MASTER ZONE <" .. spawner.masterZoneName .. ">", 30)
return false
end
if not masterZone.owner then

View File

@ -1,117 +1,14 @@
cfxZones = {}
cfxZones.version = "4.0.5"
cfxZones.version = "4.0.7"
-- cf/x zone management module
-- reads dcs zones and makes them accessible and mutable
-- by scripting.
--
-- Copyright (c) 2021, 2022 by Christian Franz and cf/x AG
-- Copyright (c) 2021 - 2023 by Christian Franz and cf/x AG
--
--[[-- VERSION HISTORY
- 2.2.4 - getCoalitionFromZoneProperty
- getStringFromZoneProperty
- 2.2.5 - createGroundUnitsInZoneForCoalition corrected coalition --> country
- 2.2.6 - getVectorFromZoneProperty(theZone, theProperty, defaultVal)
- 2.2.7 - allow 'yes' as 'true' for boolean attribute
- 2.2.8 - getBoolFromZoneProperty supports default
- cfxZones.hasProperty
- 2.3.0 - property names are case insensitive
- 2.3.1 - getCoalitionFromZoneProperty allows 0, 1, 2 also
- 2.4.0 - all zones look for owner attribute, and set it to 0 (neutral) if not present
- 2.4.1 - getBoolFromZoneProperty upgraded by expected bool
- markZoneWithSmoke raised by 3 meters
- 2.4.2 - getClosestZone also returns delta
- 2.4.3 - getCoalitionFromZoneProperty() accepts 'all' as neutral
createUniqueZoneName()
getStringFromZoneProperty returns default if property value = ""
corrected bug in addZoneToManagedZones
- 2.4.4 - getPoint(aZone) returns uip-to-date pos for linked and normal zones
- linkUnit can use "useOffset" property to keep relative position
- 2.4.5 - updated various methods to support getPoint when referencing
zone.point
- 2.4.6 - corrected spelling in markZoneWithSmoke
- 2.4.7 - copy reference to dcs zone into cfx zone
- 2.4.8 - getAllZoneProperties
- 2.4.9 - createSimpleZone no longer requires location
- parse dcs adds empty .properties = {} if none tehre
- createCircleZone adds empty properties
- createPolyZone adds empty properties
- 2.4.10 - pickRandomZoneFrom now defaults to all cfxZones.zones
- getBoolFromZoneProperty also recognizes 0, 1
- removed autostart
- 2.4.11 - removed typo in get closest zone
- 2.4.12 - getStringFromZoneProperty
- 2.5.0 - harden getZoneProperty and all getPropertyXXXX
- 2.5.1 - markZoneWithSmoke supports alt attribute
- 2.5.2 - getPoint also writes through to zone itself for optimization
- new method getPositiveRangeFromZoneProperty(theZone, theProperty, default)
- 2.5.3 - new getAllGroupsInZone()
- 2.5.4 - cleaned up getZoneProperty break on no properties
- 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
- 2.5.7 - pollFlag supports dml flags
- 2.5.8 - flagArrayFromString
- getFlagNumber invokes tonumber() before returning result
- 2.5.9 - removed pass-back flag in getPoint()
- 2.6.0 - testZoneFlag() method based flag testing
- 2.6.1 - Watchflag parsing of zone condition for number-named flags
- case insensitive
- verbose for zone-local accepted (but not acted upon)
- hasProperty now offers active information when looking for '*?' and '*!'
- 2.7.0 - doPollFlag - fully support multiple flags per bang!
- 2.7.1 - setFlagValueMult()
- 2.7.2 - '261 repair'
- 2.7.3 - testZoneFlag returns mathodResult, lastVal
- evalFlagMethodImmediate()
- 2.7.4 - doPollFlag supports immediate number setting
- 2.7.5 - more QoL checks when mixing up ? and ! for attributes
- 2.7.6 - trim for getBoolFromZoneProperty and getStringFromZoneProperty
- 2.7.7 - randomInRange()
- show number of zones
- 2.7.8 - inc method now triggers if curr value > last value
- dec method noew triggers when curr value < last value
- testFlagByMethodForZone supports lohi, hilo transitions
- doPollFlag supports 'pulse'
- pulseFlag
- unpulse
- 2.7.9 - getFlagValue QoL for <none>
- setFlagValue QoL for <none>
- 2.8.0 - new allGroupNamesInZone()
- 2.8.1 - new zonesLinkedToUnit()
- 2.8.2 - flagArrayFromString trims elements before range check
- 2.8.3 - new verifyMethod()
- changed extractPropertyFromDCS() to also match attributes with blanks like "the Attr" to "theAttr"
- new expandFlagName()
- 2.8.4 - fixed bug in setFlagValue()
- 2.8.5 - createGroundUnitsInZoneForCoalition() now always passes back a copy of the group data
- data also contains cty = country and cat = category for easy spawn
- getFlagValue additional zone name guards
- 2.8.6 - fix in getFlagValue for missing delay
- 2.8.7 - update isPointInsideZone(thePoint, theZone, radiusIncrease) - new radiusIncrease
- isPointInsideZone() returns delta as well
- 2.9.0 - linked zones can useOffset and useHeading
- getPoint update
- pointInZone understands useOrig
- allStaticsInZone supports useOrig
- dPhi for zones with useHeading
- uHdg for zones with useHading, contains linked unit's original heading
- Late-linking implemented:
- linkUnit works for late-activating units
- linkUnit now also works for player / clients, dynamic (re-)linking
- linkUnit uses zone's origin for all calculations
- 2.9.1 - new evalRemainder()
- pollFlag supports +/- for immediate numbers, flags, number flags in parantheses
- stronger guards in hasProperty
- 2.9.2 - new createRandomPointInPolyZone()
- createRandomZoneInZone uses createRandomPointInPolyZone
- new createRandomPointInZone()
- new randomPointInZone()
- 3.0.0 - support for DCS 2.8 linkUnit attribute, integration with
linedUnit and warning.
- initZoneVerbosity()
@ -157,6 +54,8 @@ cfxZones.version = "4.0.5"
- doSetFlagValue optimizations
- 4.0.5 - dynamicAB wildcard
- processDynamicValueVU
- 4.0.6 - hash mark forgotten QoL
- 4.0.7 - drawZone()
--]]--
@ -2208,6 +2107,30 @@ function cfxZones.flagArrayFromString(inString) -- dcsCommon bridge
end
--
-- Drawing a Zone
--
function cfxZones.drawZone(theZone, lineColor, fillColor, markID)
if not theZone then return 0 end
if not lineColor then lineColor = {0.8, 0.8, 0.8, 1.0} end
if not fillColor then fillColor = {0.8, 0.8, 0.8, 0.2} end
if not markID then markID = dcsCommon.numberUUID() end
if theZone.isCircle then
trigger.action.circleToAll(-1, markID, theZone.point, theZone.radius, lineColor, fillColor, 1, true, "")
else
local poly = theZone.poly
trigger.action.quadToAll(-1, markID, poly[4], poly[3], poly[2], poly[1], lineColor, fillColor, 1, true, "") -- note: left winding to get fill color
end
return markID
end
function dmlZone:drawZone(lineColor, fillColor, markID)
return cfxZones.drawZone(self, lineColor, fillColor, markID)
end
--
-- ===================
-- PROPERTY PROCESSING
@ -2444,6 +2367,14 @@ function cfxZones.hasProperty(theZone, theProperty)
return false
end
if string.sub(theProperty, -1) == "#" then
local lessOp = theProperty:sub(1,-2)
if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then
trigger.action.outText("*** NOTE: " .. theZone.name .. "'s property <" .. lessOp .. "> may be missing a hash mark ('#') at end", 30)
end
return false
end
return false
end
return true

View File

@ -1,25 +1,13 @@
limitedAirframes = {}
limitedAirframes.version = "1.5.4"
limitedAirframes.verbose = false
limitedAirframes.enabled = true -- can be turned off
limitedAirframes.userCanToggle = true -- F10 menu?
limitedAirframes.onlyOwnSide = true -- F10 query only shows own side count, for later expansion
limitedAirframes.maxRed = -1 -- -1 == infinite
limitedAirframes.maxBlue = -1 -- = infinite
limitedAirframes.redWinsFlag = "999"
limitedAirframes.blueWinsFlag = "998"
limitedAirframes.method = "inc"
limitedAirframes.version = "1.6.0"
limitedAirframes.warningSound = "Quest Snare 3.wav"
limitedAirframes.loseSound = "Death PIANO.wav"
limitedAirframes.winSound = "Triumphant Victory.wav"
limitedAirframes.announcer = true
limitedAirframes.requiredLibs = {
"dcsCommon", -- common is of course needed for everything
-- pretty stupid to check for this since we
-- need common to invoke the check, but anyway
"cfxZones", -- Zones, of course for safe landings
-- "cfxPlayer", no longer needed
"dcsCommon",
"cfxZones",
}
--[[-- VERSION HISTORY
@ -57,6 +45,10 @@ limitedAirframes.requiredLibs = {
- 1.5.3 - ... but do allow it if not coming from 'ejected' so ditching
a plane will again create CSAR missions
1.5.4 - red# and blue# instead of #red and #blue
1.6.0 - dmlZones
- new hasUI attribute
- minor clean-up
- set numRed and numBlue on startup
--]]--
@ -66,26 +58,15 @@ limitedAirframes.requiredLibs = {
-- when the number reaches -1 or smaller, other side wins
-- !!!Only affects player planes!!
-- *** EXTENDS ZONES ***
-- safe zones must have a property "pilotSafe"
-- - pilotSafe - this is a zone to safely change airframes in
-- - can also carry 'red' or 'blue' to enable
-- - redSafe (optional, defaults to true)
-- - blueSafe (optional, defaults to true)
-- set to "false" or "no" to disallow that side to change
-- airframes even when safer
-- if zone can change ownership, player's coalition
-- is checked against current zone ownership
-- zone owner.
-- when red wins due to blue frame loss, flag 999 is set to true
-- when blue wins due to red frame loss, flag 998 is set to true
-- set a mission trigger to end mission if you want to end mission
-- or simply keep running, and a CHEATER! message will flash
-- every time the losing side enters a new aircraft
limitedAirframes.safeZones = {} -- safezones are zones where a crash or change plane does not
-- these zones are created by adding an 'pilotSafe' attribute
limitedAirframes.myEvents = {5, 9, 30, 6, 20, 21, 15 } -- 5 = crash, 9 - dead, 30 - unit lost, 6 - eject, 20 - enter unit, 21 - leave unit, 15 - birth
@ -124,67 +105,71 @@ function limitedAirframes.readConfigZone()
-- note: must match exactly!!!!
local theZone = cfxZones.getZoneByName("limitedAirframesConfig")
if not theZone then
if limitedAirframes.verbose then
trigger.action.outText("+++limA: NO config zone!", 30)
end
theZone = cfxZones.createSimpleZone("limitedAirframesConfig")
end
-- remember me
limitedAirframes.config = theZone
limitedAirframes.name = "limitedAirframes" -- so we can call cfxZones with ourself as param
limitedAirframes.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
limitedAirframes.verbose = theZone.verbose
if limitedAirframes.verbose then
trigger.action.outText("+++limA: found config zone!", 30)
end
-- ok, for each property, load it if it exists
limitedAirframes.enabled = cfxZones.getBoolFromZoneProperty(theZone, "enabled", true)
limitedAirframes.enabled = theZone:getBoolFromZoneProperty("enabled", true)
limitedAirframes.userCanToggle = cfxZones.getBoolFromZoneProperty(theZone, "userCanToggle", true)
limitedAirframes.userCanToggle = theZone:getBoolFromZoneProperty( "userCanToggle", true)
limitedAirframes.hasUI = theZone:getBoolFromZoneProperty("hasUI", true)
limitedAirframes.maxRed = theZone:getNumberFromZoneProperty("maxRed", -1)
limitedAirframes.maxRed = cfxZones.getNumberFromZoneProperty(theZone, "maxRed", -1)
limitedAirframes.maxBlue = theZone:getNumberFromZoneProperty("maxBlue", -1)
limitedAirframes.currRed = limitedAirframes.maxRed
limitedAirframes.currBlue = limitedAirframes.maxBlue
limitedAirframes.maxBlue = cfxZones.getNumberFromZoneProperty(theZone, "maxBlue", -1)
if cfxZones.hasProperty(theZone, "#red") then
limitedAirframes.numRed = cfxZones.getStringFromZoneProperty(theZone, "#red", "*none")
if theZone:hasProperty("#red") then
limitedAirframes.numRed = theZone:getStringFromZoneProperty("#red", "*none")
else
limitedAirframes.numRed = cfxZones.getStringFromZoneProperty(theZone, "red#", "*none")
limitedAirframes.numRed = theZone:getStringFromZoneProperty("red#", "*none")
end
if cfxZones.hasProperty(theZone, "#blue") then
limitedAirframes.numBlue = cfxZones.getStringFromZoneProperty(theZone, "#blue", "*none")
if theZone:hasProperty("#blue") then
limitedAirframes.numBlue = theZone:getStringFromZoneProperty("#blue", "*none")
else
limitedAirframes.numBlue = cfxZones.getStringFromZoneProperty(theZone, "blue#", "*none")
limitedAirframes.numBlue = theZone:getStringFromZoneProperty("blue#", "*none")
end
limitedAirframes.redWinsFlag = cfxZones.getStringFromZoneProperty(theZone, "redWins!", "*none")
limitedAirframes.redWinsFlag = theZone:getStringFromZoneProperty("redWins!", "*none")
if cfxZones.hasProperty(theZone, "redWinsFlag!") then
limitedAirframes.redWinsFlag = cfxZones.getStringFromZoneProperty(theZone, "redWinsFlag!", "*none")
if theZone:hasProperty("redWinsFlag!") then
limitedAirframes.redWinsFlag = theZone:getStringFromZoneProperty("redWinsFlag!", "*none")
end
limitedAirframes.blueWinsFlag = cfxZones.getStringFromZoneProperty(theZone, "blueWins!", "*none")
if cfxZones.hasProperty(theZone, "blueWinsFlag!") then
limitedAirframes.blueWinsFlag = cfxZones.getStringFromZoneProperty(theZone, "blueWinsFlag!", "*none")
limitedAirframes.blueWinsFlag = theZone:getStringFromZoneProperty("blueWins!", "*none")
if theZone:hasProperty("blueWinsFlag!") then
limitedAirframes.blueWinsFlag = theZone:getStringFromZoneProperty("blueWinsFlag!", "*none")
end
limitedAirframes.method = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
limitedAirframes.method = theZone:getStringFromZoneProperty("method", "inc")
if cfxZones.hasProperty(theZone, "warningSound") then
limitedAirframes.warningSound = cfxZones.getStringFromZoneProperty(theZone, "warningSound", "none")
if theZone:hasProperty("warningSound") then
limitedAirframes.warningSound = theZone:getStringFromZoneProperty("warningSound", "none")
end
if cfxZones.hasProperty(theZone, "winSound") then
limitedAirframes.winSound = cfxZones.getStringFromZoneProperty(theZone, "winSound", "none")
if theZone:hasProperty("winSound") then
limitedAirframes.winSound = theZone:getStringFromZoneProperty("winSound", "none")
end
if cfxZones.hasProperty(theZone, "loseSound") then
limitedAirframes.loseSound = cfxZones.getStringFromZoneProperty(theZone, "loseSound", "none")
if theZone:hasProperty("loseSound") then
limitedAirframes.loseSound = theZone:getStringFromZoneProperty("loseSound", "none")
end
limitedAirframes.announcer = cfxZones.getBoolFromZoneProperty(theZone, "announcer", true)
if limitedAirframes.numRed then
cfxZones.setFlagValue(limitedAirframes.numRed, limitedAirframes.currRed, limitedAirframes)
end
if limitedAirframes.numBlue then
cfxZones.setFlagValue(limitedAirframes.numBlue, limitedAirframes.currBlue, limitedAirframes)
end
limitedAirframes.announcer = theZone:getBoolFromZoneProperty( "announcer", true)
end
--
@ -219,7 +204,7 @@ function limitedAirframes.addPlayerUnit(theUnit)
local desc = "unit <" .. uName .. "> controlled by <" .. pName .. ">"
if not(limitedAirframes.isKnownUnitName(uName)) then
--desc = "+++lim: added ".. desc .. " to list of known player units"
else
if limitedAirframes.playerUnits[uName] == pName then
desc = "player unit <".. uName .. "> controlled by <".. limitedAirframes.playerUnits[uName].."> re-seated"
@ -269,7 +254,6 @@ function limitedAirframes.updatePlayer(pName, status)
end
limitedAirframes.players[pName] = status
-- if desc then trigger.action.outText(desc, 30) end
end
function limitedAirframes.getStatusOfPlayerInUnit(theUnit)
@ -327,7 +311,6 @@ function limitedAirframes.preProcessor(event)
return false -- no longer of interest
end
if not dcsCommon.isPlayerUnit(theUnit) then
-- not a player unit. Events 5 and 6 have been
-- handled before, so we can safely ignore
@ -376,8 +359,8 @@ function limitedAirframes.somethingHappened(event)
if ID == 20 then -- 20 ENTER UNIT
local pName = limitedAirframes.getKnownUnitPilotByUnit(theUnit)
if not pName then pName = "***UNKNOWN***" end
-- local pName = limitedAirframes.getKnownUnitPilotByUnit(theUnit)
-- if not pName then pName = "***UNKNOWN***" end
return
end
@ -401,8 +384,7 @@ function limitedAirframes.somethingHappened(event)
trigger.action.outText("limAir: ***WARNING: Ignored player event (" .. ID .. "): unable to retrieve player name for " .. unitName, 30)
return -- plane no longer of interest cant retrieve pilot -- BUG!!!
end
-- event 6 - eject - plane divorced but player pilot is known
if ID == 6 then -- eject
limitedAirframes.pilotEjected(event)
@ -422,7 +404,6 @@ function limitedAirframes.somethingHappened(event)
-- so if pilot is still alive and not MIA, he's now dead.
-- forget the helo check, this now applies to all
local pStatus = limitedAirframes.getStatusOfPlayerInUnit(theUnit)
if pStatus == "alive" then
-- this frame was carrrying a live player
@ -441,7 +422,7 @@ function limitedAirframes.somethingHappened(event)
if ID == 21 then -- player left unit
-- remove pilot name from unit name
limitedAirframes.unitFlownByPlayer[unitName] = nil
--trigger.action.outText("limAir: 21 -- unit " .. unitName .. " unoccupied", 30)
if limitedAirframes.verbose then
trigger.action.outText("limAir: 21 (player left) for unit " .. unitName , 30)
end
@ -453,7 +434,6 @@ function limitedAirframes.somethingHappened(event)
if ID == 9 then -- died
--trigger.action.outText("limAir: 9 (PILOT DEAD) for unit " .. unitName , 30)
local thePilot = limitedAirframes.unitFlownByPlayer[unitName]
if not thePilot then
if limitedAirframes.verbose then
@ -514,27 +494,11 @@ function limitedAirframes.handlePlayerLeftUnit(event)
if limitedAirframes.verbose then
trigger.action.outText("+++limA: " .. theSafeZone.name .. " ownership: myside = " .. mySide .. " zone owner is " .. theSafeZone.owner, 30)
end
else
end
-- check we are at rest below 10m height. agl may give
-- misreadings on carriers and FARPs, while speed may read
-- wrongly on carriers (tbd). we now use isInAir to determine if
-- we ditched while in flight
--if speed > 2 or agl > 10 then isSafe = false end
--if not isInAir then return false end -- why *not* isInAir???
-- for matter of fact, why did we return ANYTHING???
-- there may be a bug here
-- maybe it should be "if isInAir then isSafe = false"??
if isInAir then isSafe = false end
if isSafe then
-- if limitedAirframes.announcer then
-- trigger.action.outTextForCoalition(mySide, "Pilot " .. theUnit:getPlayerName() .. " left unit " .. theUnit:getName() .. " legally in zone " .. theSafeZone.name, 30)
-- end
return;
end
end
@ -576,7 +540,6 @@ function limitedAirframes.pilotEjected(event)
end
function limitedAirframes.pilotDied(theUnit)
--limitedAirframes.killPlayerInUnit(theUnit)
local theSide = theUnit:getCoalition()
local pilot = limitedAirframes.getKnownUnitPilotByUnit(theUnit)
local uName = theUnit:getName()
@ -649,9 +612,7 @@ function limitedAirframes.pilotLost(theUnit)
return true
end
trigger.action.outSoundForCoalition(theSide, limitedAirframes.warningSound)
-- if limitedAirframes.announcer then
trigger.action.outTextForCoalition(theSide, "You have lost a pilot! Remaining: " .. limitedAirframes.currBlue, 30)
-- end
end
return false
end
@ -706,24 +667,19 @@ function limitedAirframes.addSafeZone(aZone)
trigger.action.outText("WARNING: NIL Zone in addSafeZone", 30)
return
end
-- transfer properties if they exist
-- blueSafe, redSafe: what side this is safe for, default = yes
-- add zone to my list
limitedAirframes.safeZones[aZone] = aZone
-- deprecated old code. new code contains 'red, blue' in value for pilotsafe
local safeSides = cfxZones.getStringFromZoneProperty(aZone, "pilotsafe", "")
local safeSides = aZone:getStringFromZoneProperty("pilotsafe", "")
safeSides = safeSides:lower()
if dcsCommon.containsString(safeSides, "red") or dcsCommon.containsString(safeSides, "blue") then
aZone.redSafe = dcsCommon.containsString(safeSides, "red")
aZone.blueSafe = dcsCommon.containsString(safeSides, "blue")
else
--aZone.redSafe = true
aZone.redSafe = cfxZones.getBoolFromZoneProperty(aZone, "redSafe", true)
--aZone.blueSafe = true
aZone.blueSafe = cfxZones.getBoolFromZoneProperty(aZone, "blueSafe", true)
aZone.redSafe = aZone:getBoolFromZoneProperty("redSafe", true)
aZone.blueSafe = aZone:getBoolFromZoneProperty("blueSafe", true)
end
if limitedAirframes.verbose or aZone.verbose then
@ -733,14 +689,10 @@ function limitedAirframes.addSafeZone(aZone)
if aZone.blueSafe then
trigger.action.outText("+++limA: <" .. aZone.name .. "> is safe for BLUE pilots", 30)
end
trigger.action.outText("+++limA: added safeZone " .. aZone.name, 30)
end
end
--
-- COMMAND & CONFIGURATION
--
@ -751,10 +703,13 @@ function limitedAirframes.setCommsMenu()
desc = "Pilot Count (Currently OFF)"
desc2 = "ENABLE Pilot Count"
end
if not limitedAirframes.userCanToggle then desc = "Pilot Count" end
-- remove previous version
if limitedAirframes.rootMenu then
missionCommands.removeItem(limitedAirframes.theScore)
missionCommands.removeItem(limitedAirframes.theCommand)
missionCommands.removeItem(limitedAirframes.theScore) -- frames left
if limitedAirframes.userCanToggle then
missionCommands.removeItem(limitedAirframes.theCommand) -- toggle on/off
end
missionCommands.removeItem(limitedAirframes.rootMenu)
end
limitedAirframes.theCommand = nil
@ -765,7 +720,9 @@ function limitedAirframes.setCommsMenu()
limitedAirframes.theScore = missionCommands.addCommand("How many airframes left?" , limitedAirframes.rootMenu, limitedAirframes.redirectAirframeScore, {"none"})
limitedAirframes.theCommand = missionCommands.addCommand(desc2 , limitedAirframes.rootMenu, limitedAirframes.redirectToggleAirFrames, {"none"})
if limitedAirframes.userCanToggle then
limitedAirframes.theCommand = missionCommands.addCommand(desc2 , limitedAirframes.rootMenu, limitedAirframes.redirectToggleAirFrames, {"none"})
end
end
@ -897,8 +854,8 @@ function limitedAirframes.start()
limitedAirframes.readConfigZone()
-- set output flags
cfxZones.setFlagValueMult(limitedAirframes.numBlue, limitedAirframes.currBlue, limitedAirframes.config)
cfxZones.setFlagValueMult(limitedAirframes.numRed, limitedAirframes.currRed, limitedAirframes.config)
-- cfxZones.setFlagValue(limitedAirframes.numBlue, limitedAirframes.currBlue, limitedAirframes.config)
-- cfxZones.setFlagValue(limitedAirframes.numRed, limitedAirframes.currRed, limitedAirframes.config)
-- collect all zones that are airframe safe
local afsZones = cfxZones.zonesWithProperty("pilotSafe")
@ -936,20 +893,20 @@ function limitedAirframes.start()
-- set current values
limitedAirframes.currRed = limitedAirframes.maxRed
limitedAirframes.currBlue = limitedAirframes.maxBlue
-- limitedAirframes.currRed = limitedAirframes.maxRed
-- limitedAirframes.currBlue = limitedAirframes.maxBlue
-- collect active player unit names
local allPlayerUnits = dcsCommon.getAllExistingPlayerUnitsRaw()
for i=1, #allPlayerUnits do
local aUnit = allPlayerUnits[i]
limitedAirframes.addPlayerUnit(aUnit)
-- trigger.action.outText("limAir: detected active player unit " .. aUnit:getName(), 30)
end
-- allow configuration menu
if limitedAirframes.userCanToggle then
--if limitedAirframes.userCanToggle then
if limitedAirframes.hasUI then
limitedAirframes.setCommsMenu()
end

View File

@ -1,5 +1,5 @@
messenger = {}
messenger.version = "2.3.0"
messenger.version = "2.3.1"
messenger.verbose = false
messenger.requiredLibs = {
"dcsCommon", -- always
@ -68,6 +68,7 @@ messenger.messengers = {}
unit as reference point for relative wildcards. Always broadcasts to coalition. Can be used to broadcase 'eye in the sky' type information
- fixed verbosity bug
2.3.0 - cfxZones OOP switch
2.3.1 - triggering message AFTER the on/off switches are tested
--]]--
@ -444,14 +445,7 @@ function messenger.update()
for idx, aZone in pairs(messenger.messengers) do
-- make sure to re-start before reading time limit
-- new trigger code
if aZone:testZoneFlag(aZone.triggerMessagerFlag, aZone.msgTriggerMethod, "lastMessageTriggerValue") then
if messenger.verbose or aZone.verbose then
trigger.action.outText("+++msgr: triggered on in? for <".. aZone.name ..">", 30)
end
messenger.isTriggered(aZone)
end
-- old trigger code
if aZone:testZoneFlag(aZone.messageOffFlag, aZone.msgTriggerMethod, "lastMessageOff") then
aZone.messageOff = true
if messenger.verbose or aZone.verbose then
@ -465,6 +459,15 @@ function messenger.update()
trigger.action.outText("+++msg: messenger <" .. aZone.name .. "> turned ON", 30)
end
end
if aZone:testZoneFlag(aZone.triggerMessagerFlag, aZone.msgTriggerMethod, "lastMessageTriggerValue") then
if messenger.verbose or aZone.verbose then
trigger.action.outText("+++msgr: triggered on in? for <".. aZone.name ..">", 30)
end
messenger.isTriggered(aZone)
end
end
end

View File

@ -1,4 +1,132 @@
mxObjects = {}
mxObjects.version = "1.0.0"
mxObjects.allObjects = {}
mxObjects.textBoxes = {}
mxObjects.miscObjects = {}
mxObjects.imperial = true
mxObjects.doubleLine = true
-- scan mission to set up object DB
function mxObjects.scanMissionData()
if not env.mission.drawings then
trigger.action.outText("+++mxO: Mission has no object layer", 30)
return
end
local drawings = env.mission.drawings
-- all drawings are in drawings[layer]
local layers = drawings["layers"]
if not layers then
trigger.action.outText("+++mxO: Mission has no layers in objects", 30)
return
end
-- each layer has a "name" field that identifies the layer, and
-- per layer there are the objects. Let's flatten the structure,
-- since object names are unique
local count = 0
for idx, aLayer in pairs(layers) do
local layerName = aLayer.name
local objects = aLayer.objects
-- scan objects in this layer
for idy, theObject in pairs (objects) do
local theData = dcsCommon.clone(theObject)
theData.dist = math.huge -- simply init field
-- make theData point-compatible, handle y<>z adapt
theData.x = theData.mapX -- set up x, y, z
if not theData.x then theData.x = 0 end
theData.y = 0
theData.z = theData.mapY
if not theData.z then theData.z = 0 end
if mxObjects.allObjects[theData.name] then
trigger.action.outText("+++mxO: name collision for drawing object named <" .. theData.name .. ">, skipped.", 30)
else
mxObjects.allObjects[theData.name] = theData
count = count + 1
-- sort into quick-access "type" slots
if theData.primitiveType == "TextBox" then
mxObjects.textBoxes[theData.name] = theData
else
mxObjects.miscObjects[theData.name] = theData
end
end
end
end
end
function mxObjects.sortObjectsInRelationTo(p, objects)
if not p then return nil end
-- calculate distance to all into new list
local disted = {}
for name, theData in pairs(objects) do
theData.dist = dcsCommon.dist(p, theData)
table.insert(disted, theData)
end
table.sort(disted,
function (e1, e2) return e1.dist < e2.dist end
)
return disted
end
function mxObjects.showNClosestTextObjectsToUnit(n, theUnit, numbered)
if numbered == nil then numbered = true end
local p = theUnit:getPoint()
local headingInDegrees = dcsCommon.getUnitHeadingDegrees(theUnit)
local theList = mxObjects.sortObjectsInRelationTo(p, mxObjects.textBoxes)
local msg = "\n"
if #theList < 1 then
msg = msg .. " NO OBJECTS "
else
if n > #theList then n = #theList end
for i = 1, n do
theObject = theList[i]
local dist = theObject.dist
units = "km"
if mxObjects.imperial then
dist = dist * 3.28084
dist = math.floor(dist * 0.0016457883895983) -- in 0.1 nautmil
units = "nm"
else
dist = math.floor(theObject.dist / 100) -- dekameters
end
dist = dist / 10
if numbered then
if i < 10 and n > 9 then
msg = msg .. "0"
end
msg = msg .. i .. ". "
end
-- show text
msg = msg .. theObject.text
-- bearing
local bea = dcsCommon.bearingInDegreesFromAtoB(p, theObject)
msg = msg .. " bearing " .. bea .. "°,"
-- get clock position
local clockPos = dcsCommon.clockPositionOfARelativeToB(theObject, p, headingInDegrees)
msg = msg .. " your " .. clockPos .. " o'clock, "
-- dist
msg = msg .. " " .. dist .. units
msg = msg .. "\n" -- add line feed
if mxObjects.doubleLine then msg = msg .. "\n" end
end
end
return msg
end
function mxObjects.getClosestTo(p, objects)
if not p then return nil, nil end
local closest = nil
local theDist = math.huge
for oName, theData in pairs (objects) do
end
end
function mxObjects.getObjectFreePoly(layerName, polyName, rel) -- omit rel to get absolute points, else pass 'true' to get relative to first point.
if not rel then rel = false end -- relative or absolute
@ -50,3 +178,16 @@ function mxObjects.getObjectFreePoly(layerName, polyName, rel) -- omit rel to ge
trigger.action.outText("+++mxO: no polygon named <" .. polyName .. "> in layer <" ..layerName .. ">", 30)
return {}
end
function mxObjects.start()
mxObjects.scanMissionData()
trigger.action.outText("mxObjects v" .. mxObjects.version .. " loaded.", 30)
end
mxObjects.start()
--[[--
local theUnit = Unit.getByName("Bannok")
local msg = mxObjects.showNClosestTextObjectsToUnit(8, theUnit, numbered)
trigger.action.outText(msg, 30)
--]]--

167
modules/ownAll.lua Normal file
View File

@ -0,0 +1,167 @@
ownAll = {}
ownAll.version = "1.0.0"
ownAll.verbose = false
ownAll.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
}
--[[--
VERSION HISTORY
- 1.0.0 - Initial version
--]]--
ownAll.zones = {}
function ownAll.ownAllForZone(theZone)
local allZones = theZone:getStringFromZoneProperty("ownAll", "")
local zVec = dcsCommon.splitString(allZones, ",")
zVec = dcsCommon.trimArray(zVec)
local filtered = {}
for idx, aName in pairs (zVec) do
local found = cfxZones.getZoneByName(aName)
if not found then
trigger.action.outText("+++oAll: <" .. theZone.name .. ">: zone <" .. aName .. "> does not exist.", 30)
else
table.insert(filtered, found)
end
end
if #filtered < 2 then
trigger.action.outText("+++oAll: WARNING - <" .. theZone.name .. "> has only <" .. #filtered .. "> zones", 30)
end
theZone.zones = filtered
theZone.ownState = -1 -- not all owned by one
if theZone:hasProperty("red!") then
theZone.allRed = theZone:getStringFromZoneProperty("red!", "none")
end
if theZone:hasProperty("red#") then
theZone.redNum = theZone:getStringFromZoneProperty("red#", "none")
end
if theZone:hasProperty("blue!") then
theZone.allBlue = theZone:getStringFromZoneProperty("blue!", "none")
end
if theZone:hasProperty("blue#") then
theZone.blueNum = theZone:getStringFromZoneProperty("blue#", "none")
end
theZone.method = theZone:getStringFromZoneProperty("method", "inc")
if theZone:hasProperty("total#") then
theZone.totalNum = theZone:getStringFromZoneProperty("total#", "none")
theZone:setFlagValue(theZone.totalNum, #filtered)
end
theZone.ownershipUplink = theZone:getBoolFromZoneProperty("uplink", true)
local redNum, blueNum
theZone.state, redNum, blueNum = ownAll.calcState(theZone)
if theZone.redNum then
theZone:setFlagValue(theZone.redNum, redNum)
end
if theZone.blueNum then
theZone:setFlagValue(theZone.blueNum, blueNum)
end
end
function ownAll.calcState(theZone)
local redNum = 0
local blueNum = 0
local allSame = true
if #theZone.zones < 1 then return -1, 0, 0 end
local s = theZone.zones[1].owner
if not s then
trigger.action.outText("+++oAll: zone <" .. theZone.zones[1].name .."> has no owner (?)", 30)
s = -1
end
for idx, aZone in pairs (theZone.zones) do
local s2 = aZone.owner
if not s2 then
trigger.action.outText("+++oAll: zone <" .. aZone.name .."> has no owner (?)", 30)
s2 = -1
elseif s2 == 1 then
redNum = redNum + 1
elseif s2 == 2 then
blueNum = blueNum + 1
end -- note: no separate counting for neutral or contested
if s ~= s2 then allSame = false end
end
local res = s
if not allSame then s = -1 end
return s, redNum, blueNum
end
function ownAll.update()
timer.scheduleFunction(ownAll.update, {}, timer.getTime() + 1)
for idx, theZone in pairs(ownAll.zones) do
local newState, redNum, blueNum = ownAll.calcState(theZone)
if newState ~= theZone.state then
-- all are owned by a different than last time
if newState == 1 and theZone.allRed then
theZone:pollFlag(theZone.allRed, theZone.method)
elseif newState == 2 and theZone.allBlue then
theZone:pollFlag(theZone.allBlue, theZone.method)
end
if theZone.verbose then
trigger.action.outText("+++oAll: zone <" .. theZone.name .. "> status changed to <" .. newState .. ">", 30)
end
theZone.state = newState
end
if theZone.ownershipUplink then
if theZone.state == 1 or theZone.state == 2 then
theZone.owner = theZone.state
else
theZone.owner = 0
end
end
if theZone.redNum then
theZone:setFlagValue(theZone.redNum, redNum)
end
if theZone.blueNum then
theZone:setFlagValue(theZone.blueNum, blueNum)
end
end
end
function ownAll.readConfigZone()
local theZone = cfxZones.getZoneByName("ownAllConfig")
if not theZone then
theZone = cfxZones.createSimpleZone("ownAllConfig")
end
end
function ownAll.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("cfx ownAlll requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx ownAll", ownAll.requiredLibs) then
return false
end
-- read config
ownAll.readConfigZone()
-- process cloner Zones
local attrZones = cfxZones.getZonesWithAttributeNamed("ownAll")
for k, aZone in pairs(attrZones) do
ownAll.ownAllForZone(aZone) -- process attributes
table.insert(ownAll.zones, aZone) -- add to list
end
-- start update
timer.scheduleFunction(ownAll.update, {}, timer.getTime() + 1)
trigger.action.outText("cfx ownAll v" .. ownAll.version .. " started.", 30)
return true
end
-- let's go!
if not ownAll.start() then
trigger.action.outText("cfx ownAll aborted: missing libraries", 30)
ownAll = nil
end

Binary file not shown.