Version 0.9985

CivAir
QoL
fixes in ssbClient, cloneZone
This commit is contained in:
Christian Franz 2022-04-21 14:25:33 +02:00
parent 284063b829
commit ab1fb76c6f
14 changed files with 290 additions and 307 deletions

Binary file not shown.

Binary file not shown.

View File

@ -273,7 +273,7 @@ function cfxSSBClient:onEvent(event)
-- player entered unit? -- player entered unit?
-- check if this is cloned impostor -- check if this is cloned impostor
if not theUnit.getPlayerName then if not theUnit.getPlayerName then
trigger.action.outText("+++SSBC: non-player client " .. uName .. " detected, ignoring.", 30) trigger.action.outText("+++SSBC: non-player 'client' " .. uName .. " detected, ignoring.", 30)
return return
end end
local playerName = theUnit:getPlayerName() local playerName = theUnit:getPlayerName()

View File

@ -6,7 +6,7 @@
-- --
cfxZones = {} cfxZones = {}
cfxZones.version = "2.7.4" cfxZones.version = "2.7.5"
--[[-- VERSION HISTORY --[[-- VERSION HISTORY
- 2.2.4 - getCoalitionFromZoneProperty - 2.2.4 - getCoalitionFromZoneProperty
- getStringFromZoneProperty - getStringFromZoneProperty
@ -69,6 +69,7 @@ cfxZones.version = "2.7.4"
- 2.7.3 - testZoneFlag returns mathodResult, lastVal - 2.7.3 - testZoneFlag returns mathodResult, lastVal
- evalFlagMethodImmediate() - evalFlagMethodImmediate()
- 2.7.4 - doPollFlag supports immediate number setting - 2.7.4 - doPollFlag supports immediate number setting
- 2.7.5 - more QoL checks when mixing up ? and ! for attributes
--]]-- --]]--
cfxZones.verbose = false cfxZones.verbose = false
@ -1655,11 +1656,16 @@ end
function cfxZones.hasProperty(theZone, theProperty) function cfxZones.hasProperty(theZone, theProperty)
local foundIt = cfxZones.getZoneProperty(theZone, theProperty) local foundIt = cfxZones.getZoneProperty(theZone, theProperty)
if not foundIt then if not foundIt then
if string.sub(theProperty, -1) == "?" then -- check for possible forgotten or exchanged IO flags
if string.sub(theProperty, -1) == "?" then
local lessOp = theProperty:sub(1,-2) local lessOp = theProperty:sub(1,-2)
if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then
trigger.action.outText("*** NOTE: " .. theZone.name .. "'s property <" .. lessOp .. "> may be missing a Query ('?') symbol", 30) trigger.action.outText("*** NOTE: " .. theZone.name .. "'s property <" .. lessOp .. "> may be missing a Query ('?') symbol", 30)
end end
local lessPlus = lessOp .. "!"
if cfxZones.getZoneProperty(theZone, lessPlus) ~= nil then
trigger.action.outText("*** NOTE: " .. theZone.name .. "'s property <" .. lessOp .. "> may be using '!' instead of '?' for input", 30)
end
return false return false
end end
@ -1668,6 +1674,10 @@ function cfxZones.hasProperty(theZone, theProperty)
if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then if cfxZones.getZoneProperty(theZone, lessOp) ~= nil then
trigger.action.outText("*** NOTE: " .. theZone.name .. "'s property <" .. lessOp .. "> may be missing a Bang! ('!') symbol", 30) trigger.action.outText("*** NOTE: " .. theZone.name .. "'s property <" .. lessOp .. "> may be missing a Bang! ('!') symbol", 30)
end end
local lessPlus = lessOp .. "?"
if cfxZones.getZoneProperty(theZone, lessPlus) ~= nil then
trigger.action.outText("*** NOTE: " .. theZone.name .. "'s property <" .. lessOp .. "> may be using '!' instead of '?' for input", 30)
end
return false return false
end end

View File

@ -1,5 +1,5 @@
changer = {} changer = {}
changer.version = "0.0.0" changer.version = "1.0.0"
changer.verbose = false changer.verbose = false
changer.ups = 1 changer.ups = 1
changer.requiredLibs = { changer.requiredLibs = {
@ -15,11 +15,7 @@ changer.changers = {}
- not - not
- bool - bool
- value - value
- rnd
- count (? multiple signals, better done with xFlags)
- min, max minmax 2,3, cap,
--]]-- --]]--
function changer.addChanger(theZone) function changer.addChanger(theZone)
@ -48,14 +44,17 @@ function changer.createChangerWithZone(theZone)
-- triggerChangerMethod -- triggerChangerMethod
theZone.triggerChangerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change") theZone.triggerChangerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
if cfxZones.hasProperty(theZone, "triggerChangerMethod") then if cfxZones.hasProperty(theZone, "triggerChangeMethod") then
theZone.triggerChangerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerChangerMethod", "change") theZone.triggerChangerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerChangeMethod", "change")
end end
theZone.inEval = cfxZones.getBoolFromZoneProperty(theZone, "inEval", true) -- yes/no to pre-process, default is yes theZone.inEval = cfxZones.getBoolFromZoneProperty(theZone, "inEval", true) -- yes/no to pre-process, default is yes
theZone.changeTo = cfxZones.getStringFromZoneProperty(theZone, "to", "val") -- val, not, bool theZone.changeTo = cfxZones.getStringFromZoneProperty(theZone, "to", "val") -- val, not, bool
if cfxZones.hasProperty(theZone, "changeTo") then
theZone.changerTo = cfxZones.getStringFromZoneProperty(theZone, "changeTo", "val")
end
theZone.changeTo = string.lower(theZone.changeTo) theZone.changeTo = string.lower(theZone.changeTo)
theZone.changeTo = dcsCommon.trim(theZone.changeTo) theZone.changeTo = dcsCommon.trim(theZone.changeTo)
@ -64,6 +63,28 @@ function changer.createChangerWithZone(theZone)
theZone.changeOut = cfxZones.getStringFromZoneProperty(theZone, "changeOut!", "*none") theZone.changeOut = cfxZones.getStringFromZoneProperty(theZone, "changeOut!", "*none")
end end
-- pause / on / off commands
theZone.changerPaused = cfxZones.getBoolFromZoneProperty(theZone, "paused", false) -- we default to unpaused
if cfxZones.hasProperty(theZone, "changePaused") then
theZone.changerPaused = cfxZones.getBoolFromZoneProperty(theZone, "changePaused", false)
end
if theZone.changerPaused and (changer.verbose or theZone.verbose) then
trigger.action.outText("+++chgr: <" .. theZone.name .. "> starts paused", 30)
end
theZone.changerOn = cfxZones.getStringFromZoneProperty(theZone, "on?", "*<none>")
if cfxZones.hasProperty(theZone, "changeOn?") then
theZone.changerOn = cfxZones.getStringFromZoneProperty(theZone, "changeOn?", "*<none>")
end
theZone.lastChangerOnValue = cfxZones.getFlagValue(theZone.changerOn, theZone)
theZone.changerOff = cfxZones.getStringFromZoneProperty(theZone, "off?", "*<none>")
if cfxZones.hasProperty(theZone, "changeOff?") then
theZone.changerOff = cfxZones.getStringFromZoneProperty(theZone, "changeOff?", "*<none>")
end
theZone.lastChangerOffValue = cfxZones.getFlagValue(theZone.changerOff, theZone)
if changer.verbose or theZone.verbose then if changer.verbose or theZone.verbose then
trigger.action.outText("+++chgr: new changer zone <".. theZone.name ..">", 30) trigger.action.outText("+++chgr: new changer zone <".. theZone.name ..">", 30)
end end
@ -90,11 +111,14 @@ function changer.process(theZone)
-- process and write outflag -- process and write outflag
if op == "bool" then if op == "bool" then
if currVal == 0 then res = 0 else res = 1 end if currVal == 0 then res = 0 else res = 1 end
elseif elseif op == "not" then
op == "not" then
if currVal == 0 then res = 1 else res = 0 end if currVal == 0 then res = 1 else res = 0 end
elseif op == "val" or op == "direct" then
-- do nothing
else
trigger.action.outText("+++chgr: unsupported changeTo operation <" .. .. "> in zone <" .. .. ">, using 'val'", 30)
end end
-- all others drop through -- illegal ops drop through after warning, functioning as 'val'
-- write out -- write out
cfxZones.setFlagValueMult(theZone.changeOut, res, theZone) cfxZones.setFlagValueMult(theZone.changeOut, res, theZone)
@ -116,7 +140,27 @@ function changer.update()
timer.scheduleFunction(changer.update, {}, timer.getTime() + 1/changer.ups) timer.scheduleFunction(changer.update, {}, timer.getTime() + 1/changer.ups)
for idx, aZone in pairs(changer.changers) do for idx, aZone in pairs(changer.changers) do
changer.process(aZone)
-- process the pause/unpause flags
-- see if we should suspend
if cfxZones.testZoneFlag(theZone, theZone.changerOn, "change", "lastChangerOnValue") then
if changer.verbose or theZone.verbose then
trigger.action.outText("+++chgr: enabling " .. theZone.name, 30)
end
theZone.changerPaused = false
end
if cfxZones.testZoneFlag(theZone, theZone.changerOff, "change", "lastChangerOffValue") then
if changer.verbose or theZone.verbose then
trigger.action.outText("+++chgr: DISabling " .. theZone.name, 30)
end
theZone.changerPaused = true
end
-- do processing if not paused
if not aZone.changerPaused then
changer.process(aZone)
end
end end
end end
@ -173,4 +217,11 @@ end
if not changer.start() then if not changer.start() then
trigger.action.outText("cfx changer aborted: missing libraries", 30) trigger.action.outText("cfx changer aborted: missing libraries", 30)
changer = nil changer = nil
end end
--[[--
Possible expansions
- rnd
- min, max minmax 2,3, cap to left right values,
--]]--

View File

@ -1,5 +1,5 @@
civAir = {} civAir = {}
civAir.version = "1.4.0" civAir.version = "1.5.0"
--[[-- --[[--
1.0.0 initial version 1.0.0 initial version
1.1.0 exclude list for airfields 1.1.0 exclude list for airfields
@ -16,7 +16,12 @@ civAir.version = "1.4.0"
all configs it finds all configs it finds
module check module check
removed obsolete civAirConfig module removed obsolete civAirConfig module
1.5.0 process zones as in all other modules
verbose is part of config zone
reading type array from config corrected
massive simplifications: always between zoned airfieds
exclude list and include list
--]]-- --]]--
@ -34,52 +39,28 @@ civAir.aircraftTypes = {"Yak-40", "Yak-40", "C-130", "C-17A", "IL-76MD", "An-30
-- concurrently under way -- concurrently under way
civAir.maxTraffic = 10 -- number of flights at the same time civAir.maxTraffic = 10 -- number of flights at the same time
civAir.maxIdle = 8 * 60 -- seconds of ide time before it is removed after landing civAir.maxIdle = 8 * 60 -- seconds of ide time before it is removed after landing
civAir.trafficAirbases = {
randomized = 0, -- between any on map
localHubs = 1, -- between any two airfields inside the same random hub listed in trafficCenters
betweenHubs = 2 -- between any in random hub 1 to any in random hub 2
}
civAir.trafficRange = 100 -- 120000 -- defines hub size, in meters. Make it 100 to make it only that airfield
-- ABPickmethod determines how airfields are picked
-- for air traffic
civAir.ABPickMethod = civAir.trafficAirbases.betweenHubs
civAir.trafficCenters = { civAir.trafficCenters = {
--"batu", }
--"kobul", -- place zones on the map and add a "civAir" attribute.
--"senaki", -- If the attribute's value is anything
--"kutai", -- but "exclude", the closest airfield to the zone
} -- trafficCenters is used with hubs. Each entry defines a hub -- is added to trafficCenters
-- where we collect airdromes etc based on range
-- simply add a string to identify the hub center -- if you leave this list empty, and do not add airfields
-- e.g. "senak" to define "Senaki Kolkhi" -- by zones, the list is automatically populated with all
-- to have planes only fly between airfields in 100 km range -- airfields in the map
-- around senaki kolkhi, enter only senaki as traffic center, set
-- trafficRange to 100000 and ABPickMethod to localHubs
-- to have traffic only between any airfields listed
-- in trafficCenters, set trafficRange to a small value
-- like 100 meters and set ABPickMethod to betweenHubs
-- to have flights that always cross the map with multiple
-- airfields, choose two or three hubs that are 300 km apart,
-- then set trafficRange to 150000 and ABPickMethod to betweenHubs
-- you can also place zones on the map and add a
-- civAir attribute. If the attribute value is anything
-- but "exclude", the closest airfield to the zone
-- is added to trafficCenters
-- if you leave this list empty, and do not add airfields
-- by zones, the list is automatically populated by all
-- airfields in the map
civAir.excludeAirfields = { civAir.excludeAirfields = {
--"senaki",
} }
-- list all airfields that must NOT be included in -- list all airfields that must NOT be included in
-- civilian activities. Will be used for neither landing -- civilian activities. Will be used for neither landing
-- nor departure. overrides any airfield that was included -- nor departure. overrides any airfield that was included
-- in trafficCenters. Here, Senaki is off limits for -- in trafficCenters. Here, Senaki is off limits for
-- civilian air traffic -- civilian air traffic
-- can be populated by zone on the map that have the -- can be populated by zone on the map that have the
-- 'civAir' attribute with value "exclude" -- 'civAir' attribute with value "exclude"
civAir.requiredLibs = { civAir.requiredLibs = {
"dcsCommon", -- common is of course needed for everything "dcsCommon", -- common is of course needed for everything
@ -91,7 +72,7 @@ civAir.idlePlanes = {}
function civAir.readConfigZone() function civAir.readConfigZone()
-- note: must match exactly!!!! -- note: must match exactly!!!!
local theZone = cfxZones.getZoneByName("CivAirConfig") local theZone = cfxZones.getZoneByName("civAirConfig")
if not theZone then if not theZone then
trigger.action.outText("***civA: NO config zone!", 30) trigger.action.outText("***civA: NO config zone!", 30)
return return
@ -101,7 +82,10 @@ function civAir.readConfigZone()
-- ok, for each property, load it if it exists -- ok, for each property, load it if it exists
if cfxZones.hasProperty(theZone, "aircraftTypes") then if cfxZones.hasProperty(theZone, "aircraftTypes") then
civAir.aircraftTypes = cfxZones.getStringFromZoneProperty(theZone, "aircraftTypes", "Yak-40") local theTypes = cfxZones.getStringFromZoneProperty(theZone, "aircraftTypes", "Yak-40")
local typeArray = dcsCommon.splitString(theTypes, ",")
typeArray = dcsCommon.trimArray(typeArray)
civAir.aircraftTypes = typeArray
end end
if cfxZones.hasProperty(theZone, "ups") then if cfxZones.hasProperty(theZone, "ups") then
@ -117,18 +101,27 @@ function civAir.readConfigZone()
civAir.maxIdle = cfxZones.getNumberFromZoneProperty(theZone, "maxIdle", 8 * 60) civAir.maxIdle = cfxZones.getNumberFromZoneProperty(theZone, "maxIdle", 8 * 60)
end end
if cfxZones.hasProperty(theZone, "trafficRange") then
civAir.trafficRange = cfxZones.getNumberFromZoneProperty(theZone, "trafficRange", 120000) -- 120 km
end
if cfxZones.hasProperty(theZone, "ABPickMethod") then
civAir.ABPickMethod = cfxZones.getNumberFromZoneProperty(theZone, "ABPickMethod", 0) -- randomized any
end
if cfxZones.hasProperty(theZone, "initialAirSpawns") then if cfxZones.hasProperty(theZone, "initialAirSpawns") then
civAir.initialAirSpawns = cfxZones.getBoolFromZoneProperty(theZone, "initialAirSpawns", true) civAir.initialAirSpawns = cfxZones.getBoolFromZoneProperty(theZone, "initialAirSpawns", true)
end
civAir.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
end end
function civAir.processZone(theZone)
local value = cfxZones.getStringFromZoneProperty(theZone, "civAir", "")
local af = dcsCommon.getClosestAirbaseTo(theZone.point, 0) -- 0 = only airfields, not farp or ships
if af then
local afName = af:getName()
if value:lower() == "exclude" then
table.insert(civAir.excludeAirfields, afName)
else
table.insert(civAir.trafficCenters, afName) -- note that adding the same twice makes it more likely to be picked
end
else
trigger.action.outText("+++civA: unable to resolve airfield for <" .. theZone.name .. ">", 30)
end
end
function civAir.addPlane(thePlaneUnit) -- warning: is actually a group function civAir.addPlane(thePlaneUnit) -- warning: is actually a group
@ -158,122 +151,49 @@ function civAir.getPlane(aName) -- warning: returns GROUP!
return civAir.activePlanes[aName] return civAir.activePlanes[aName]
end end
-- get an air base, may exclude an airbase from choice
-- method is dependent on
function civAir.getAnAirbase(excludeThisOne)
-- different methods to select a base
-- purely random from current list
local theAB;
if civAir.ABPickMethod == civAir.trafficAirbases.randomized then
repeat
local allAB = dcsCommon.getAirbasesWhoseNameContains("*", 0) -- all airfields, no Ships nor FABS
theAB = dcsCommon.pickRandom(allAB)
until theAB ~= excludeThisOne
return theAB
end
if civAir.ABPickMethod == civAir.trafficAirbases.localHubs then
-- first, pick a hub name
end
trigger.action.outText("civA: warning - unknown method <" .. civAir.ABPickMethod .. ">", 30)
return nil
end
function civAir.excludeAirbases(inList, excludeList) function civAir.filterAirfields(inAll, inFilter)
if not inList then return {} end local outList = {}
if not excludeList then return inList end for idx, anItem in pairs(inAll) do
if #excludeList < 1 then return inList end if dcsCommon.arrayContainsString(inFilter, anItem) then
-- filtered, do nothing.
local theDict = {} else
-- build dict -- not filtered
for idx, aBase in pairs(inList) do table.insert(outList, anItem)
theDict[aBase:getName()] = aBase
end
-- now iterate through all excludes and remove them from dics
for idx, aName in pairs (excludeList) do
local allOfflimitAB = dcsCommon.getAirbasesWhoseNameContains(aName, 0)
for idx2, illegalBase in pairs (allOfflimitAB) do
theDict[illegalBase:getName()] = nil
end end
end end
-- now linearise (make array) from dict return outList
local theArray = dcsCommon.enumerateTable(theDict)
return theArray
end end
function civAir.getTwoAirbases() function civAir.getTwoAirbases()
local fAB local fAB -- first airbase to depart
local sAB local sAB -- second airbase to fly to
-- get any two airbases on the map
if civAir.ABPickMethod == civAir.trafficAirbases.randomized then -- remove all currently excluded air bases from available
local allAB = dcsCommon.getAirbasesWhoseNameContains("*", 0) -- all airfields, no Ships nor FABS, all coalitions local filteredAB = civAir.filterAirfields(civAir.trafficCenters, civAir.excludeAirfields)
-- remove illegal source/dest airfields -- if none left, error
allAB = civAir.excludeAirbases(allAB, civAir.excludeAirfields) if #filteredAB < 1 then
trigger.action.outText("+++civA: too few airfields")
return nil, nil
end
-- if one left use it twice, boring flight.
if #filteredAB < 2 then
local fabName = filteredAB[1]
fAB = dcsCommon.getAirbasesWhoseNameContains(fabName, 0)
return fAB, fAB -- same twice
end
-- pick any two that are not the same
fAB = dcsCommon.pickRandom(filteredAB)
repeat
sAB = dcsCommon.pickRandom(filteredAB)
until fAB ~= sAB
fAB = dcsCommon.getFirstAirbaseWhoseNameContains(fAB, 0)
sAB = dcsCommon.getFirstAirbaseWhoseNameContains(sAB, 0)
fAB = dcsCommon.pickRandom(allAB) return fAB, sAB
repeat
sAB = dcsCommon.pickRandom(allAB)
until fAB ~= sAB or (#allAB < 2)
return fAB, sAB
end
-- pick a hub, and then selct any two different airbases in the hub
if civAir.ABPickMethod == civAir.trafficAirbases.localHubs then
local hubName = dcsCommon.pickRandom(civAir.trafficCenters)
-- get the airfield that is identified by this
local theHub = dcsCommon.getFirstAirbaseWhoseNameContains(hubName, 0) -- only airfields, all coalitions
-- get all airbases that surround in range
local allAB = dcsCommon.getAirbasesInRangeOfAirbase(
theHub, -- centered on this base
true, -- include hub itself
civAir.trafficRange, -- hub size in meters
0 -- only airfields
)
allAB = civAir.excludeAirbases(allAB, civAir.excludeAirfields)
fAB = dcsCommon.pickRandom(allAB)
repeat
sAB = dcsCommon.pickRandom(allAB)
until fAB ~= sAB or (#allAB < 2)
return fAB, sAB
end
-- pick two hubs: one for source, one for destination airfields,
-- then pick an airfield from each hub
if civAir.ABPickMethod == civAir.trafficAirbases.betweenHubs then
--trigger.action.outText("between", 30)
local sourceHubName = dcsCommon.pickRandom(civAir.trafficCenters)
--trigger.action.outText("picked " .. sourceHubName, 30)
local sourceHub = dcsCommon.getFirstAirbaseWhoseNameContains(sourceHubName, 0)
--trigger.action.outText("sourceHub " .. sourceHub:getName(), 30)
local destHub
repeat destHubName = dcsCommon.pickRandom(civAir.trafficCenters)
until destHubName ~= sourceHubName or #civAir.trafficCenters < 2
destHub = dcsCommon.getFirstAirbaseWhoseNameContains(destHubName, 0)
--trigger.action.outText("destHub " .. destHub:getName(), 30)
local allAB = dcsCommon.getAirbasesInRangeOfAirbase(
sourceHub, -- centered on this base
true, -- include hub itself
civAir.trafficRange, -- hub size in meters
0 -- only airfields
)
allAB = civAir.excludeAirbases(allAB, civAir.excludeAirfields)
fAB = dcsCommon.pickRandom(allAB)
allAB = dcsCommon.getAirbasesInRangeOfAirbase(
destHub, -- centered on this base
true, -- include hub itself
civAir.trafficRange, -- hub size in meters
0 -- only airfields
)
allAB = civAir.excludeAirbases(allAB, civAir.excludeAirfields)
sAB = dcsCommon.pickRandom(allAB)
return fAB, sAB
end
trigger.action.outText("civA: warning - unknown method <" .. civAir.ABPickMethod .. "> in getTwoAirbases()", 30)
end end
function civAir.parkingIsFree(fromWP) function civAir.parkingIsFree(fromWP)
@ -370,6 +290,10 @@ function civAir.createNewFlight(inAirStart)
civAir.flightCount = civAir.flightCount + 1 civAir.flightCount = civAir.flightCount + 1
local fAB, sAB = civAir.getTwoAirbases() -- from AB local fAB, sAB = civAir.getTwoAirbases() -- from AB
if not fAB or not sAB then
trigger.action.outText("+++civA: cannot create flight, no source or destination", 30)
return
end
local name = fAB:getName() .. "-" .. sAB:getName().. "/" .. civAir.flightCount local name = fAB:getName() .. "-" .. sAB:getName().. "/" .. civAir.flightCount
local TypeString = dcsCommon.pickRandom(civAir.aircraftTypes) local TypeString = dcsCommon.pickRandom(civAir.aircraftTypes)
@ -500,17 +424,7 @@ function civAir.collectHubs()
local pZones = cfxZones.zonesWithProperty("civAir") local pZones = cfxZones.zonesWithProperty("civAir")
for k, aZone in pairs(pZones) do for k, aZone in pairs(pZones) do
local value = cfxZones.getStringFromZoneProperty(aZone, "civAir", "") civAir.processZone(aZone)
local af = dcsCommon.getClosestAirbaseTo(aZone.point, 0) -- 0 = only airfields, not farp or ships
if af then
local afName = af:getName()
if value:lower() == "exclude" then
table.insert(civAir.excludeAirfields, afName)
else
table.insert(civAir.trafficCenters, afName)
end
end
end end
end end
@ -536,17 +450,19 @@ function civAir.start()
-- make sure there is something in trafficCenters -- make sure there is something in trafficCenters
if #civAir.trafficCenters < 1 then if #civAir.trafficCenters < 1 then
trigger.action.outText("+++civTraffic: auto-populating", 30) trigger.action.outText("+++civA: auto-populating", 30)
-- simply add airfields on the map -- simply add airfields on the map
local allBases = dcsCommon.getAirbasesWhoseNameContains("*", 0) local allBases = dcsCommon.getAirbasesWhoseNameContains("*", 0)
for idx, aBase in pairs(allBases) do for idx, aBase in pairs(allBases) do
local afName = aBase:getName() local afName = aBase:getName()
--trigger.action.outText("+++civTraffic: adding " .. afName, 30)
table.insert(civAir.trafficCenters, afName) table.insert(civAir.trafficCenters, afName)
end end
end end
civAir.listTrafficCenters() if civAir.verbose then
civAir.listTrafficCenters()
end
-- air-start half population if allowed -- air-start half population if allowed
if civAir.initialAirSpawns then if civAir.initialAirSpawns then
@ -557,7 +473,7 @@ function civAir.start()
civAir.update() civAir.update()
-- say hi! -- say hi!
trigger.action.outText("cf/x civTraffic v" .. civAir.version .. " started.", 30) trigger.action.outText("cf/x civAir v" .. civAir.version .. " started.", 30)
return true return true
end end
@ -568,5 +484,11 @@ end
--[[-- --[[--
Additional ideas Additional ideas
source to target method
- border zones: ac can airstart in there and disappear in there
- callbacks for civ spawn / despawn
- add civkill callback / redCivKill blueCivKill flag bangers
- Helicopter support
- departure only, destination only
- add slot checking to see if other planes block it even though DCS claims the slot is free
--]]-- --]]--

View File

@ -1,5 +1,5 @@
cloneZones = {} cloneZones = {}
cloneZones.version = "1.4.1" cloneZones.version = "1.4.2"
cloneZones.verbose = false cloneZones.verbose = false
cloneZones.requiredLibs = { cloneZones.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -38,6 +38,8 @@ cloneZones.uniqueCounter = 9200000 -- we start group numbering here
- trackWith: attribute - trackWith: attribute
1.4.0 - Watchflags 1.4.0 - Watchflags
1.4.1 - trackWith: accepts list of trackers 1.4.1 - trackWith: accepts list of trackers
1.4.2 - onstart delays for 0.1 s to prevent static stacking
- turn bug for statics (bug in dcsCommon, resolved)
--]]-- --]]--
@ -688,7 +690,7 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
-- now use raw data to spawn and see if it works outabox -- now use raw data to spawn and see if it works outabox
--local theCat = cfxMX.catText2ID(cat) -- will be "static" --local theCat = cfxMX.catText2ID(cat) -- will be "static"
-- move origin trigger.action.outText("static object proccing", 30)
rawData.x = rawData.x + zoneDelta.x rawData.x = rawData.x + zoneDelta.x
rawData.y = rawData.y + zoneDelta.z -- !!! rawData.y = rawData.y + zoneDelta.z -- !!!
@ -704,7 +706,7 @@ function cloneZones.spawnWithTemplateForZone(theZone, spawnZone)
ctry = cloneZones.resolveOwnership(spawnZone, ctry) ctry = cloneZones.resolveOwnership(spawnZone, ctry)
-- handle linkUnit if provided -- handle linkUnit if provided
if rawData.linkUnit then if false and rawData.linkUnit then
--trigger.action.outText("has link to " .. rawData.linkUnit, 30) --trigger.action.outText("has link to " .. rawData.linkUnit, 30)
local lU = cloneZones.resolveStaticLinkUnit(rawData.linkUnit) local lU = cloneZones.resolveStaticLinkUnit(rawData.linkUnit)
--trigger.action.outText("resolved to " .. lU, 30) --trigger.action.outText("resolved to " .. lU, 30)
@ -869,14 +871,6 @@ function cloneZones.hasLiveUnits(theZone)
return false return false
end end
-- old code, deprecated
--[[--
function cloneZones.pollFlag(flagNum, method)
-- we currently ignore method
local num = trigger.misc.getUserFlag(flagNum)
trigger.action.setUserFlag(flagNum, num+1)
end
--]]--
-- --
-- UPDATE -- UPDATE
-- --
@ -903,20 +897,6 @@ function cloneZones.update()
end end
cloneZones.spawnWithCloner(aZone) cloneZones.spawnWithCloner(aZone)
end end
-- old code
--[[--
if aZone.spawnFlag then
local currTriggerVal = cfxZones.getFlagValue(aZone.spawnFlag, aZone) -- trigger.misc.getUserFlag(aZone.spawnFlag)
if currTriggerVal ~= aZone.lastSpawnValue
then
if cloneZones.verbose then
trigger.action.outText("+++clnZ: spawn triggered for <" .. aZone.name .. ">", 30)
end
cloneZones.spawnWithCloner(aZone)
aZone.lastSpawnValue = currTriggerVal
end
end
--]]--
-- empty handling -- empty handling
local isEmpty = cloneZones.countLiveUnits(aZone) < 1 and aZone.hasClones local isEmpty = cloneZones.countLiveUnits(aZone) < 1 and aZone.hasClones
@ -999,8 +979,12 @@ function cloneZones.start()
cloneZones.addCloneZone(aZone) -- remember it so we can smoke it cloneZones.addCloneZone(aZone) -- remember it so we can smoke it
end end
-- run through onStart -- run through onStart, but leave at least a few
cloneZones.onStart() -- cycles to go through object removal so statics
-- can spawn on ground. onStart is being deprecated, the
-- raiseFlag module covers this since the first time
-- raiseFlag is run is t0 + 0.5s
timer.scheduleFunction(cloneZones.onStart, {}, timer.getTime() + 0.1)
-- start update -- start update
cloneZones.update() cloneZones.update()
@ -1016,13 +1000,6 @@ if not cloneZones.start() then
cloneZones = nil cloneZones = nil
end end
--[[-- callback testing
czcb = {}
function czcb.callback(theZone, reason, args)
trigger.action.outText("clone CB: " .. theZone.name .. " with " .. reason, 30)
end
cloneZones.addCallback(czcb.callback)
--]]--
--[[-- --[[--
to resolve tasks to resolve tasks
@ -1030,4 +1007,5 @@ cloneZones.addCallback(czcb.callback)
- AFAC - AFAC
- FAC Assign group - FAC Assign group
- set freq for unit - set freq for unit
- embark / disembark
--]]-- --]]--

View File

@ -1,5 +1,5 @@
dcsCommon = {} dcsCommon = {}
dcsCommon.version = "2.5.9" dcsCommon.version = "2.6.1"
--[[-- VERSION HISTORY --[[-- VERSION HISTORY
2.2.6 - compassPositionOfARelativeToB 2.2.6 - compassPositionOfARelativeToB
- clockPositionOfARelativeToB - clockPositionOfARelativeToB
@ -70,6 +70,7 @@ dcsCommon.version = "2.5.9"
2.5.8 - string2GroupCat() 2.5.8 - string2GroupCat()
2.5.9 - string2ObjectCat() 2.5.9 - string2ObjectCat()
2.6.0 - unified uuid, removed uuIdent 2.6.0 - unified uuid, removed uuIdent
2.6.1 - removed bug in rotateUnitData: cy --> cz param passing
--]]-- --]]--
@ -1483,7 +1484,7 @@ dcsCommon.version = "2.5.9"
return px, py return px, py
end end
function dcsCommon.rotateUnitData(theUnit, degrees, cx, cy) function dcsCommon.rotateUnitData(theUnit, degrees, cx, cz)
if not cx then cx = 0 end if not cx then cx = 0 end
if not cz then cz = 0 end if not cz then cz = 0 end
local cy = cz local cy = cz

View File

@ -1,5 +1,5 @@
delayFlag = {} delayFlag = {}
delayFlag.version = "1.2.1" delayFlag.version = "1.2.2"
delayFlag.verbose = false delayFlag.verbose = false
delayFlag.requiredLibs = { delayFlag.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -31,6 +31,9 @@ delayFlag.flags = {}
1.2.0 - Watchflags 1.2.0 - Watchflags
1.2.1 - method goes to dlyMethod 1.2.1 - method goes to dlyMethod
- delay done is correctly inited - delay done is correctly inited
1.2.2 - delayMethod defaults to inc
- zone-local verbosity
- code clean-up
--]]-- --]]--
@ -58,7 +61,7 @@ end
function delayFlag.createTimerWithZone(theZone) function delayFlag.createTimerWithZone(theZone)
-- delay -- delay
theZone.delayMin, theZone.delayMax = cfxZones.getPositiveRangeFromZoneProperty(theZone, "timeDelay", 1) -- same as zone signature theZone.delayMin, theZone.delayMax = cfxZones.getPositiveRangeFromZoneProperty(theZone, "timeDelay", 1) -- same as zone signature
if delayFlag.verbose then if delayFlag.verbose or theZone.verbose then
trigger.action.outText("+++dlyF: time delay is <" .. theZone.delayMin .. ", " .. theZone.delayMax .. "> seconds", 30) trigger.action.outText("+++dlyF: time delay is <" .. theZone.delayMin .. ", " .. theZone.delayMax .. "> seconds", 30)
end end
@ -88,10 +91,10 @@ function delayFlag.createTimerWithZone(theZone)
end end
theZone.delayMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "flip") theZone.delayMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
if cfxZones.hasProperty(theZone, "delayMethod") then if cfxZones.hasProperty(theZone, "delayMethod") then
theZone.delayMethod = cfxZones.getStringFromZoneProperty(theZone, "delayMethod", "flip") theZone.delayMethod = cfxZones.getStringFromZoneProperty(theZone, "delayMethod", "inc")
end end
-- out flag -- out flag
@ -108,9 +111,6 @@ function delayFlag.createTimerWithZone(theZone)
theZone.lastTriggerStopValue = cfxZones.getFlagValue(theZone.triggerStopDelay, theZone) theZone.lastTriggerStopValue = cfxZones.getFlagValue(theZone.triggerStopDelay, theZone)
end end
-- init -- init
theZone.delayRunning = false theZone.delayRunning = false
theZone.timeLimit = -1 theZone.timeLimit = -1
@ -139,7 +139,7 @@ function delayFlag.startDelay(theZone)
if delay > theZone.delayMax then delay = theZone.delayMax end if delay > theZone.delayMax then delay = theZone.delayMax end
if delay < 1 then delay = 1 end if delay < 1 then delay = 1 end
if delayFlag.verbose then if delayFlag.verbose or theZone.verbose then
trigger.action.outText("+++dlyF: delay " .. theZone.name .. " range " .. delayMin .. "-" .. delayMax .. ": selected " .. delay, 30) trigger.action.outText("+++dlyF: delay " .. theZone.name .. " range " .. delayMin .. "-" .. delayMax .. ": selected " .. delay, 30)
end end
end end
@ -157,25 +157,14 @@ function delayFlag.update()
-- see if we need to stop -- see if we need to stop
if cfxZones.testZoneFlag(aZone, aZone.triggerStopDelay, aZone.delayTriggerMethod, "lastTriggerStopValue") then if cfxZones.testZoneFlag(aZone, aZone.triggerStopDelay, aZone.delayTriggerMethod, "lastTriggerStopValue") then
aZone.delayRunning = false -- simply stop. aZone.delayRunning = false -- simply stop.
if delayFlag.verbose then if delayFlag.verbose or aZone.verbose then
trigger.action.outText("+++dlyF: stopped delay " .. aZone.name, 30) trigger.action.outText("+++dlyF: stopped delay " .. aZone.name, 30)
end end
end end
-- old code
--[[--
if aZone.triggerStopDelay then
local currTriggerVal = cfxZones.getFlagValue(aZone.triggerStopDelay, aZone)
if currTriggerVal ~= lastTriggerStopValue then
aZone.delayRunning = false -- simply stop.
if delayFlag.verbose then
trigger.action.outText("+++dlyF: stopped delay " .. aZone.name, 30)
end
end
end
--]]--
if cfxZones.testZoneFlag(aZone, aZone.triggerDelayFlag, aZone.delayTriggerMethod, "lastDelayTriggerValue") then if cfxZones.testZoneFlag(aZone, aZone.triggerDelayFlag, aZone.delayTriggerMethod, "lastDelayTriggerValue") then
if delayFlag.verbose then if delayFlag.verbose or aZone.verbose then
if aZone.delayRunning then if aZone.delayRunning then
trigger.action.outText("+++dlyF: re-starting timer " .. aZone.name, 30) trigger.action.outText("+++dlyF: re-starting timer " .. aZone.name, 30)
else else
@ -184,25 +173,7 @@ function delayFlag.update()
end end
delayFlag.startDelay(aZone) -- we restart even if running delayFlag.startDelay(aZone) -- we restart even if running
end end
-- old code
--[[--
-- make sure to re-start before reading time limit
if aZone.triggerDelayFlag then
local currTriggerVal = cfxZones.getFlagValue(aZone.triggerDelayFlag, aZone) -- trigger.misc.getUserFlag(aZone.triggerDelayFlag)
if currTriggerVal ~= aZone.lastDelayTriggerValue
then
if delayFlag.verbose then
if aZone.delayRunning then
trigger.action.outText("+++dlyF: re-starting timer " .. aZone.name, 30)
else
trigger.action.outText("+++dlyF: init timer for " .. aZone.name, 30)
end
end
delayFlag.startDelay(aZone) -- we restart even if running
aZone.lastDelayTriggerValue = currTriggerVal
end
end
--]]--
if aZone.delayRunning then if aZone.delayRunning then
-- check expiry -- check expiry
@ -240,18 +211,7 @@ function delayFlag.readConfigZone()
end end
end end
--[[--
function delayFlag.onStart()
for idx, theZone in pairs(delayFlag.flags) do
if theZone.onStart then
if delayFlag.verbose then
trigger.action.outText("+++dlyF: onStart for <"..theZone.name .. ">", 30)
end
delayFlag.startDelay(theZone)
end
end
end
--]]--
function delayFlag.start() function delayFlag.start()
-- lib check -- lib check

View File

@ -13,6 +13,7 @@ radioTrigger.radioTriggers = {}
1.0.0 - initial version 1.0.0 - initial version
--]]-- --]]--
function radioTrigger.addRadioTrigger(theZone) function radioTrigger.addRadioTrigger(theZone)
table.insert(radioTrigger.radioTriggers, theZone) table.insert(radioTrigger.radioTriggers, theZone)
end end

View File

@ -1,5 +1,5 @@
unitZone={} unitZone={}
unitZone.version = "1.2.0" unitZone.version = "1.2.1"
unitZone.verbose = false unitZone.verbose = false
unitZone.ups = 1 unitZone.ups = 1
unitZone.requiredLibs = { unitZone.requiredLibs = {
@ -12,6 +12,7 @@ unitZone.requiredLibs = {
1.1.0 - DML flag integration 1.1.0 - DML flag integration
- method/uzMethod - method/uzMethod
1.2.0 - uzOn?, uzOff?, triggerMethod 1.2.0 - uzOn?, uzOff?, triggerMethod
1.2.1 - uzDirect
--]]-- --]]--
@ -96,6 +97,11 @@ function unitZone.createUnitZone(theZone)
end end
end end
-- uzDirect
if cfxZones.hasProperty(theZone, "uzDirect") then
theZone.uzDirect = cfxZones.getStringFromZoneProperty(theZone, "uzDirect", "*<none>")
end
-- on/off flags -- on/off flags
theZone.uzPaused = false -- we are turned on theZone.uzPaused = false -- we are turned on
theZone.triggerOnFlag = cfxZones.getStringFromZoneProperty(theZone, "uzOn?", "*<none1>") theZone.triggerOnFlag = cfxZones.getStringFromZoneProperty(theZone, "uzOn?", "*<none1>")
@ -260,6 +266,15 @@ function unitZone.update()
unitZone.bangState(aZone, newState) unitZone.bangState(aZone, newState)
aZone.lastStatus = newState aZone.lastStatus = newState
end end
-- output direct state
if aZone.uzDirect then
if newState then
cfxZones.setFlagValueMult(aZone.uzDirect, 1, aZone)
else
cfxZones.setFlagValueMult(aZone.uzDirect, 0, aZone)
end
end
end end
end end
end end

View File

@ -1,6 +1,7 @@
xFlags = {} xFlags = {}
xFlags.version = "1.2.1" xFlags.version = "1.2.1"
xFlags.verbose = false xFlags.verbose = false
xFlags.hiVerbose = false
xFlags.ups = 1 -- overwritten in get config when configZone is present xFlags.ups = 1 -- overwritten in get config when configZone is present
xFlags.requiredLibs = { xFlags.requiredLibs = {
"dcsCommon", -- always "dcsCommon", -- always
@ -22,6 +23,9 @@ xFlags.requiredLibs = {
- xSuccess optimizations - xSuccess optimizations
- inc, dec, quoted flags - inc, dec, quoted flags
- matchNum can carry flag - matchNum can carry flag
1.2.2 - on/off/suspend commands
- hiVerbose option
- corrected bug in reset checksum
--]]-- --]]--
xFlags.xFlagZones = {} xFlags.xFlagZones = {}
@ -33,6 +37,7 @@ end
-- create xFlag -- create xFlag
-- --
function xFlags.reset(theZone) function xFlags.reset(theZone)
theZone.flagChecksum = "" -- reset checksum
for i = 1, #theZone.flagNames do for i = 1, #theZone.flagNames do
-- since the checksum is order dependent, -- since the checksum is order dependent,
-- we must preserve the order of the array -- we must preserve the order of the array
@ -116,6 +121,18 @@ function xFlags.createXFlagsWithZone(theZone)
theZone.xOneShot = cfxZones.getBoolFromZoneProperty(theZone, "oneShot", true) theZone.xOneShot = cfxZones.getBoolFromZoneProperty(theZone, "oneShot", true)
-- on / off commands
-- on/off flags
theZone.xSuspended = cfxZones.getBoolFromZoneProperty(theZone, "xSuspended", false) -- we are turned on
if theZone.xSuspended and (xFlags.verbose or theZone.verbose) then
trigger.action.outText("+++xFlg: <" .. theZone.name .. "> starts suspended", 30)
end
theZone.xtriggerOnFlag = cfxZones.getStringFromZoneProperty(theZone, "xOn?", "*<none1>")
theZone.xlastTriggerOnValue = cfxZones.getFlagValue(theZone.xtriggerOnFlag, theZone)
theZone.xtriggerOffFlag = cfxZones.getStringFromZoneProperty(theZone, "xOff?", "*<none2>")
theZone.xlastTriggerOffValue = cfxZones.getFlagValue(theZone.xtriggerOffFlag, theZone)
end end
function xFlags.evaluateNumOrFlag(theAttribute, theZone) function xFlags.evaluateNumOrFlag(theAttribute, theZone)
@ -282,30 +299,41 @@ function xFlags.evaluateZone(theZone)
-- supported any/or, all/and, moreThan, atLeast, exactly -- supported any/or, all/and, moreThan, atLeast, exactly
local op = theZone.inspect local op = theZone.inspect
local evalResult = false local evalResult = false
if (op == "or" or op == "any" or op == "some") and hits > 0 then if (op == "or" or op == "any" or op == "some") then
evalResult = true if hits > 0 then evalResult = true end
elseif (op == "and" or op == "all") and hits == #theZone.flagNames then elseif (op == "and" or op == "all") then
evalResult = true if hits == #theZone.flagNames then evalResult = true end
elseif (op == "morethan" or op == "more than") and hits > matchNum then
evalResult = true elseif (op == "morethan" or op == "more than") then
elseif (op == "atleast" or op == "at least") and hits >= matchNum then if hits > matchNum then evalResult = true end
evalResult = true
elseif op == "exactly" and hits == matchNum then elseif (op == "atleast" or op == "at least") then
evalResult = true if hits >= matchNum then evalResult = true end
elseif (op == "none" or op == "nor") and hits == 0 then
evalResult = true elseif op == "exactly" then
elseif (op == "not all" or op == "notall" or op == "nand") and hits < #theZone.flagNames then if hits == matchNum then evalResult = true end
evalResult = true
elseif (op == "most") and hits > (#theZone.flagNames / 2) then elseif (op == "none" or op == "nor") then
evalResult = true if hits == 0 then evalResult = true end
elseif (op == "half" or op == "at least half" or op == "half or more") and hits >= (#theZone.flagNames / 2) then
-- warning: 'half' means really 'at least half" elseif (op == "not all" or op == "notall" or op == "nand") then
evalResult = true if hits < #theZone.flagNames then evalResult = true end
elseif (op == "most") then
if hits > (#theZone.flagNames / 2) then evalResult = true end
elseif (op == "half" or op == "at least half" or op == "half or more") then
if hits >= (#theZone.flagNames / 2) then
-- warning: 'half' means really 'at least half"
evalResult = true
end
else
trigger.action.outText("+++xFlg: WARNING: <" .. theZone.name .. "> has unknown requirement: <" .. op .. ">", 30)
end end
-- add "most" to more than 50% of flagnum -- add "most" to more than 50% of flagnum
-- now check if changed and if result true -- now check if changed and if result true
if checkSum ~= theZone.flagChecksum then if checkSum ~= theZone.flagChecksum then
if xFlags.verbose or theZone.verbose then if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xFlag: change detected for " .. theZone.name .. ": " .. theZone.flagChecksum .. "-->" ..checkSum, 30) trigger.action.outText("+++xFlag: change detected for " .. theZone.name .. ": " .. theZone.flagChecksum .. "-->" ..checkSum, 30)
@ -319,7 +347,7 @@ function xFlags.evaluateZone(theZone)
end end
theZone.flagChecksum = checkSum theZone.flagChecksum = checkSum
else else
if xFlags.verbose or theZone.verbose then if xFlags.hiVerbose and (xFlags.verbose or theZone.verbose) then
trigger.action.outText("+++xFlag: no change, checksum is |" .. checkSum .. "| for <" .. theZone.name .. ">", 10) trigger.action.outText("+++xFlag: no change, checksum is |" .. checkSum .. "| for <" .. theZone.name .. ">", 10)
end end
end end
@ -337,7 +365,7 @@ function xFlags.evaluateZone(theZone)
-- now see if we bang the output according to method -- now see if we bang the output according to method
if evalResult then if evalResult then
if xFlags.verbose or theZone.verbose then if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xFlag: success bang! on <" .. theZone.xSuccess .. "> for <" .. theZone.name .. ">", 30) trigger.action.outText("+++xFlag: success bang! on <" .. theZone.xSuccess .. "> for <" .. theZone.name .. "> with method <" .. theZone.xMethod .. ">", 30)
end end
cfxZones.pollFlag(theZone.xSuccess, theZone.xMethod, theZone) cfxZones.pollFlag(theZone.xSuccess, theZone.xMethod, theZone)
theZone.xHasFired = true theZone.xHasFired = true
@ -351,8 +379,25 @@ function xFlags.update()
timer.scheduleFunction(xFlags.update, {}, timer.getTime() + 1/xFlags.ups) timer.scheduleFunction(xFlags.update, {}, timer.getTime() + 1/xFlags.ups)
for idx, theZone in pairs (xFlags.xFlagZones) do for idx, theZone in pairs (xFlags.xFlagZones) do
-- see if we should suspend
if cfxZones.testZoneFlag(theZone, theZone.xtriggerOnFlag, "change", "xlastTriggerOnValue") then
if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xFlg: enabling " .. theZone.name, 30)
end
theZone.xSuspended = false
end
if cfxZones.testZoneFlag(theZone, theZone.xtriggerOffFlag, "change", "xlastTriggerOffValue") then
if xFlags.verbose or theZone.verbose then
trigger.action.outText("+++xFlg: DISabling " .. theZone.name, 30)
end
theZone.xSuspended = true
end
-- see if they should fire -- see if they should fire
xFlags.evaluateZone(theZone) if not theZone.xSuspended then
xFlags.evaluateZone(theZone)
end
-- see if they should reset -- see if they should reset
if theZone.xReset then if theZone.xReset then

Binary file not shown.

Binary file not shown.