LZ, fireFX, smrGUI
This commit is contained in:
Christian Franz 2022-09-16 10:15:11 +02:00
parent 58d81e162f
commit 46712cba20
10 changed files with 550 additions and 78 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
LZ = {} LZ = {}
LZ.version = "0.0.0" LZ.version = "1.0.0"
LZ.verbose = false LZ.verbose = false
LZ.ups = 1 LZ.ups = 1
LZ.requiredLibs = { LZ.requiredLibs = {
@ -9,10 +9,12 @@ LZ.requiredLibs = {
LZ.LZs = {} LZ.LZs = {}
--[[-- --[[--
LZ - module to generate flag events when a unit lands to takes off inside
the zone.
Version History Version History
1.0.0 - initial version 1.0.0 - initial version
--]]-- --]]--
function LZ.addLZ(theZone) function LZ.addLZ(theZone)
@ -27,21 +29,69 @@ function LZ.getLZByName(aName)
trigger.action.outText("+++LZ: no LZ with name <" .. aName ..">", 30) trigger.action.outText("+++LZ: no LZ with name <" .. aName ..">", 30)
end end
return nil
end end
-- --
-- read zone -- read zone
-- --
function LZ.createLZWithZone(theZone) function LZ.createLZWithZone(theZone)
-- read main trigger if cfxZones.hasProperty(theZone, "landed!") then
theZone.triggerLZFlag = cfxZones.getStringFromZoneProperty(theZone, "lz!", "*<none>") theZone.lzLanded = cfxZones.getStringFromZoneProperty(theZone, "landed!", "*<none>")
end
-- TriggerMethod: common and specific synonym if cfxZones.hasProperty(theZone, "departed!") then
theZone.lzDeparted = cfxZones.getStringFromZoneProperty(theZone, "departed!", "*<none>")
end
-- who to look for
theZone.coalition = cfxZones.getCoalitionFromZoneProperty(theZone, "coalition", 0)
-- units / groups / types
if cfxZones.hasProperty(theZone, "group") then
theZone.lzGroups = cfxZones.getStringFromZoneProperty(theZone, "group", "<none>")
theZone.lzGroups = dcsCommon.string2Array(theZone.lzGroups, ",", true)
elseif cfxZones.hasProperty(theZone, "groups") then
theZone.lzGroups = cfxZones.getStringFromZoneProperty(theZone, "groups", "<none>")
theZone.lzGroups = dcsCommon.string2Array(theZone.lzGroups, ",", true)
elseif cfxZones.hasProperty(theZone, "type") then
theZone.lzTypes = cfxZones.getStringFromZoneProperty(theZone, "type", "ALL")
theZone.lzTypes = dcsCommon.string2Array(theZone.lzTypes, ",", true)
elseif cfxZones.hasProperty(theZone, "types") then
theZone.lzTypes = cfxZones.getStringFromZoneProperty(theZone, "types", "ALL")
theZone.lzTypes = dcsCommon.string2Array(theZone.lzTypes, ",", true)
elseif cfxZones.hasProperty(theZone, "unit") then
theZone.lzUnits = cfxZones.getStringFromZoneProperty(theZone, "unit", "none")
theZone.lzUnits = dcsCommon.string2Array(theZone.lzUnits, ",", true)
elseif cfxZones.hasProperty(theZone, "units") then
theZone.lzUnits = cfxZones.getStringFromZoneProperty(theZone, "units", "none")
theZone.lzUnits = dcsCommon.string2Array(theZone.lzUnits, ",", true)
end
theZone.lzPlayerOnly = cfxZones.getBoolFromZoneProperty(theZone, "playerOnly", false)
-- output method
theZone.lzMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc") theZone.lzMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
if cfxZones.hasProperty(theZone, "outputMethod") then
theZone.lzMethod = cfxZones.getStringFromZoneProperty(theZone, "outputMethod", "inc")
end
if cfxZones.hasProperty(theZone, "lzTriggerMethod") then -- trigger method
theZone.lzMethod = cfxZones.getStringFromZoneProperty(theZone, "lzMethod", "change") theZone.lzTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "lzTriggerMethod", "change")
if cfxZones.hasProperty(theZone, "triggerMethod") then
theZone.lzTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
end
-- pause / unpause
theZone.lzIsPaused = cfxZones.getBoolFromZoneProperty(theZone, "isPaused", false)
if cfxZones.hasProperty(theZone, "pause?") then
theZone.lzPause = cfxZones.getStringFromZoneProperty(theZone, "pause?", "*<none>")
theZone.lzLastPause = cfxZones.getFlagValue(theZone.lzPause, theZone)
end
if cfxZones.hasProperty(theZone, "continue?") then
theZone.lzContinue = cfxZones.getStringFromZoneProperty(theZone, "continue?", "*<none>")
theZone.lzLastContinue = cfxZones.getFlagValue(theZone.lzContinue, theZone)
end end
if LZ.verbose or theZone.verbose then if LZ.verbose or theZone.verbose then
@ -50,45 +100,196 @@ function LZ.createLZWithZone(theZone)
end end
-- function LZ.nameMatchForArray(theName, theArray, wildcard)
-- MAIN ACTION theName = dcsCommon.trim(theName)
-- if not theName then return false end
function LZ.processUpdate(theZone) if not theArray then return false end
theName = string.upper(theName) -- case insensitive
-- trigger.action.outText("enter name match with <" .. theName .. "> look for match in <" .. dcsCommon.array2string(theArray) .. "> and wc <" .. wildcard .. ">", 30)
for idx, entry in pairs(theArray) do
if wildcard and dcsCommon.stringEndsWith(entry, wildcard) then
entry = dcsCommon.removeEnding(entry, wildcard)
-- trigger.action.outText("trying to WC-match <" .. theName .. "> with <" .. entry .. ">", 30)
if dcsCommon.stringStartsWith(theName, entry) then
-- theName "hi there" matches wildcarded entry "hi*"
return true
end end
else
-- trigger.action.outText("trying to simple-match <" .. theName .. "> with <" .. entry .. ">", 30)
if theName == entry then
return true
end
end
end
-- trigger.action.outText ("no match for <" .. theName .. ">", 30)
return false
end
--
-- Misc Processing
--
function LZ.unitIsInterestingForZone(theUnit, theZone)
--trigger.action.outText("enter isInterestingB4pause for <" .. theUnit:getName() .. ">", 40)
-- see if zone is interested in this unit.
if theZone.isPaused then
return false
end
-- trigger.action.outText("enter isinteresting for <" .. theUnit:getName() .. ">", 40)
if theZone.lzPlayerOnly then
if not dcsCommon.isPlayerUnit(theUnit) then
if theZone.verbose or LZ.verbose then
trigger.action.outText("+++LZ: unit <" .. theUnit:getName() .. "> arriving/departing <" .. theZone.name .. "> is not a player unit", 30)
end
return false
else
-- trigger.action.outText("player match!", 30)
end
end
if theZone.coalition > 0 then
local theGroup = theUnit:getGroup()
local coa = theGroup:getCoalition()
if coa ~= theZone.coalition then
if theZone.verbose or LZ.verbose then
trigger.action.outText("+++LZ: unit <" .. theUnit:getName() .. "> arriving/departing <" .. theZone.name .. "> does not match coa <" .. theZone.coalition .. ">", 30)
end
return false
end
end
-- if we get here, we are filtered for coa and player
if theZone.lzUnits then
local theName = theUnit:getName()
return LZ.nameMatchForArray(theName, theZone.lzUnits, "*")
elseif theZone.lzGroups then
local theGroup = theUnit:getGroup()
local theName = theGroup:getName()
return LZ.nameMatchForArray(theName, theZone.lzGroups, "*")
elseif theZone.lzTypes then
local theType = theUnit:getTypeName()
local theGroup = theUnit:getGroup()
local cat = theGroup:getCategory() -- can't trust unit:getCategory
local coa = theGroup:getCoalition()
for idx, aType in pairs (theZone.lzTypes) do
if aType == "ANY" or aType == "ALL" then
return true
elseif aType == "HELO" or aType == "HELICOPTER" or aType == "HELICOPTERS" or aType == "HELOS" then
if cat == 1 then
return true
end
elseif aType == "PLANE" or aType == "PLANES" then
if cat == 0 then
return true
end
else
if theType == aType then
return true
end
end
end -- for all types
return false -- not a single match
else
-- we can return true since player and coa mismatch
-- have already been filtered
--[[-- -- neither type, unit, nor group
local theGroup = theUnit:getGroup()
local coa = theGroup:getCoalition()
--
--]]--
return true -- theZone.coalition == coa end
end
trigger.action.outText("+++LZ: unknown attribute check for <" .. theZone.name .. ">", 30)
return false
end
-- --
-- Event Handling -- Event Handling
-- --
function LZ:onEvent(event) function LZ:onEvent(event)
-- only interested in S_EVENT_BASE_CAPTURED events -- make sure we have an initiator
if event.id ~= world.event.S_EVENT_BASE_CAPTURED then if not event.initiator then return end
-- only interested in S_EVENT_TAKEOFF and events
if event.id ~= world.event.S_EVENT_TAKEOFF and
event.id ~= world.event.S_EVENT_LAND then
return return
end end
for idx, aZone in pairs(LZ.LZs) do --if LZ.verbose or true then
-- check if landed inside and of correct type, colition, name whatever -- trigger.action.outText("+++LZ: on event proccing", 30)
--end
local theUnit = event.initiator
if not Unit.isExist(theUnit) then return end
local p = theUnit:getPoint()
--if LZ.verbose or true then
-- trigger.action.outText("+++LZ: before iterating zones", 30)
--end
for idx, aZone in pairs(LZ.LZs) do
-- see if inside the zone
local inZone, percent, dist = cfxZones.pointInZone(p, aZone)
if inZone then
-- see if this unit interests us at all
if LZ.unitIsInterestingForZone(theUnit, aZone) then
-- interesting unit in zone triggered the event
if aZone.lzDeparted and event.id == world.event.S_EVENT_TAKEOFF then
if LZ.verbose or aZone.verbose then
trigger.action.outText("+++LZ: detected departure from <" .. aZone.name .. ">", 30)
end end
cfxZones.pollFlag(aZone.lzDeparted, aZone.lzMethod, aZone)
end
if aZone.lzLanded and event.id == world.event.S_EVENT_LAND then
if LZ.verbose or aZone.verbose then
trigger.action.outText("+++LZ: detected landing in <" .. aZone.name .. ">", 30)
end
cfxZones.pollFlag(aZone.lzLanded, aZone.lzMethod, aZone)
end
end -- if interesting
else
if LZ.verbose or true then
-- trigger.action.outText("+++LZ: unit <" .. theUnit:getName() .. "> not in zone <" .. aZone.name .. ">", 30)
end
end -- if in zone
end -- end for
end end
-- --
-- Update -- Update
-- --
function LZ.update() function LZ.update()
-- call me in a second to poll triggers -- call me in a second to poll triggers
timer.scheduleFunction(LZ.update, {}, timer.getTime() + 1/LZ.ups) timer.scheduleFunction(LZ.update, {}, timer.getTime() + 1/LZ.ups)
for idx, aZone in pairs(LZ.LZs) do for idx, aZone in pairs(LZ.LZs) do
-- see if we are triggered -- see if we are being paused or unpaused
if cfxZones.testZoneFlag(aZone, aZone.triggerLZFlag, aZone.LZTriggerMethod, "lastTriggerLZValue") then if cfxZones.testZoneFlag(aZone, aZone.lzPause, aZone.LZTriggerMethod, "lzLastPause") then
if LZ.verbose or theZone.verbose then if LZ.verbose or theZone.verbose then
trigger.action.outText("+++LZ: triggered on main? for <".. aZone.name ..">", 30) trigger.action.outText("+++LZ: triggered pause? for <".. aZone.name ..">", 30)
end end
LZ.processUpdate(aZone) aZone.isPaused = true
end
if cfxZones.testZoneFlag(aZone, aZone.lzContinue, aZone.LZTriggerMethod, "lzLastContinue") then
if LZ.verbose or theZone.verbose then
trigger.action.outText("+++LZ: triggered continue? for <".. aZone.name ..">", 30)
end
aZone.isPaused = false
end end
end end
end end
-- --
@ -97,12 +298,13 @@ end
function LZ.readConfigZone() function LZ.readConfigZone()
local theZone = cfxZones.getZoneByName("LZConfig") local theZone = cfxZones.getZoneByName("LZConfig")
if not theZone then if not theZone then
theZone = cfxZones.createSimpleZone(LZConfig)
if LZ.verbose then if LZ.verbose then
trigger.action.outText("+++LZ: NO config zone!", 30) trigger.action.outText("+++LZ: NO config zone!", 30)
end end
return
end end
LZ.lzCooldown = cfxZones.getNumberFromZoneProperty(theZone, "cooldown", 20)
LZ.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false) LZ.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
if LZ.verbose then if LZ.verbose then
@ -125,12 +327,15 @@ function LZ.start()
-- process LZ Zones -- process LZ Zones
-- old style -- old style
local attrZones = cfxZones.getZonesWithAttributeNamed("lz!") local attrZones = cfxZones.getZonesWithAttributeNamed("lz")
for k, aZone in pairs(attrZones) do for k, aZone in pairs(attrZones) do
LZ.createLZWithZone(aZone) -- process attributes LZ.createLZWithZone(aZone) -- process attributes
LZ.addLZ(aZone) -- add to list LZ.addLZ(aZone) -- add to list
end end
-- connect event handler
world.addEventHandler(LZ)
-- start update -- start update
LZ.update() LZ.update()

View File

@ -1,5 +1,5 @@
cloneZones = {} cloneZones = {}
cloneZones.version = "1.5.4" cloneZones.version = "1.5.5"
cloneZones.verbose = false cloneZones.verbose = false
cloneZones.requiredLibs = { cloneZones.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -61,7 +61,7 @@ cloneZones.allCObjects = {} -- all clones objects
1.5.2 - fixed bug in trackWith: referencing wrong cloner 1.5.2 - fixed bug in trackWith: referencing wrong cloner
1.5.3 - centerOnly/wholeGroups attribute for rndLoc, rndHeading and onRoad 1.5.3 - centerOnly/wholeGroups attribute for rndLoc, rndHeading and onRoad
1.5.4 - parking for aircraft processing when cloning from template 1.5.4 - parking for aircraft processing when cloning from template
1.5.5 - removed some verbosity
--]]-- --]]--
@ -1053,7 +1053,7 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
end end
function cloneZones.spawnWithCloner(theZone) function cloneZones.spawnWithCloner(theZone)
trigger.action.outText("+++clnZ: enter spawnWithCloner for <" .. theZone.name .. ">", 30) -- trigger.action.outText("+++clnZ: enter spawnWithCloner for <" .. theZone.name .. ">", 30)
if not theZone then if not theZone then
trigger.action.outText("+++clnZ: nil zone on spawnWithCloner", 30) trigger.action.outText("+++clnZ: nil zone on spawnWithCloner", 30)
return return
@ -1232,7 +1232,7 @@ end
function cloneZones.doOnStart() function cloneZones.doOnStart()
for idx, theZone in pairs(cloneZones.cloners) do for idx, theZone in pairs(cloneZones.cloners) do
if theZone.onStart then if theZone.onStart then
trigger.action.outText("+++clnZ: onStart true for <" .. theZone.name .. ">", 30) -- trigger.action.outText("+++clnZ: onStart true for <" .. theZone.name .. ">", 30)
if theZone.isStarted then if theZone.isStarted then
if cloneZones.verbose or theZone.verbose then if cloneZones.verbose or theZone.verbose then
trigger.action.outText("+++clnz: onStart pre-empted for <" .. theZone.name .. "> by persistence", 30) trigger.action.outText("+++clnz: onStart pre-empted for <" .. theZone.name .. "> by persistence", 30)

View File

@ -1,5 +1,5 @@
dcsCommon = {} dcsCommon = {}
dcsCommon.version = "2.7.2" dcsCommon.version = "2.7.4"
--[[-- VERSION HISTORY --[[-- VERSION HISTORY
2.2.6 - compassPositionOfARelativeToB 2.2.6 - compassPositionOfARelativeToB
- clockPositionOfARelativeToB - clockPositionOfARelativeToB
@ -98,6 +98,9 @@ dcsCommon.version = "2.7.2"
new decFlag() new decFlag()
nil trap in stringStartsWith() nil trap in stringStartsWith()
new getClosestFreeSlotForCatInAirbaseTo() new getClosestFreeSlotForCatInAirbaseTo()
2.7.3 - new string2Array()
- additional guard for isPlayerUnit
2.7.4 - new array2string()
--]]-- --]]--
@ -1853,6 +1856,33 @@ end
return trimmedArray return trimmedArray
end end
function dcsCommon.string2Array(inString, deli, uCase)
if not inString then return {} end
if not deli then return {} end
if not uCase then uCase = false end
if uCase then inString = string.upper(inString) end
inString = dcsCommon.trim(inString)
if dcsCommon.containsString(inString, deli) then
local a = dcsCommon.splitString(inString, deli)
a = dcsCommon.trimArray(a)
return a
else
return {inString}
end
end
function dcsCommon.array2string(inArray, deli)
if not deli then deli = "," end
if type(inArray) ~= "table" then return "<err in array2string: not an array>" end
local s = ""
local count = 0
for idx, ele in pairs(inArray) do
if count > 0 then s = s .. deli .. " " end
s = s .. ele
end
return s
end
function dcsCommon.stripLF(theString) function dcsCommon.stripLF(theString)
return theString:gsub("[\r\n]", "") return theString:gsub("[\r\n]", "")
end end
@ -2320,6 +2350,7 @@ end
function dcsCommon.isPlayerUnit(theUnit) function dcsCommon.isPlayerUnit(theUnit)
-- new patch. simply check if getPlayerName returns something -- new patch. simply check if getPlayerName returns something
if not theUnit then return false end if not theUnit then return false end
if not Unit.isExist(theUnit) then return end
if not theUnit.getPlayerName then return false end -- map/static object if not theUnit.getPlayerName then return false end -- map/static object
local pName = theUnit:getPlayerName() local pName = theUnit:getPlayerName()
if pName then return true end if pName then return true end

186
modules/fireFX.lua Normal file
View File

@ -0,0 +1,186 @@
fireFX = {}
fireFX.version = "1.0.0"
fireFX.verbose = false
fireFX.ups = 1
fireFX.requiredLibs = {
"dcsCommon", -- always
"cfxZones", -- Zones, of course
}
fireFX.fx = {}
function fireFX.addFX(theZone)
table.insert(fireFX.fx, theZone)
end
function fireFX.getFXByName(aName)
for idx, aZone in pairs(fireFX.fx) do
if aName == aZone.name then return aZone end
end
if fireFX.verbose then
trigger.action.outText("+++ffx: no fire FX with name <" .. aName ..">", 30)
end
end
--
-- read zone
--
function fireFX.createFXWithZone(theZone)
-- decode size and fire
local theSize = cfxZones.getStringFromZoneProperty(theZone, "fireFX", "none")
theSize = dcsCommon.trim(theSize)
theSize = string.upper(theSize)
local fxCode = 1
if theSize == "S" or theSize == "SMALL" then fxCode = 1 end
if theSize == "M" or theSize == "MEDIUM" then fxCode = 2 end
if theSize == "L" or theSize == "LARGE" then fxCode = 3 end
if theSize == "H" or theSize == "HUGE" then fxCode = 4 end
if theSize == "XL" then fxCode = 4 end
local theFire = cfxZones.getBoolFromZoneProperty(theZone, "flames", true)
if theFire then
-- code stays as it is
else
-- smoke only
fxCode = fxCode + 4
end
theZone.fxCode = fxCode
if theZone.verbose or fireFX.verbose then
trigger.action.outText("+++ffx: new FX with code = <" .. fxCode .. ">", 30)
end
theZone.density = cfxZones.getNumberFromZoneProperty(theZone, "density", 0.5)
if cfxZones.hasProperty(theZone, "start?") then
theZone.fxStart = cfxZones.getStringFromZoneProperty(theZone, "start?", "*<none>")
theZone.fxLastStart = cfxZones.getFlagValue(theZone.fxStart, theZone)
end
if cfxZones.hasProperty(theZone, "stop?") then
theZone.fxStop = cfxZones.getStringFromZoneProperty(theZone, "stop?", "*<none>")
theZone.fxLastStop = cfxZones.getFlagValue(theZone.fxStop, theZone)
end
theZone.fxOnStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", false)
theZone.burning = false
if not theZone.fxOnStart and not theZone.fxStart then
trigger.action.outText("+++ffx: WARNING - fireFX Zone <" .. theZone.name .. "> can't be started, neither onStart nor 'start?' defined", 30)
end
-- output method (not needed)
-- trigger method
theZone.fxTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "fxTriggerMethod", "change")
if cfxZones.hasProperty(theZone, "triggerMethod") then
theZone.fxTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
end
if fireFX.verbose or theZone.verbose then
trigger.action.outText("+++ffx: new FX <".. theZone.name ..">", 30)
end
end
--
-- Update
--
function fireFX.startTheFire(theZone)
if not theZone.burning then
local p = cfxZones.getPoint(theZone)
p.y = land.getHeight({x = p.x, y = p.z})
local preset = theZone.fxCode
local density = theZone.density
trigger.action.effectSmokeBig(p, preset, density, theZone.name)
theZone.burning = true
end
end
function fireFX.extinguishFire(theZone)
if theZone.burning then
trigger.action.effectSmokeStop(theZone.name)
theZone.burning = false
end
end
function fireFX.update()
-- call me in a second to poll triggers
timer.scheduleFunction(fireFX.update, {}, timer.getTime() + 1/fireFX.ups)
for idx, aZone in pairs(fireFX.fx) do
-- see if we are being paused or unpaused
if cfxZones.testZoneFlag(aZone, aZone.fxStop, aZone.fxTriggerMethod, "fxLastStop") then
if fireFX.verbose or aZone.verbose then
trigger.action.outText("+++ffx: triggered 'stop?' for <".. aZone.name ..">", 30)
end
fireFX.extinguishFire(aZone)
end
if cfxZones.testZoneFlag(aZone, aZone.fxStart, aZone.fxTriggerMethod, "fxLastStart") then
if fireFX.verbose or aZone.verbose then
trigger.action.outText("+++ffx: triggered 'start?' for <".. aZone.name ..">", 30)
end
fireFX.startTheFire(aZone)
end
end
end
--
-- Config & Start
--
function fireFX.readConfigZone()
local theZone = cfxZones.getZoneByName("fireFXConfig")
if not theZone then
theZone = cfxZones.createSimpleZone(LZConfig)
if fireFX.verbose then
trigger.action.outText("+++ffx: NO config zone!", 30)
end
end
if fireFX.verbose then
trigger.action.outText("+++ffx: read config", 30)
end
end
function fireFX.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("cfx fire FX requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx fire FX", fireFX.requiredLibs) then
return false
end
-- read config
fireFX.readConfigZone()
-- process fireFX Zones
-- old style
local attrZones = cfxZones.getZonesWithAttributeNamed("fireFX")
for k, aZone in pairs(attrZones) do
fireFX.createFXWithZone(aZone) -- process attributes
fireFX.addFX(aZone) -- add to list
end
-- handle onStart
for idx, theZone in pairs(fireFX.fx) do
if theZone.fxOnStart then
fireFX.startTheFire(theZone)
end
end
-- start update
fireFX.update()
trigger.action.outText("cfx fire FX v" .. fireFX.version .. " started.", 30)
return true
end
-- let's go!
if not fireFX.start() then
trigger.action.outText("cfx fireFX aborted: missing libraries", 30)
fireFX = nil
end

View File

@ -1,5 +1,5 @@
limitedAirframes = {} limitedAirframes = {}
limitedAirframes.version = "1.5.0" limitedAirframes.version = "1.5.1"
limitedAirframes.verbose = false limitedAirframes.verbose = false
limitedAirframes.enabled = true -- can be turned off limitedAirframes.enabled = true -- can be turned off
limitedAirframes.userCanToggle = true -- F10 menu? limitedAirframes.userCanToggle = true -- F10 menu?
@ -12,6 +12,7 @@ limitedAirframes.method = "inc"
limitedAirframes.warningSound = "Quest Snare 3.wav" limitedAirframes.warningSound = "Quest Snare 3.wav"
limitedAirframes.loseSound = "Death PIANO.wav" limitedAirframes.loseSound = "Death PIANO.wav"
limitedAirframes.winSound = "Triumphant Victory.wav" limitedAirframes.winSound = "Triumphant Victory.wav"
limitedAirframes.announcer = true
limitedAirframes.requiredLibs = { limitedAirframes.requiredLibs = {
"dcsCommon", -- common is of course needed for everything "dcsCommon", -- common is of course needed for everything
@ -50,6 +51,7 @@ limitedAirframes.requiredLibs = {
currRed currRed
- 1.4.1 - removed dependency to cfxPlayer - 1.4.1 - removed dependency to cfxPlayer
- 1.5.0 - persistence support - 1.5.0 - persistence support
- 1.5.1 - new "announcer" attribute
--]]-- --]]--
@ -133,27 +135,17 @@ function limitedAirframes.readConfigZone()
end end
-- ok, for each property, load it if it exists -- ok, for each property, load it if it exists
-- if cfxZones.hasProperty(theZone, "enabled") then
limitedAirframes.enabled = cfxZones.getBoolFromZoneProperty(theZone, "enabled", true) limitedAirframes.enabled = cfxZones.getBoolFromZoneProperty(theZone, "enabled", true)
-- end
-- if cfxZones.hasProperty(theZone, "userCanToggle") then
limitedAirframes.userCanToggle = cfxZones.getBoolFromZoneProperty(theZone, "userCanToggle", true) limitedAirframes.userCanToggle = cfxZones.getBoolFromZoneProperty(theZone, "userCanToggle", true)
-- end
-- if cfxZones.hasProperty(theZone, "maxRed") then
limitedAirframes.maxRed = cfxZones.getNumberFromZoneProperty(theZone, "maxRed", -1) limitedAirframes.maxRed = cfxZones.getNumberFromZoneProperty(theZone, "maxRed", -1)
-- end
-- if cfxZones.hasProperty(theZone, "maxBlue") then
limitedAirframes.maxBlue = cfxZones.getNumberFromZoneProperty(theZone, "maxBlue", -1) limitedAirframes.maxBlue = cfxZones.getNumberFromZoneProperty(theZone, "maxBlue", -1)
-- end
limitedAirframes.numRed = cfxZones.getStringFromZoneProperty(theZone, "#red", "*none") limitedAirframes.numRed = cfxZones.getStringFromZoneProperty(theZone, "#red", "*none")
limitedAirframes.numBlue = cfxZones.getStringFromZoneProperty(theZone, "#blue", "*none") limitedAirframes.numBlue = cfxZones.getStringFromZoneProperty(theZone, "#blue", "*none")
limitedAirframes.redWinsFlag = cfxZones.getStringFromZoneProperty(theZone, "redWins!", "*none") limitedAirframes.redWinsFlag = cfxZones.getStringFromZoneProperty(theZone, "redWins!", "*none")
if cfxZones.hasProperty(theZone, "redWinsFlag!") then if cfxZones.hasProperty(theZone, "redWinsFlag!") then
@ -178,6 +170,8 @@ function limitedAirframes.readConfigZone()
if cfxZones.hasProperty(theZone, "loseSound") then if cfxZones.hasProperty(theZone, "loseSound") then
limitedAirframes.loseSound = cfxZones.getStringFromZoneProperty(theZone, "loseSound", "none") limitedAirframes.loseSound = cfxZones.getStringFromZoneProperty(theZone, "loseSound", "none")
end end
limitedAirframes.announcer = cfxZones.getBoolFromZoneProperty(theZone, "announcer", true)
end end
-- --
@ -221,17 +215,18 @@ function limitedAirframes.addPlayerUnit(theUnit)
end end
end end
limitedAirframes.playerUnits[uName] = pName limitedAirframes.playerUnits[uName] = pName
if limitedAirframes.announcer then
trigger.action.outTextForCoalition(theSide, desc, 30) trigger.action.outTextForCoalition(theSide, desc, 30)
end end
end
function limitedAirframes.killPlayer(pName) function limitedAirframes.killPlayer(pName)
limitedAirframes.updatePlayer(pName, "dead") limitedAirframes.updatePlayer(pName, "dead")
--trigger.action.outText("+++lim: PILOT LOST: " .. pName .. ", NO CSAR", 30)
end end
function limitedAirframes.killPlayerInUnit(theUnit) function limitedAirframes.killPlayerInUnit(theUnit)
limitedAirframes.updatePlayerInUnit(theUnit, "dead") limitedAirframes.updatePlayerInUnit(theUnit, "dead")
--trigger.action.outText("+++lim: PILOT LOST, NO CSAR", 30)
end end
function limitedAirframes.updatePlayerInUnit(theUnit, status) function limitedAirframes.updatePlayerInUnit(theUnit, status)
@ -476,7 +471,6 @@ function limitedAirframes.handlePlayerLeftUnit(event)
local pName = limitedAirframes.getKnownUnitPilotByUnitName(theUnit:getName()) local pName = limitedAirframes.getKnownUnitPilotByUnitName(theUnit:getName())
local pStatus = limitedAirframes.getStatusOfPlayerInUnit(theUnit) local pStatus = limitedAirframes.getStatusOfPlayerInUnit(theUnit)
-- player was already dead and has been accounted for -- player was already dead and has been accounted for
--trigger.action.outText("limAir: Change Plane for player <" .. pName .. "> with status <" .. pStatus .. "> procced.", 30)
return return
end end
@ -485,11 +479,8 @@ function limitedAirframes.handlePlayerLeftUnit(event)
local uPos = theUnit:getPoint() local uPos = theUnit:getPoint()
local meInside = cfxZones.getZonesContainingPoint(uPos, limitedAirframes.safeZones) local meInside = cfxZones.getZonesContainingPoint(uPos, limitedAirframes.safeZones)
local mySide = theUnit:getCoalition() local mySide = theUnit:getCoalition()
--local speed = dcsCommon.getUnitSpeed(theUnit) -- this can cause problems with carriers, so check if below
--local agl = dcsCommon.getUnitAGL(theUnit) -- this will cause problems with FARP and carriers.
-- we now check the inAir -- we now check the inAir
local isInAir = theUnit:inAir() local isInAir = theUnit:inAir()
--trigger.action.outTextForCoalition(mySide, "limAir: safe check for Pilot " .. theUnit:getPlayerName() .. ": agl=" .. agl .. ", speed = " .. speed .. ", air status = " .. dcsCommon.bool2YesNo(isInAir), 30)
for i=1, #meInside do for i=1, #meInside do
-- I'm inside all these zones. We look for the first -- I'm inside all these zones. We look for the first
@ -527,19 +518,18 @@ function limitedAirframes.handlePlayerLeftUnit(event)
if isInAir then isSafe = false end if isInAir then isSafe = false end
if isSafe then if isSafe then
-- if limitedAirframes.verbose then -- if limitedAirframes.announcer then
trigger.action.outTextForCoalition(mySide, "Pilot " .. theUnit:getPlayerName() .. " left unit " .. theUnit:getName() .. " legally in zone " .. theSafeZone.name, 30) -- trigger.action.outTextForCoalition(mySide, "Pilot " .. theUnit:getPlayerName() .. " left unit " .. theUnit:getName() .. " legally in zone " .. theSafeZone.name, 30)
-- end -- end
-- remove from known player planes
-- no more limitedAirframes.removePlayerUnit(theUnit)
return; return;
end end
end end
-- ditched outside safe harbour -- ditched outside safe harbour
-- if limitedAirframes.verbose then if limitedAirframes.announcer then
trigger.action.outTextForCoalition(mySide, "Pilot " .. theUnit:getPlayerName() .. " DITCHED unit " .. theUnit:getName() .. " -- PILOT is considered MIA", 30) trigger.action.outTextForCoalition(mySide, "Pilot " .. theUnit:getPlayerName() .. " DITCHED unit " .. theUnit:getName() .. " -- PILOT is considered MIA", 30)
-- end end
limitedAirframes.pilotLost(theUnit) limitedAirframes.pilotLost(theUnit)
if csarManager and csarManager.airframeDitched then if csarManager and csarManager.airframeDitched then
@ -559,7 +549,9 @@ function limitedAirframes.pilotEjected(event)
local theSide = theUnit:getCoalition() local theSide = theUnit:getCoalition()
local pilot = limitedAirframes.getKnownUnitPilotByUnit(theUnit) local pilot = limitedAirframes.getKnownUnitPilotByUnit(theUnit)
local uName = theUnit:getName() local uName = theUnit:getName()
if limitedAirframes.announcer then
trigger.action.outTextForCoalition(theSide, "Pilot <" .. pilot .. "> ejected from " .. uName .. ", now MIA", 30) trigger.action.outTextForCoalition(theSide, "Pilot <" .. pilot .. "> ejected from " .. uName .. ", now MIA", 30)
end
local hasLostTheWar = limitedAirframes.pilotLost(theUnit) local hasLostTheWar = limitedAirframes.pilotLost(theUnit)
@ -575,7 +567,9 @@ function limitedAirframes.pilotDied(theUnit)
local theSide = theUnit:getCoalition() local theSide = theUnit:getCoalition()
local pilot = limitedAirframes.getKnownUnitPilotByUnit(theUnit) local pilot = limitedAirframes.getKnownUnitPilotByUnit(theUnit)
local uName = theUnit:getName() local uName = theUnit:getName()
if limitedAirframes.announcer then
trigger.action.outTextForCoalition(theSide, "Pilot <" .. pilot .. "> is confirmed KIA while controlling " .. uName, 30) trigger.action.outTextForCoalition(theSide, "Pilot <" .. pilot .. "> is confirmed KIA while controlling " .. uName, 30)
end
limitedAirframes.pilotLost(theUnit) limitedAirframes.pilotLost(theUnit)
end end
@ -593,7 +587,7 @@ function limitedAirframes.pilotLost(theUnit)
local theSide = theUnit:getCoalition() local theSide = theUnit:getCoalition()
local pilot = limitedAirframes.getKnownUnitPilotByUnit(theUnit) local pilot = limitedAirframes.getKnownUnitPilotByUnit(theUnit)
local uName = theUnit:getName() local uName = theUnit:getName()
--trigger.action.outTextForCoalition(theSide, "Pilot <" .. pilot .. "> is confirmed KIA while controlling " .. uName, 30)
if theSide == 1 then -- red if theSide == 1 then -- red
theOtherSide = 2 theOtherSide = 2
@ -605,16 +599,16 @@ function limitedAirframes.pilotLost(theUnit)
if limitedAirframes.currRed == 0 then if limitedAirframes.currRed == 0 then
trigger.action.outTextForCoalition(theSide, "\nYou have lost almost all of your pilots.\n\nWARNING: Losing any more pilots WILL FAIL THE MISSION\n", 30) trigger.action.outTextForCoalition(theSide, "\nYou have lost almost all of your pilots.\n\nWARNING: Losing any more pilots WILL FAIL THE MISSION\n", 30)
trigger.action.outSoundForCoalition(theSide, limitedAirframes.warningSound)--"Quest Snare 3.wav") trigger.action.outSoundForCoalition(theSide, limitedAirframes.warningSound)
return false return false
end end
if limitedAirframes.currRed < 0 then if limitedAirframes.currRed < 0 then
-- red have lost all airframes -- red have lost all airframes
trigger.action.outText("\nREDFORCE has lost all of their pilots.\n\nBLUEFORCE WINS!\n", 30) trigger.action.outText("\nREDFORCE has lost all of their pilots.\n\nBLUEFORCE WINS!\n", 30)
trigger.action.outSoundForCoalition(theSide, limitedAirframes.loseSound) --"Death PIANO.wav") trigger.action.outSoundForCoalition(theSide, limitedAirframes.loseSound)
trigger.action.outSoundForCoalition(theOtherSide, limitedAirframes.winSound)--"Triumphant Victory.wav") trigger.action.outSoundForCoalition(theOtherSide, limitedAirframes.winSound)
-- trigger.action.setUserFlag(limitedAirframes.blueWinsFlag, 1 )
cfxZones.pollFlag(limitedAirframes.blueWinsFlag, limitedAirframes.method, limitedAirframes.config) cfxZones.pollFlag(limitedAirframes.blueWinsFlag, limitedAirframes.method, limitedAirframes.config)
return true return true
end end
@ -629,20 +623,22 @@ function limitedAirframes.pilotLost(theUnit)
if limitedAirframes.currBlue == 0 then if limitedAirframes.currBlue == 0 then
trigger.action.outTextForCoalition(theSide, "\nYou have lost almost all of your pilots.\n\nWARNING: Losing any more pilots WILL FAIL THE MISSION\n", 30) trigger.action.outTextForCoalition(theSide, "\nYou have lost almost all of your pilots.\n\nWARNING: Losing any more pilots WILL FAIL THE MISSION\n", 30)
trigger.action.outSoundForCoalition(theSide, limitedAirframes.warningSound)--"Quest Snare 3.wav") trigger.action.outSoundForCoalition(theSide, limitedAirframes.warningSound)
return false return false
end end
if limitedAirframes.currBlue < 0 then if limitedAirframes.currBlue < 0 then
-- red have lost all airframes -- red have lost all airframes
trigger.action.outText("\nBLUEFORCE has lost all of their pilots.\n\nREDFORCE WINS!\n", 30) trigger.action.outText("\nBLUEFORCE has lost all of their pilots.\n\nREDFORCE WINS!\n", 30)
-- trigger.action.setUserFlag(limitedAirframes.redWinsFlag, 1 )
cfxZones.pollFlag(limitedAirframes.redWinsFlag, limitedAirframes.method, limitedAirframes.config) cfxZones.pollFlag(limitedAirframes.redWinsFlag, limitedAirframes.method, limitedAirframes.config)
trigger.action.outSoundForCoalition(theSide, limitedAirframes.loseSound)--"Death PIANO.wav") trigger.action.outSoundForCoalition(theSide, limitedAirframes.loseSound)
trigger.action.outSoundForCoalition(theOtherSide, limitedAirframes.winSound)--"Triumphant Victory.wav") trigger.action.outSoundForCoalition(theOtherSide, limitedAirframes.winSound)
return true return true
end end
trigger.action.outSoundForCoalition(theSide, limitedAirframes.warningSound)--"Quest Snare 3.wav") trigger.action.outSoundForCoalition(theSide, limitedAirframes.warningSound)
-- if limitedAirframes.announcer then
trigger.action.outTextForCoalition(theSide, "You have lost a pilot! Remaining: " .. limitedAirframes.currBlue, 30) trigger.action.outTextForCoalition(theSide, "You have lost a pilot! Remaining: " .. limitedAirframes.currBlue, 30)
-- end
end end
return false return false
end end

View File

@ -1,5 +1,5 @@
persistence = {} persistence = {}
persistence.version = "1.0.2" persistence.version = "1.0.3"
persistence.ups = 1 -- once every 1 seconds persistence.ups = 1 -- once every 1 seconds
persistence.verbose = false persistence.verbose = false
persistence.active = false persistence.active = false
@ -22,6 +22,8 @@ persistence.requiredLibs = {
- cfxZones interface - cfxZones interface
- always output save location - always output save location
1.0.2 - QoL when verbosity is on 1.0.2 - QoL when verbosity is on
1.0.3 - no longer always tells " mission saved to"
new 'saveNotification" can be off
PROVIDES LOAD/SAVE ABILITY TO MODULES PROVIDES LOAD/SAVE ABILITY TO MODULES
@ -375,9 +377,9 @@ function persistence.doSaveMission()
return return
end end
-- if persistence.verbose then if persistence.saveNotification then
trigger.action.outText("+++persistence: mission saved to\n" .. persistence.missionDir .. persistence.saveFileName, 30) trigger.action.outText("+++persistence: mission saved to\n" .. persistence.missionDir .. persistence.saveFileName, 30)
-- end end
end end
function persistence.noteCleanRestart() function persistence.noteCleanRestart()
@ -470,6 +472,8 @@ function persistence.readConfigZone()
persistence.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false) persistence.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
persistence.saveNotification = cfxZones.getBoolFromZoneProperty(theZone, "saveNotification", true)
if persistence.verbose then if persistence.verbose then
trigger.action.outText("+++persistence: read config", 30) trigger.action.outText("+++persistence: read config", 30)
end end

50
server modules/smrGUI.lua Normal file
View File

@ -0,0 +1,50 @@
smr = {}
smr.restartFlag = "simpleMissionRestart"
--
-- smr: simple mission restart (server module)
-- in your mission, set flag "simpleMissionRestart" to a value < 0 (zero)
-- and the server restarts the mission within one second
--
-- Created 20220902 by cfrag - version 1.0.0
--
-- misc procs
function smr.getServerFlagValue(theFlag)
-- execute getUserFlag() in server space
local val, errNo = net.dostring_in('server', " return trigger.misc.getUserFlag(\""..theFlag.."\"); ")
if (not val) and errNo then
net.log("smr - can't access flag, dostring_in returned <".. errNo .. ">")
return 0
else
-- dostring_in returns a string, so convert to number
return tonumber(val)
end
end
function smr.restartMission()
local mn = DCS.getMissionFilename( )
net.log("+++smr: restarting mission: ".. mn)
net.send_chat("+++smr: restarting mission: ".. mn, true)
local success = net.load_mission(mn)
if not success then
net.log("+++smr: FAILED to load <" .. mn .. ">")
net.send_chat("+++smr: FAILED to load <" .. mn .. ">", true)
end
end
-- main update loop, checked once per secon
local lTime = DCS.getModelTime()
function smr.onSimulationFrame()
if lTime + 1 < DCS.getModelTime() then
-- set next time
lTime = DCS.getModelTime()
-- check to see if the restartFlag is set
if not DCS.isServer() then return end
if smr.getServerFlagValue(smr.restartFlag) > 0 then
smr.restartMission()
end
end
end
-- install smr in hooks
DCS.setUserCallbacks(smr)