mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 1.4.6
ownAll
This commit is contained in:
parent
28830f1378
commit
08527a515d
Binary file not shown.
Binary file not shown.
@ -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
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
167
modules/ownAll.lua
Normal 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
|
||||
BIN
tutorial & demo missions/demo - All is what I own.miz
Normal file
BIN
tutorial & demo missions/demo - All is what I own.miz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user