mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 1.1.7
autoCSAR williePete ssbClient 3.0.0
This commit is contained in:
parent
4c0b0e8bed
commit
5ec26aaaf1
Binary file not shown.
Binary file not shown.
@ -27,7 +27,7 @@ function autoCSAR.createNewCSAR(theUnit)
|
||||
-- unit has no group
|
||||
local coa = theUnit:getCoalition()
|
||||
if coa == 0 then -- neutral
|
||||
trigger.action.outText("Neutal Pilot made it safely to ground.", 30)
|
||||
trigger.action.outText("Neutral Pilot made it safely to ground.", 30)
|
||||
return
|
||||
end
|
||||
if coa == 1 and not autoCSAR.redCSAR then
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxSSBClient = {}
|
||||
cfxSSBClient.version = "2.1.0"
|
||||
cfxSSBClient.version = "3.0.0"
|
||||
cfxSSBClient.verbose = false
|
||||
cfxSSBClient.singleUse = false -- set to true to block crashed planes
|
||||
-- NOTE: singleUse (true) requires SSB to disable immediate respawn after kick
|
||||
@ -19,7 +19,7 @@ Version History
|
||||
1.1.1 - performance tuning. only read player groups once
|
||||
- and remove in-air-start groups from scan. this requires
|
||||
- ssb (server) be not modified
|
||||
1.2.0 - API to close airfields: invoke openAirfieldNamed()
|
||||
1.2.0 - API to close airfields: invoke openAirFieldNamed()
|
||||
and closeAirfieldNamed() with name as string (exact match required)
|
||||
to block an airfield for any player aircraft.
|
||||
Works for FARPS as well
|
||||
@ -42,6 +42,12 @@ Version History
|
||||
in onEvent
|
||||
2.1.0 - slotState
|
||||
- persistence
|
||||
3.0.0 - closing an airfield will not kick players who are active
|
||||
- much better verbosity
|
||||
- open?
|
||||
- close?
|
||||
- also persists closed airfield list
|
||||
|
||||
|
||||
|
||||
WHAT IT IS
|
||||
@ -92,8 +98,59 @@ cfxSSBClient.closedAirfields = {} -- list that closes airfields for any aircraft
|
||||
cfxSSBClient.playerPlanes = {} -- names of units that a player is flying
|
||||
cfxSSBClient.crashedGroups = {} -- names of groups to block after crash of their player-flown plane
|
||||
cfxSSBClient.slotState = {} -- keeps a record of which slot has which value. For persistence and debugging
|
||||
cfxSSBClient.occupiedUnits = {} -- by unit name if occupied to prevent kicking. clears after crash or leaving plane
|
||||
-- will not be persisted because on start all planes are empty
|
||||
|
||||
-- dml zone interface for open/close interface
|
||||
cfxSSBClient.clientZones = {}
|
||||
|
||||
function cfxSSBClient.addClientZone(theZone)
|
||||
table.insert(cfxSSBClient.clientZones, theZone)
|
||||
end
|
||||
|
||||
function cfxSSBClient.getClientZoneByName(aName)
|
||||
for idx, aZone in pairs(cfxSSBClient.clientZones) do
|
||||
if aName == aZone.name then return aZone end
|
||||
end
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++ssbc: no client zone with name <" .. aName ..">", 30)
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
--
|
||||
-- read client zones
|
||||
--
|
||||
function cfxSSBClient.createClientZone(theZone)
|
||||
local thePoint = cfxZones.getPoint(theZone)
|
||||
local theAF = cfxSSBClient.getClosestAirbaseTo(thePoint)
|
||||
local afName = theAF:getName()
|
||||
if cfxSSBClient.verbose or theZone.verbose then
|
||||
trigger.action.outText("+++ssbc: zone <" .. theZone.name .. "> linked to AF/FARP <" .. afName .. ">", 30)
|
||||
end
|
||||
theZone.afName = afName
|
||||
theZone.ssbTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "ssbTriggerMethod", "change")
|
||||
|
||||
if cfxZones.hasProperty(theZone, "open?") then
|
||||
theZone.ssbOpen = cfxZones.getStringFromZoneProperty(theZone, "open?", "none")
|
||||
theZone.lastSsbOpen = cfxZones.getFlagValue(theZone.ssbOpen, theZone)
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(theZone, "close?") then
|
||||
theZone.ssbClose = cfxZones.getStringFromZoneProperty(theZone, "close?", "none")
|
||||
theZone.lastSsbClose = cfxZones.getFlagValue(theZone.ssbClose, theZone)
|
||||
end
|
||||
|
||||
theZone.ssbOpenOnStart = cfxZones.getBoolFromZoneProperty(theZone, "openOnStart", true)
|
||||
if not theZone.ssbOpenOnStart then
|
||||
cfxSSBClient.closeAirfieldNamed(theZone.afName)
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Open / Close Airfield API
|
||||
--
|
||||
function cfxSSBClient.closeAirfieldNamed(name)
|
||||
if not name then return end
|
||||
cfxSSBClient.closedAirfields[name] = true
|
||||
@ -155,6 +212,25 @@ function cfxSSBClient.setSlotAccessForGroup(theGroup)
|
||||
if not theGroup then return end
|
||||
-- WARNING: theGroup is cfxGroup record
|
||||
local theName = theGroup.name
|
||||
|
||||
-- we now check if any plane of that group is still
|
||||
-- existing and in the air. if so, we skip this check
|
||||
-- to prevent players being kicked for losing their
|
||||
-- originating airfield
|
||||
|
||||
-- we now iterate all playerUnits in theGroup.
|
||||
-- theGroup is cfxGroup
|
||||
for idx, playerData in pairs (theGroup.playerUnits) do
|
||||
local uName = playerData.name
|
||||
if cfxSSBClient.occupiedUnits[uName] then
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++ssbc: unit <" .. uName .. "> of group <" .. theName .. "> is occupied, no airfield check", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- when we get here, no unit in the entire group is occupied
|
||||
local theMatchingAirfield = theGroup.airfield
|
||||
-- airfield was attached at startup to group
|
||||
if cfxSSBClient.singleUse and cfxSSBClient.crashedGroups[theName] then
|
||||
@ -194,11 +270,17 @@ function cfxSSBClient.setSlotAccessForGroup(theGroup)
|
||||
end
|
||||
end
|
||||
-- set the ssb flag for this group so the server can see it
|
||||
if cfxSSBClient.verbose then
|
||||
local lastState = trigger.misc.getUserFlag(theName)
|
||||
if lastState ~= blockState then
|
||||
trigger.action.outText("+++ssbc: <" .. theName .. "> changes from <" .. lastState .. "> to <" .. blockState .. ">", 30)
|
||||
trigger.action.outText("+++SSB: group ".. theName .. ": " .. comment, 30)
|
||||
end
|
||||
end
|
||||
trigger.action.setUserFlag(theName, blockState)
|
||||
cfxSSBClient.slotState[theName] = blockState
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++SSB: group ".. theName .. ": " .. comment, 30)
|
||||
end
|
||||
--if cfxSSBClient.verbose then
|
||||
--end
|
||||
else
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++SSB: group ".. theName .. " no bound airfield: available", 30)
|
||||
@ -206,6 +288,18 @@ function cfxSSBClient.setSlotAccessForGroup(theGroup)
|
||||
end
|
||||
end
|
||||
|
||||
function cfxSSBClient.setSlotAccessForUnit(theUnit) -- calls setSlotAccessForGroup
|
||||
if not theUnit then return end
|
||||
local theGroup = theUnit:getGroup()
|
||||
if not theGroup then return end
|
||||
local gName = theGroup:getName()
|
||||
if not gName then return end
|
||||
local pGroup = cfxSSBClient.getPlayerGroupForGroupNamed(gName)
|
||||
if pGroup then
|
||||
cfxSSBClient.setSlotAccessForGroup(pGroup)
|
||||
end
|
||||
end
|
||||
|
||||
function cfxSSBClient.getPlayerGroupForGroupNamed(aName)
|
||||
local pGroups = cfxSSBClient.playerGroups
|
||||
for idx, theGroup in pairs(pGroups) do
|
||||
@ -217,11 +311,10 @@ end
|
||||
function cfxSSBClient.setSlotAccessByAirfieldOwner()
|
||||
-- get all groups that have a player-controlled aircraft
|
||||
-- now uses cached, reduced set of player planes
|
||||
local pGroups = cfxSSBClient.playerGroups -- cfxGroups.getPlayerGroup() -- we want the group.name attribute
|
||||
local pGroups = cfxSSBClient.playerGroups
|
||||
for idx, theGroup in pairs(pGroups) do
|
||||
cfxSSBClient.setSlotAccessForGroup(theGroup)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function cfxSSBClient.reOpenSlotForGroupNamed(args)
|
||||
@ -243,9 +336,6 @@ end
|
||||
|
||||
function cfxSSBClient:onEvent(event)
|
||||
if event.id == 21 then -- S_EVENT_PLAYER_LEAVE_UNIT
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++SSB: Player leave unit", 30)
|
||||
end
|
||||
local theUnit = event.initiator
|
||||
if not theUnit then
|
||||
if cfxSSBClient.verbose then
|
||||
@ -255,30 +345,38 @@ function cfxSSBClient:onEvent(event)
|
||||
end
|
||||
local curH = theUnit:getLife()
|
||||
local maxH = theUnit:getLife0()
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++SSB: Health check: " .. curH .. " of " .. maxH, 30)
|
||||
local uName = theUnit:getName()
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++SSB: Player leaves unit <" .. uName .. ">", 30)
|
||||
trigger.action.outText("+++SSB: unit health check: " .. curH .. " of " .. maxH, 30)
|
||||
end
|
||||
|
||||
cfxSSBClient.occupiedUnits[uName] = nil -- forget I was occupied
|
||||
cfxSSBClient.setSlotAccessForUnit(theUnit) -- prevent re-slotting if airfield lost
|
||||
return
|
||||
end
|
||||
|
||||
if event.id == 10 then -- S_EVENT_BASE_CAPTURED
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++SSB: CAPTURE EVENT -- RESETTING SLOTS", 30)
|
||||
if cfxSSBClient.verbose then
|
||||
local place = event.place
|
||||
|
||||
trigger.action.outText("+++SSB: CAPTURE EVENT: <" .. place:getName() .. "> now owned by <" .. place:getCoalition() .. "> -- RESETTING SLOTS", 30)
|
||||
end
|
||||
cfxSSBClient.setSlotAccessByAirfieldOwner()
|
||||
end
|
||||
|
||||
-- write down player names and planes
|
||||
if event.id == 15 then
|
||||
--trigger.action.outText("+++SSBC:SU: enter event 15", 30)
|
||||
if event.id == 15 then -- birth
|
||||
if not event.initiator then return end
|
||||
local theUnit = event.initiator -- we know this exists
|
||||
local uName = theUnit:getName()
|
||||
if not uName then return end
|
||||
-- player entered unit?
|
||||
-- check if this is cloned impostor
|
||||
-- check if this is a cloned impostor
|
||||
if not theUnit.getPlayerName then
|
||||
trigger.action.outText("+++SSBC: non-player 'client' " .. uName .. " detected, ignoring.", 30)
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++SSBC: non-player 'client' " .. uName .. " detected, ignoring.", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
local playerName = theUnit:getPlayerName()
|
||||
@ -291,12 +389,22 @@ function cfxSSBClient:onEvent(event)
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++SSBC:SU: noted " .. playerName .. " piloting player unit " .. uName, 30)
|
||||
end
|
||||
-- mark it as occupied to player won't get kicked until they
|
||||
-- leave the unit
|
||||
cfxSSBClient.occupiedUnits[uName] = playerName
|
||||
return
|
||||
end
|
||||
|
||||
if event.id == 5 then -- crash PRE-processing
|
||||
if not event.initiator then return end
|
||||
local theUnit = event.initiator
|
||||
local uName = theUnit:getName()
|
||||
cfxSSBClient.occupiedUnits[uName] = nil -- no longer occupied
|
||||
cfxSSBClient.setSlotAccessForUnit(theUnit) -- prevent re-slotting if airfield lost
|
||||
end
|
||||
|
||||
if cfxSSBClient.singleUse and event.id == 5 then -- crash
|
||||
if not event.initiator then return end
|
||||
--if not event.initiator then return end
|
||||
local theUnit = event.initiator
|
||||
local uName = theUnit:getName()
|
||||
if not uName then return end
|
||||
@ -321,7 +429,9 @@ function cfxSSBClient:onEvent(event)
|
||||
-- remember this plane to not re-enable if
|
||||
-- airfield changes hands later
|
||||
cfxSSBClient.crashedGroups[gName] = thePilot -- set to crash pilot
|
||||
trigger.action.outText("+++SSBC:SU: Blocked slot for group <" .. gName .. ">", 30)
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++SSBC:SU: Blocked slot for group <" .. gName .. ">", 30)
|
||||
end
|
||||
|
||||
if cfxSSBClient.reUseAfter > 0 then
|
||||
-- schedule re-opening this slot in <x> seconds
|
||||
@ -340,8 +450,38 @@ function cfxSSBClient.update()
|
||||
|
||||
-- now establish all slot blocks
|
||||
cfxSSBClient.setSlotAccessByAirfieldOwner()
|
||||
|
||||
-- show occupied planes
|
||||
if cfxSSBClient.verbose then
|
||||
for uName, pName in pairs (cfxSSBClient.occupiedUnits) do
|
||||
trigger.action.outText("+++ssbc: <" .. uName .. "> occupied by <" .. pName .. ">", 30)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function cfxSSBClient.dmlUpdate()
|
||||
-- first, re-schedule me in one second
|
||||
timer.scheduleFunction(cfxSSBClient.dmlUpdate, {}, timer.getTime() + 1)
|
||||
|
||||
for idx, theZone in pairs (cfxSSBClient.clientZones) do
|
||||
-- see if we received any signals on out inputs
|
||||
if theZone.ssbOpen and cfxZones.testZoneFlag(theZone, theZone.ssbOpen, theZone.ssbTriggerMethod, "lastSsbOpen") then
|
||||
if theZone.verbose then
|
||||
trigger.action.outText("+++ssbc: <" .. theZone.name .. "> open input triggered for <" .. theZone.afName .. ">", 30)
|
||||
end
|
||||
cfxSSBClient.openAirFieldNamed(theZone.afName)
|
||||
end
|
||||
|
||||
if theZone.ssbClose and cfxZones.testZoneFlag(theZone, theZone.ssbClose, theZone.ssbTriggerMethod, "lastSsbClose") then
|
||||
if theZone.verbose then
|
||||
trigger.action.outText("+++ssbc: <" .. theZone.name .. "> close input triggered for <" .. theZone.afName .. ">", 30)
|
||||
end
|
||||
cfxSSBClient.closeAirfieldNamed(theZone.afName)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- pre-process static player data to minimize
|
||||
-- processor load on checks
|
||||
function cfxSSBClient.processPlayerData()
|
||||
@ -376,7 +516,7 @@ function cfxSSBClient.processGroupData()
|
||||
theAirfield, delta = cfxSSBClient.getClosestAirbaseTo(playerData.point)
|
||||
local afName = theAirfield:getName()
|
||||
if cfxSSBClient.verbose then
|
||||
trigger.action.outText("+++SSB: group: " .. theGroup.name .. " closest to AF " .. afName .. ": " .. delta .. "m" , 30)
|
||||
trigger.action.outText("+++SSB: group: " .. theGroup.name .. " closest to AF " .. afName .. ": " .. math.floor(delta) .. "m" , 30)
|
||||
end
|
||||
if delta > cfxSSBClient.maxAirfieldRange then
|
||||
-- forget airfield
|
||||
@ -437,8 +577,10 @@ function cfxSSBClient.saveData()
|
||||
local theData = {}
|
||||
local states = dcsCommon.clone(cfxSSBClient.slotState)
|
||||
local crashed = dcsCommon.clone(cfxSSBClient.crashedGroups)
|
||||
local closed = dcsCommon.clone(cfxSSBClient.closedAirfields)
|
||||
theData.states = states
|
||||
theData.crashed = crashed
|
||||
theData.closed = closed
|
||||
return theData
|
||||
end
|
||||
|
||||
@ -463,12 +605,17 @@ function cfxSSBClient.loadData()
|
||||
trigger.action.outText("SSB: blocked <" .. slot .. "> on load", 30)
|
||||
end
|
||||
end
|
||||
|
||||
cfxSSBClient.crashedGroups = theData.crashed
|
||||
if not cfxSSBClient.crashedGroups then
|
||||
cfxSSBClient.crashedGroups = {}
|
||||
trigger.action.outText("SSBClient: nil crashers on load", 30)
|
||||
end
|
||||
if theData.crashed then
|
||||
cfxSSBClient.crashedGroups = theData.crashed
|
||||
if not cfxSSBClient.crashedGroups then
|
||||
cfxSSBClient.crashedGroups = {}
|
||||
trigger.action.outText("SSBClient: nil crashers on load", 30)
|
||||
end
|
||||
end
|
||||
|
||||
if theData.closed then
|
||||
cfxSSBClient.closedAirfields = theData.closed
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@ -495,9 +642,20 @@ function cfxSSBClient.start()
|
||||
-- into cfxSSBClient.playerGroups
|
||||
cfxSSBClient.processPlayerData()
|
||||
|
||||
-- process ssbc zones
|
||||
-- for in-mission DML interface
|
||||
local attrZones = cfxZones.getZonesWithAttributeNamed("ssbClient")
|
||||
for k, theZone in pairs(attrZones) do
|
||||
cfxSSBClient.createClientZone(theZone) -- process attributes
|
||||
cfxSSBClient.addClientZone(theZone) -- add to list
|
||||
end
|
||||
|
||||
-- install a timed update just to make sure
|
||||
-- and start NOW
|
||||
timer.scheduleFunction(cfxSSBClient.update, {}, timer.getTime() + 1)
|
||||
|
||||
-- start dml update (on a different timer
|
||||
cfxSSBClient.dmlUpdate()
|
||||
|
||||
-- now turn on ssb
|
||||
trigger.action.setUserFlag("SSB",100)
|
||||
@ -515,7 +673,6 @@ function cfxSSBClient.start()
|
||||
-- say hi!
|
||||
trigger.action.outText("cfxSSBClient v".. cfxSSBClient.version .. " running, SBB enabled", 30)
|
||||
|
||||
--cfxSSBClient.allYourBase()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxSmokeZone = {}
|
||||
cfxSmokeZone.version = "1.1.0"
|
||||
cfxSmokeZone.version = "1.1.1"
|
||||
cfxSmokeZone.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
"cfxZones", -- Zones, of course
|
||||
@ -16,16 +16,8 @@ cfxSmokeZone.requiredLibs = {
|
||||
- alphanum DML flag upgrade
|
||||
- random color support
|
||||
1.1.0 - Watchflag upgrade
|
||||
1.1.1 - stopSmoke? input
|
||||
|
||||
SMOKE ZONES *** EXTENDS ZONES ***
|
||||
keeps 'eternal' smoke up for any zone that has the
|
||||
'smoke' attribute
|
||||
|
||||
USAGE
|
||||
add a 'smoke' attribute to the zone. the value of the attribute
|
||||
defines the color. Valid values are: red, green, blue, white, orange, 0 (results in green smoke), 1 (red smoke), 2 (white), 3 (orange), 4 (blue)
|
||||
defaults to "green"
|
||||
altiude is meters above ground height, defaults to 5m
|
||||
--]]--
|
||||
cfxSmokeZone.smokeZones = {}
|
||||
cfxSmokeZone.updateDelay = 5 * 60 -- every 5 minutes
|
||||
@ -51,9 +43,7 @@ function cfxSmokeZone.processSmokeZone(aZone)
|
||||
-- f? query flags
|
||||
if cfxZones.hasProperty(aZone, "f?") then
|
||||
aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "f?", "*<none>")
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(aZone, "startSmoke?") then
|
||||
elseif cfxZones.hasProperty(aZone, "startSmoke?") then
|
||||
aZone.onFlag = cfxZones.getStringFromZoneProperty(aZone, "startSmoke?", "none")
|
||||
end
|
||||
|
||||
@ -61,6 +51,11 @@ function cfxSmokeZone.processSmokeZone(aZone)
|
||||
aZone.onFlagVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- save last value
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(aZone, "stopSmoke?") then
|
||||
aZone.smkStopFlag = cfxZones.getStringFromZoneProperty(aZone, "stopSmoke?", "<none>")
|
||||
aZone.smkLastStopFlag = cfxZones.getFlagValue(aZone.smkStopFlag, aZone)
|
||||
end
|
||||
|
||||
-- watchflags:
|
||||
-- triggerMethod
|
||||
aZone.smokeTriggerMethod = cfxZones.getStringFromZoneProperty(aZone, "triggerMethod", "change")
|
||||
@ -145,16 +140,13 @@ function cfxSmokeZone.checkFlags()
|
||||
-- see if this changed
|
||||
if cfxZones.testZoneFlag(aZone, aZone.onFlag, aZone.smokeTriggerMethod, "onFlagVal") then
|
||||
cfxSmokeZone.startSmoke(aZone)
|
||||
end
|
||||
--[[--
|
||||
-- old code
|
||||
local currTriggerVal = cfxZones.getFlagValue(aZone.onFlag, aZone) -- trigger.misc.getUserFlag(aZone.onFlag)
|
||||
if currTriggerVal ~= aZone.onFlagVal then
|
||||
-- yupp, trigger start
|
||||
cfxSmokeZone.startSmoke(aZone)
|
||||
aZone.onFlagVal = currTriggerVal
|
||||
end
|
||||
--]]--
|
||||
end
|
||||
end
|
||||
|
||||
if aZone.smkStopFlag then
|
||||
if cfxZones.testZoneFlag(aZone, aZone.smkStopFlag, aZone.smokeTriggerMethod, "smkLastStopFlag") then
|
||||
aZone.paused = true -- will no longer re-smoke on update
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
dcsCommon = {}
|
||||
dcsCommon.version = "2.7.5"
|
||||
dcsCommon.version = "2.7.6"
|
||||
--[[-- VERSION HISTORY
|
||||
2.2.6 - compassPositionOfARelativeToB
|
||||
- clockPositionOfARelativeToB
|
||||
@ -104,6 +104,7 @@ dcsCommon.version = "2.7.5"
|
||||
2.7.5 - new bitAND32()
|
||||
- new LSR()
|
||||
- new num2bin()
|
||||
2.7.6 - new getObjectsForCatAtPointWithRadius()
|
||||
|
||||
--]]--
|
||||
|
||||
@ -2693,6 +2694,25 @@ function dcsCommon.objectHandler(theObject, theCollector)
|
||||
return true
|
||||
end
|
||||
|
||||
function dcsCommon.getObjectsForCatAtPointWithRadius(aCat, thePoint, theRadius)
|
||||
if not aCat then aCat = Object.Category.UNIT end
|
||||
local p = {x=thePoint.x, y=thePoint.y, z=thePoint.z}
|
||||
local collector = {}
|
||||
|
||||
-- now build the search argument
|
||||
local args = {
|
||||
id = world.VolumeType.SPHERE,
|
||||
params = {
|
||||
point = p,
|
||||
radius = theRadius
|
||||
}
|
||||
}
|
||||
|
||||
-- now call search
|
||||
world.searchObjects(aCat, args, dcsCommon.objectHandler, collector)
|
||||
return collector
|
||||
end
|
||||
|
||||
function dcsCommon.getSceneryObjectsInZone(theZone) -- DCS ZONE!!!
|
||||
local aCat = 5 -- scenery
|
||||
-- WARNING: WE ARE USING DCS ZONES, NOT CFX!!!
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
persistence = {}
|
||||
persistence.version = "1.0.3"
|
||||
persistence.version = "1.0.4"
|
||||
persistence.ups = 1 -- once every 1 seconds
|
||||
persistence.verbose = false
|
||||
persistence.active = false
|
||||
@ -24,10 +24,11 @@ persistence.requiredLibs = {
|
||||
1.0.2 - QoL when verbosity is on
|
||||
1.0.3 - no longer always tells " mission saved to"
|
||||
new 'saveNotification" can be off
|
||||
1.0.4 - new optional 'root' property
|
||||
|
||||
|
||||
PROVIDES LOAD/SAVE ABILITY TO MODULES
|
||||
PROVIDES STANDALONE/HOSTED SERVER COMPATIOBILITY
|
||||
PROVIDES STANDALONE/HOSTED SERVER COMPATIBILITY
|
||||
|
||||
--]]--
|
||||
|
||||
@ -255,7 +256,6 @@ function persistence.initFlagsFromData(theFlags)
|
||||
trigger.action.outText("+++persistence: no flags loaded, commencing mission data load", 30)
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
|
||||
function persistence.missionStartDataLoad()
|
||||
@ -427,7 +427,24 @@ function persistence.readConfigZone()
|
||||
end
|
||||
|
||||
-- serverDir is the path from the server save directory, usually "Missions/".
|
||||
-- will be added to lfs.writedir().
|
||||
-- will be added to lfs.writedir() unless given a root attribute
|
||||
if cfxZones.hasProperty(theZone, "root") then
|
||||
-- we split this to enable further processing down the
|
||||
-- line if neccessary
|
||||
persistence.root = cfxZones.getStringFromZoneProperty(theZone, "root", lfs.writedir()) -- safe default
|
||||
if not dcsCommon.stringEndsWith(persistence.root, "\\") then
|
||||
persistence.root = persistence.root .. "\\"
|
||||
end
|
||||
if theZone.verbose then
|
||||
trigger.action.outText("+++persistence: setting root to <" .. persistence.root .. ">", 30)
|
||||
end
|
||||
else
|
||||
persistence.root = lfs.writedir() -- safe defaulting
|
||||
if theZone.verbose then
|
||||
trigger.action.outText("+++persistence: defaulting root to <" .. persistence.root .. ">", 30)
|
||||
end
|
||||
end
|
||||
|
||||
persistence.serverDir = cfxZones.getStringFromZoneProperty(theZone, "serverDir", "Missions\\")
|
||||
|
||||
if hasConfig then
|
||||
@ -509,13 +526,13 @@ function persistence.start()
|
||||
end
|
||||
end
|
||||
|
||||
local mainDir = lfs.writedir() .. persistence.serverDir
|
||||
-- local mainDir = lfs.writedir() .. persistence.serverDir
|
||||
local mainDir = persistence.root .. persistence.serverDir
|
||||
if not dcsCommon.stringEndsWith(mainDir, "\\") then
|
||||
mainDir = mainDir .. "\\"
|
||||
end
|
||||
-- lets see if we can access the server's mission directory and
|
||||
-- save directory
|
||||
-- we first try to access server's main mission directory, called "mainDir" which is usually <writeDir>/Missions/>
|
||||
|
||||
if persistence.isDir(mainDir) then
|
||||
if persistence.verbose then
|
||||
@ -563,6 +580,7 @@ function persistence.start()
|
||||
end
|
||||
end
|
||||
|
||||
-- missionDir is root + serverDir + saveDir
|
||||
persistence.missionDir = missionDir
|
||||
|
||||
persistence.active = true -- we can load and save data
|
||||
|
||||
@ -1,7 +1,8 @@
|
||||
williePete = {}
|
||||
williePete.version = "1.0.0"
|
||||
williePete.ups = 10 -- we update at 10 fps, so accuracy of a
|
||||
-- mach two missile is within 33 meters, with interpolation even less
|
||||
-- missile moving at Mach 2 is within 33 meters,
|
||||
-- with interpolation even at 3 meters
|
||||
|
||||
williePete.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
@ -12,8 +13,11 @@ williePete.requiredLibs = {
|
||||
williePete.willies = {}
|
||||
williePete.wpZones = {}
|
||||
williePete.playerGUIs = {} -- used for unit guis
|
||||
williePete.blastedObjects = {} -- used when we detonate something
|
||||
|
||||
williePete.smokeWeapons = {"HYDRA_70_M274","HYDRA_70_MK61","HYDRA_70_MK1","HYDRA_70_WTU1B","BDU_45B","BDU_33","BDU_45","BDU_45LGB","BDU_50HD","BDU_50LD","BDU_50LGB","C_8CM"}
|
||||
-- recognizes WP munitions. May require regular update when new
|
||||
-- models come out.
|
||||
williePete.smokeWeapons = {"HYDRA_70_M274","HYDRA_70_MK61","HYDRA_70_MK1","HYDRA_70_WTU1B","HYDRA_70_M156","HYDRA_70_M158","BDU_45B","BDU_33","BDU_45","BDU_45LGB","BDU_50HD","BDU_50LD","BDU_50LGB","C_8CM"}
|
||||
|
||||
function williePete.addWillie(theWillie)
|
||||
table.insert(williePete.willies, theWillie)
|
||||
@ -72,8 +76,6 @@ function williePete.getClosestZoneForCoa(point, coa)
|
||||
currDelta = delta
|
||||
closestZone = zData
|
||||
end
|
||||
else
|
||||
-- trigger.outText("Zone <" .. zData.name .. ">, coa <" .. zData.coalition .. "> does not match <" .. coa .. ">", 30)
|
||||
end
|
||||
end
|
||||
return closestZone, currDelta
|
||||
@ -91,19 +93,20 @@ function williePete.createWPZone(aZone)
|
||||
aZone.readyTime = 0 -- if readyTime > now we are not ready
|
||||
aZone.trackingPlayer = nil -- name player's unit who is being tracked for wp. may not be neccessary
|
||||
aZone.checkedIn = {} -- dict of all planes currently checked in
|
||||
aZone.trackingEndsTime = 0 -- if now > trackingends, we remove player and send a message
|
||||
|
||||
aZone.wpTriggerMethod = cfxZones.getStringFromZoneProperty(aZone, "wpTriggerMethod", "change")
|
||||
|
||||
aZone.FACTypes = cfxZones.getStringFromZoneProperty(aZone, "facTypes", "all")
|
||||
aZone.wpMethod = cfxZones.getStringFromZoneProperty(aZone, "wpMethod", "change")
|
||||
|
||||
aZone.checkInRange = cfxZones.getNumberFromZoneProperty(aZone, "checkInRange", williePete.checkInRange) -- default to my default
|
||||
|
||||
aZone.ackSound = cfxZones.getStringFromZoneProperty(aZone, "ackSound", williePete.ackSound)
|
||||
aZone.guiSound = cfxZones.getStringFromZoneProperty(aZone, "guiSound", williePete.guiSound)
|
||||
|
||||
if cfxZones.hasProperty(aZone, "triggerMethod") then
|
||||
aZone.wpTriggerMethod = cfxZones.getStringFromZoneProperty(aZone, "triggerMethod", "change")
|
||||
if cfxZones.hasProperty(aZone, "method") then
|
||||
aZone.wpMethod = cfxZones.getStringFromZoneProperty(aZone, "method", "change")
|
||||
end
|
||||
|
||||
if cfxZones.hasProperty(aZone, "wpFire!") then
|
||||
aZone.wpFire = cfxZones.getStringFromZoneProperty(aZone, "wpFire!", "<none)")
|
||||
end
|
||||
|
||||
if aZone.verbose then
|
||||
@ -112,7 +115,7 @@ function williePete.createWPZone(aZone)
|
||||
end
|
||||
|
||||
--
|
||||
-- player management
|
||||
-- PLAYER MANAGEMENT
|
||||
--
|
||||
function williePete.startPlayerGUI()
|
||||
-- scan all mx players
|
||||
@ -158,22 +161,33 @@ function williePete.startPlayerGUI()
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- BOOM
|
||||
--
|
||||
|
||||
--
|
||||
-- BOOM command
|
||||
--
|
||||
function williePete.doBoom(args)
|
||||
local unitInfo = args.unitInfo
|
||||
if unitInfo then
|
||||
-- note that unit who commânded fire may no longer be alive
|
||||
-- so check it every time. unit must be alive
|
||||
-- to receive credits later
|
||||
local uName = unitInfo.name
|
||||
local blastRad = math.floor(math.sqrt(args.strength)) * 2
|
||||
if blastRad < 10 then blastRad = 10 end
|
||||
|
||||
local affectedUnits = dcsCommon.getObjectsForCatAtPointWithRadius(nil, args.point, blastRad)
|
||||
for idx, aUnit in pairs(affectedUnits) do
|
||||
local aName = aUnit:getName()
|
||||
if williePete.verbose then
|
||||
trigger.action.outText("<" .. aName .. "> is in blast Radius (" .. blastRad .. "m) of shells for <" .. uName .. ">'s target coords", 30)
|
||||
end
|
||||
williePete.blastedObjects[aName] = uName -- last one gets the kill
|
||||
end
|
||||
end
|
||||
trigger.action.explosion(args.point, args.strength)
|
||||
data = {}
|
||||
data.point = args.point
|
||||
data.strength = args.strength
|
||||
-- cfxArtilleryZones.invokeCallbacksFor('impact', args.zone, data)
|
||||
|
||||
end
|
||||
|
||||
function williePete.doParametricFireAt(aPoint, accuracy, shellNum, shellBaseStrength, shellVariance, transitionTime)
|
||||
function williePete.doParametricFireAt(aPoint, accuracy, shellNum, shellBaseStrength, shellVariance, transitionTime, unitInfo)
|
||||
if williePete.verbose then
|
||||
trigger.action.outText("fire with accuracy <" .. accuracy .. "> shellNum <" .. shellNum .. "> baseStren <" .. shellBaseStrength .. "> variance <" .. shellVariance .. ">, ttime <" .. transitionTime .. ">", 30)
|
||||
end
|
||||
@ -200,6 +214,7 @@ function williePete.doParametricFireAt(aPoint, accuracy, shellNum, shellBaseStre
|
||||
thePoint.y = land.getHeight({x = thePoint.x, y = thePoint.z}) + 1 -- elevate to ground height + 1
|
||||
boomArgs.point = thePoint
|
||||
boomArgs.zone = aZone
|
||||
boomArgs.unitInfo = unitInfo
|
||||
local timeVar = 5 * (2 * dcsCommon.randomPercent() - 1.0) -- +/- 1.5 seconds
|
||||
if timeVar < 0 then timeVar = -timeVar end
|
||||
|
||||
@ -218,6 +233,12 @@ end
|
||||
function williePete.doCheckIn(unitInfo)
|
||||
--trigger.action.outText("check-in received", 30)
|
||||
local theUnit = Unit.getByName(unitInfo.name)
|
||||
if not theUnit then
|
||||
-- dead man calling. Pilot dead but unit still alive
|
||||
trigger.action.outText("Calling station, say again, can't read you.", 30)
|
||||
return
|
||||
end
|
||||
|
||||
local p = theUnit:getPoint()
|
||||
local theZone, dist = williePete.closestCheckInTgtZoneForCoa(p, unitInfo.coa)
|
||||
|
||||
@ -245,12 +266,12 @@ function williePete.doCheckIn(unitInfo)
|
||||
theZone.checkedIn[unitInfo.name] = unitInfo
|
||||
|
||||
-- add the 'Target marked' menu
|
||||
unitInfo.targetMarked = missionCommands.addCommandForGroup(unitInfo.gID, "Target Marked", unitInfo.root, williePete.redirectTargetMarked, unitInfo)
|
||||
unitInfo.targetMarked = missionCommands.addCommandForGroup(unitInfo.gID, "Target Marked, commence firing", unitInfo.root, williePete.redirectTargetMarked, unitInfo)
|
||||
-- remove 'check in'
|
||||
missionCommands.removeItemForGroup(unitInfo.gID, unitInfo.checkIn)
|
||||
unitInfo.checkIn = nil
|
||||
-- add 'check out'
|
||||
unitInfo.checkOut = missionCommands.addCommandForGroup(unitInfo.gID, "Check Out", unitInfo.root, williePete.redirectCheckOut, unitInfo)
|
||||
unitInfo.checkOut = missionCommands.addCommandForGroup(unitInfo.gID, "Check Out of " .. theZone.name, unitInfo.root, williePete.redirectCheckOut, unitInfo)
|
||||
|
||||
trigger.action.outTextForGroup(unitInfo.gID, "Roger " .. unitInfo.name .. ", " .. theZone.name .. " tracks you, standing by for target data.", 30)
|
||||
trigger.action.outSoundForGroup(unitInfo.gID, theZone.guiSound)
|
||||
@ -261,8 +282,6 @@ function williePete.redirectCheckOut(unitInfo)
|
||||
end
|
||||
|
||||
function williePete.doCheckOut(unitInfo)
|
||||
--trigger.action.outText("check-out received", 30)
|
||||
|
||||
-- check out of all zones
|
||||
local wasCheckedIn = false
|
||||
local fromZone = ""
|
||||
@ -305,10 +324,15 @@ function williePete.rogerDodger(args)
|
||||
end
|
||||
|
||||
function williePete.doTargetMarked(unitInfo)
|
||||
--trigger.action.outText("mark received", 30)
|
||||
-- first, check if we are past the time-out
|
||||
local now = timer.getTime()
|
||||
|
||||
if not unitInfo.wpInZone then
|
||||
trigger.action.outTextForGroup(unitInfo.gID, "No target mark visible, please mark again", 30)
|
||||
trigger.action.outSoundForGroup(unitInfo.gID, williePete.guiSound)
|
||||
return
|
||||
end
|
||||
|
||||
-- now check if zone matches check-in
|
||||
if not unitInfo.expiryTime or unitInfo.expiryTime < now then
|
||||
trigger.action.outTextForGroup(unitInfo.gID, "Target mark stale or ambiguous, set fresh mark", 30)
|
||||
@ -357,13 +381,15 @@ function williePete.doTargetMarked(unitInfo)
|
||||
local transitionTime = tgtZone.transitionTime
|
||||
local accuracy = tgtZone.baseAccuracy
|
||||
|
||||
williePete.doParametricFireAt(unitInfo.pos, accuracy, shellNum, shellStrength, 0.2, transitionTime)
|
||||
williePete.doParametricFireAt(unitInfo.pos, accuracy, shellNum, shellStrength, 0.2, transitionTime, unitInfo)
|
||||
|
||||
-- set zone's cooldown
|
||||
tgtZone.readyTime = now + tgtZone.coolDown
|
||||
-- erase player's wp mark
|
||||
unitInfo.wpInZone = nil
|
||||
unitInfo.pos = nil
|
||||
|
||||
-- if we have an output, trigger it now
|
||||
if tgtZone.wpFire then
|
||||
cfxZones.pollFlag(tgtZone.wpFire, tgtZone.wpMethod, tgtZone)
|
||||
end
|
||||
end
|
||||
-- return true if a zone is actively tracking theUnit to place
|
||||
-- a wp
|
||||
@ -381,16 +407,43 @@ function williePete.isWP(theWeapon)
|
||||
for idx, wpw in pairs(williePete.smokeWeapons) do
|
||||
if theDesc == wpw then return true end
|
||||
end
|
||||
trigger.action.outText(theDesc .. " is no wp, ignoring.", 30)
|
||||
return false
|
||||
end
|
||||
|
||||
function williePete.zedsDead(theObject)
|
||||
if not theObject then return end
|
||||
|
||||
local theName = theObject:getName()
|
||||
-- now check if it's a registered blasted object:getSampleRate()
|
||||
local blaster = williePete.blastedObjects[theName]
|
||||
if blaster then
|
||||
local theUnit = Unit.getByName(blaster)
|
||||
if theUnit then
|
||||
-- interface to playerscore
|
||||
if cfxPlayerScore then
|
||||
local fakeEvent = {}
|
||||
fakeEvent.initiator = theUnit -- killer
|
||||
fakeEvent.target = theObject -- vic
|
||||
cfxPlayerScore.killDetected(fakeEvent)
|
||||
end
|
||||
end
|
||||
williePete.blastedObjects[theName] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function williePete:onEvent(event)
|
||||
if not event.initiator then
|
||||
--trigger.action.outText("onEvent - " .. event.id .. ": no initiator",30)
|
||||
return
|
||||
end
|
||||
|
||||
-- check if it's a dead event
|
||||
if event.id == 8 then
|
||||
-- death event
|
||||
williePete.zedsDead(event.initiator)
|
||||
end
|
||||
|
||||
if not event.weapon then
|
||||
--trigger.action.outText("onEvent - " .. event.id .. ": no WEAPON",30)
|
||||
return
|
||||
end
|
||||
|
||||
@ -401,21 +454,18 @@ function williePete:onEvent(event)
|
||||
if event.id == 1 then -- S_EVENT_SHOT
|
||||
-- initiator is who fired. maybe want to test if player
|
||||
|
||||
--trigger.action.outText(theUnit:getName() .. " " .. pType .. " fired " .. event.weapon:getTypeName() .. ".", 30)
|
||||
|
||||
if not williePete.isWP(event.weapon) then
|
||||
--trigger.action.outText("<" .. event.weapon:getTypeName() .. "> not a smoke weapon", 30)
|
||||
-- we only trigger on WP weapons
|
||||
return
|
||||
end
|
||||
|
||||
-- make sure that whoever fired it is being tracked by
|
||||
-- a zone
|
||||
if not williePete.zoneIsTracking(theUnit) then
|
||||
--trigger.action.outText("<" .. event.weapon:getTypeName() .. "> fired while not being tracked by zone", 30)
|
||||
return
|
||||
end
|
||||
|
||||
-- assuming it's a willie, let's track it
|
||||
-- it's a willie, fired by player who is checked in: let's track it
|
||||
local theWillie = {}
|
||||
theWillie.firedBy = theUnit:getName()
|
||||
theWillie.theUnit = theUnit
|
||||
@ -427,16 +477,18 @@ function williePete:onEvent(event)
|
||||
williePete.addWillie(theWillie)
|
||||
end
|
||||
|
||||
--[[--
|
||||
if event.id == 2 then -- hit
|
||||
local what = "something"
|
||||
if event.target then what = event.target:getName() end
|
||||
--trigger.action.outText("Weapon " .. event.weapon:getTypeName() .. " fired by unit ".. theUnit:getName() .. " " .. pType .. " hit " .. what, 30)
|
||||
-- may need to remove willie from willies
|
||||
end
|
||||
--]]--
|
||||
|
||||
end
|
||||
|
||||
-- test if a projectile hit ground inside a wp zone
|
||||
-- test if a projectile has hit the ground inside a wp zone
|
||||
function williePete.isInside(theWillie)
|
||||
local thePoint = theWillie.pos
|
||||
local theUnitName = theWillie.firedBy -- may be dead already, but who cares
|
||||
@ -457,8 +509,6 @@ function williePete.isInside(theWillie)
|
||||
end
|
||||
-- if we want to allow neutral zones (doens't make sense)
|
||||
-- add another guard below
|
||||
else
|
||||
--trigger.action.outText("willie outside " .. theZone.name, 30)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
@ -471,7 +521,6 @@ function williePete.projectileHit(theWillie)
|
||||
-- interpolate pos: half time between updates times last velocity
|
||||
local vmod = dcsCommon.vMultScalar(theWillie.v, 0.5 / williePete.ups)
|
||||
theWillie.pos = dcsCommon.vAdd(theWillie.pos, vmod)
|
||||
--trigger.action.outText("Willie " .. theWillie.wt .. " expired at " .. dcsCommon.point2text(theWillie.pos) .. " interpolated.", 30)
|
||||
|
||||
-- reset last mark for player
|
||||
local thePlayer = williePete.playerGUIs[theWillie.firedBy]
|
||||
@ -493,15 +542,6 @@ function williePete.projectileHit(theWillie)
|
||||
thePlayer.pos = theWillie.pos -- remember the loc
|
||||
thePlayer.wpInZone = theZone -- remember the zone
|
||||
|
||||
-- mark point with smoke blue
|
||||
--dcsCommon.markPointWithSmoke(theWillie.pos, 4)
|
||||
|
||||
if cfxArtilleryZones then
|
||||
--cfxArtilleryZones.doParametricFireAt(theWillie.pos, 50, 10)
|
||||
else
|
||||
-- mark point with smoke blue
|
||||
--dcsCommon.markPointWithSmoke(theWillie.pos, 4)
|
||||
end
|
||||
end
|
||||
|
||||
function williePete.updateWP()
|
||||
@ -635,14 +675,3 @@ if not williePete.start() then
|
||||
trigger.action.outText("cf/x Willie Pete aborted: missing libraries", 30)
|
||||
williePete = nil
|
||||
end
|
||||
|
||||
--[[--
|
||||
Mechanics:
|
||||
- unit checks in with arty zone. if not in range of arty zone + safe dist, error 'not in range' is returned, else <artillery zone: status> is sent. <status can be ready, firing, or reloading>. Zone will advise on status change when checked in.
|
||||
- if unit leaves arty zone + safe dist, <leaving zone> is displayed and <checkout> is invoked
|
||||
- unit can check out any time
|
||||
- when checked in, any wp hitting the ground is remembered if still inside target zone
|
||||
- player then gives 'target marked'
|
||||
- if artillery on cooldown, or wp not inside zone error, else fire sequence starts, and cooldown starts for entire zone
|
||||
|
||||
--]]--
|
||||
@ -1,5 +1,5 @@
|
||||
xFlags = {}
|
||||
xFlags.version = "1.3.0"
|
||||
xFlags.version = "1.3.1"
|
||||
xFlags.verbose = false
|
||||
xFlags.hiVerbose = false
|
||||
xFlags.ups = 1 -- overwritten in get config when configZone is present
|
||||
@ -27,7 +27,13 @@ xFlags.requiredLibs = {
|
||||
- hiVerbose option
|
||||
- corrected bug in reset checksum
|
||||
1.3.0 - xCount! flag
|
||||
- "never" operator
|
||||
- "never" operator
|
||||
1.3.1 - guards for xtriggerOffFlag and xtriggerOnFlag
|
||||
to prevent QoL warnings
|
||||
- guards for xDirect
|
||||
- guards for xCount
|
||||
|
||||
|
||||
|
||||
--]]--
|
||||
xFlags.xFlagZones = {}
|
||||
@ -96,9 +102,13 @@ function xFlags.createXFlagsWithZone(theZone)
|
||||
theZone.xChange = cfxZones.getStringFromZoneProperty(theZone, "xChange!", "*<none>")
|
||||
end
|
||||
|
||||
theZone.xDirect = cfxZones.getStringFromZoneProperty(theZone, "xDirect", "*<none>")
|
||||
if cfxZones.hasProperty(theZone, "xDirect") then
|
||||
theZone.xDirect = cfxZones.getStringFromZoneProperty(theZone, "xDirect", "*<none>")
|
||||
end
|
||||
|
||||
theZone.xCount = cfxZones.getStringFromZoneProperty(theZone, "xCount", "*<none>")
|
||||
if cfxZones.hasProperty(theZone, "xCount") then
|
||||
theZone.xCount = cfxZones.getStringFromZoneProperty(theZone, "xCount", "*<none>")
|
||||
end
|
||||
|
||||
theZone.inspect = cfxZones.getStringFromZoneProperty(theZone, "require", "or") -- same as any
|
||||
-- supported any/or, all/and, moreThan, atLeast, exactly
|
||||
@ -132,11 +142,14 @@ function xFlags.createXFlagsWithZone(theZone)
|
||||
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)
|
||||
if cfxZones.hasProperty(theZone, "xOn?") then
|
||||
theZone.xtriggerOnFlag = cfxZones.getStringFromZoneProperty(theZone, "xOn?", "*<none1>")
|
||||
theZone.xlastTriggerOnValue = cfxZones.getFlagValue(theZone.xtriggerOnFlag, theZone)
|
||||
end
|
||||
if cfxZones.hasProperty(theZone, "xOff?") then
|
||||
theZone.xtriggerOffFlag = cfxZones.getStringFromZoneProperty(theZone, "xOff?", "*<none2>")
|
||||
theZone.xlastTriggerOffValue = cfxZones.getFlagValue(theZone.xtriggerOffFlag, theZone)
|
||||
end
|
||||
end
|
||||
|
||||
function xFlags.evaluateNumOrFlag(theAttribute, theZone)
|
||||
@ -363,15 +376,18 @@ function xFlags.evaluateZone(theZone)
|
||||
-- now directly set the value of evalResult (0 = false, 1 = true)
|
||||
-- to "xDirect". Always sets output to current result of evaluation
|
||||
-- true (1)/false(0), no matter if changed or not
|
||||
|
||||
if evalResult then
|
||||
cfxZones.setFlagValueMult(theZone.xDirect, 1, theZone)
|
||||
else
|
||||
cfxZones.setFlagValueMult(theZone.xDirect, 0, theZone)
|
||||
end
|
||||
if theZone.xDirect then
|
||||
if evalResult then
|
||||
cfxZones.setFlagValueMult(theZone.xDirect, 1, theZone)
|
||||
else
|
||||
cfxZones.setFlagValueMult(theZone.xDirect, 0, theZone)
|
||||
end
|
||||
end
|
||||
|
||||
-- directly set the xCount flag
|
||||
cfxZones.setFlagValueMult(theZone.xCount, hits, theZone)
|
||||
if theZone.xCount then
|
||||
cfxZones.setFlagValueMult(theZone.xCount, hits, theZone)
|
||||
end
|
||||
|
||||
-- now see if we bang the output according to method
|
||||
if evalResult then
|
||||
@ -391,14 +407,14 @@ function xFlags.update()
|
||||
|
||||
for idx, theZone in pairs (xFlags.xFlagZones) do
|
||||
-- see if we should suspend
|
||||
if cfxZones.testZoneFlag(theZone, theZone.xtriggerOnFlag, "change", "xlastTriggerOnValue") then
|
||||
if theZone.xtriggerOnFlag and 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 theZone.xtriggerOffFlag and cfxZones.testZoneFlag(theZone, theZone.xtriggerOffFlag, "change", "xlastTriggerOffValue") then
|
||||
if xFlags.verbose or theZone.verbose then
|
||||
trigger.action.outText("+++xFlg: DISabling " .. theZone.name, 30)
|
||||
end
|
||||
|
||||
BIN
sound FX/roger that click half.ogg
Normal file
BIN
sound FX/roger that click half.ogg
Normal file
Binary file not shown.
BIN
tutorial & demo missions/demo - Slot-Blocking and you.miz
Normal file
BIN
tutorial & demo missions/demo - Slot-Blocking and you.miz
Normal file
Binary file not shown.
BIN
tutorial & demo missions/demo - feats and autoCSAR.miz
Normal file
BIN
tutorial & demo missions/demo - feats and autoCSAR.miz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user