mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 1.4.2
NoGap, Wiper
This commit is contained in:
parent
7c6deec7a6
commit
23830d47db
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
|||||||
cfxReconMode = {}
|
cfxReconMode = {}
|
||||||
cfxReconMode.version = "2.2.0"
|
cfxReconMode.version = "2.2.1"
|
||||||
cfxReconMode.verbose = false -- set to true for debug info
|
cfxReconMode.verbose = false -- set to true for debug info
|
||||||
cfxReconMode.reconSound = "UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav" -- to be played when somethiong discovered
|
cfxReconMode.reconSound = "UI_SCI-FI_Tone_Bright_Dry_20_stereo.wav" -- to be played when somethiong discovered
|
||||||
|
|
||||||
@ -89,6 +89,7 @@ VERSION HISTORY
|
|||||||
2.2.0 - new marksLocked config attribute, defaults to false
|
2.2.0 - new marksLocked config attribute, defaults to false
|
||||||
- new marksFadeAfter config attribute to control mark time
|
- new marksFadeAfter config attribute to control mark time
|
||||||
- dmlZones OOP upgrade
|
- dmlZones OOP upgrade
|
||||||
|
2.2.1 - fixed "cfxReconSMode" typo
|
||||||
|
|
||||||
|
|
||||||
cfxReconMode is a script that allows units to perform reconnaissance
|
cfxReconMode is a script that allows units to perform reconnaissance
|
||||||
@ -657,7 +658,7 @@ function cfxReconMode.doDeActivate()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function cfxReconSMode.updateQueues()
|
function cfxReconMode.updateQueues()
|
||||||
-- schedule next call
|
-- schedule next call
|
||||||
timer.scheduleFunction(cfxReconMode.updateQueues, {}, timer.getTime() + 1/cfxReconMode.ups)
|
timer.scheduleFunction(cfxReconMode.updateQueues, {}, timer.getTime() + 1/cfxReconMode.ups)
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxZones = {}
|
cfxZones = {}
|
||||||
cfxZones.version = "4.0.0"
|
cfxZones.version = "4.0.2"
|
||||||
|
|
||||||
-- cf/x zone management module
|
-- cf/x zone management module
|
||||||
-- reads dcs zones and makes them accessible and mutable
|
-- reads dcs zones and makes them accessible and mutable
|
||||||
@ -150,6 +150,8 @@ cfxZones.version = "4.0.0"
|
|||||||
- immediate method switched to preceeding '#', to resolve conflict witzh
|
- immediate method switched to preceeding '#', to resolve conflict witzh
|
||||||
negative numbers, backwards compatibility with old (dysfunctional) method
|
negative numbers, backwards compatibility with old (dysfunctional) method
|
||||||
- 4.0.1 - dmlZone:getName()
|
- 4.0.1 - dmlZone:getName()
|
||||||
|
- 4.0.2 - removed verbosity from declutterZone (both versions)
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -963,17 +965,17 @@ end
|
|||||||
function cfxZones.declutterZone(theZone)
|
function cfxZones.declutterZone(theZone)
|
||||||
if not theZone then return end
|
if not theZone then return end
|
||||||
local theVol = cfxZones.getZoneVolume(theZone)
|
local theVol = cfxZones.getZoneVolume(theZone)
|
||||||
if theZone.verbose then
|
-- if theZone.verbose then
|
||||||
dcsCommon.dumpVar2Str("vol", theVol)
|
-- dcsCommon.dumpVar2Str("vol", theVol)
|
||||||
end
|
-- end
|
||||||
world.removeJunk(theVol)
|
world.removeJunk(theVol)
|
||||||
end
|
end
|
||||||
|
|
||||||
function dmlZone:declutterZone()
|
function dmlZone:declutterZone()
|
||||||
local theVol = cfxZones.getZoneVolume(self)
|
local theVol = cfxZones.getZoneVolume(self)
|
||||||
if self.verbose then
|
-- if self.verbose then
|
||||||
dcsCommon.dumpVar2Str("vol", theVol)
|
-- dcsCommon.dumpVar2Str("vol", theVol)
|
||||||
end
|
-- end
|
||||||
world.removeJunk(theVol)
|
world.removeJunk(theVol)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
130
modules/duel.lua
130
modules/duel.lua
@ -1,5 +1,5 @@
|
|||||||
duel = {}
|
duel = {}
|
||||||
duel.version = "1.0.0"
|
duel.version = "1.0.2"
|
||||||
duel.verbose = false
|
duel.verbose = false
|
||||||
duel.requiredLibs = {
|
duel.requiredLibs = {
|
||||||
"dcsCommon",
|
"dcsCommon",
|
||||||
@ -9,6 +9,8 @@ duel.requiredLibs = {
|
|||||||
--[[--
|
--[[--
|
||||||
Version History
|
Version History
|
||||||
1.0.0 - Initial Version
|
1.0.0 - Initial Version
|
||||||
|
1.0.1 - verbosity bug with SSB removed
|
||||||
|
1.0.2 - units are reserved for player when they disappear
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
@ -16,13 +18,16 @@ duel.requiredLibs = {
|
|||||||
ATTENTION!
|
ATTENTION!
|
||||||
- REQUIRES that SSB is running on the host
|
- REQUIRES that SSB is running on the host
|
||||||
- REQUIRTES that SSB is confgured that '0' (zero) means slot is enabled (this is SSB default)
|
- REQUIRTES that SSB is confgured that '0' (zero) means slot is enabled (this is SSB default)
|
||||||
|
- REQUIRES MULTIPLAYER (kind of obvious...)
|
||||||
- This script must run at MISSION START and will enable SSB
|
- This script must run at MISSION START and will enable SSB
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
duel.duelZones = {}
|
duel.duelZones = {}
|
||||||
duel.activeDuelists = {}
|
duel.activePlayers = {} -- by player name
|
||||||
duel.allDuelists = {}
|
--duel.activeUnits = {} -- as above, by unit name
|
||||||
|
--duel.missingPlayers = {}
|
||||||
|
duel.allDuelists = {} -- all potential dualists as collected from zones
|
||||||
--
|
--
|
||||||
-- reading attributes
|
-- reading attributes
|
||||||
--
|
--
|
||||||
@ -45,7 +50,7 @@ function duel.createDuelZone(theZone)
|
|||||||
duelist.groupName = groupData.name
|
duelist.groupName = groupData.name
|
||||||
duelist.coa = cfxMX.groupCoalitionByName[duelist.groupName]
|
duelist.coa = cfxMX.groupCoalitionByName[duelist.groupName]
|
||||||
if duel.verbose then
|
if duel.verbose then
|
||||||
trigger.action.outText("Detected player unit <" .. duelist.name .. ">, type <" .. duelist.type .. "> of group <" .. duelist.groupName .. "> of coa <" .. duelist.coa .. "> in zone <" .. theZone.name .. "> as duelist", 30)
|
-- trigger.action.outText("Detected player unit <" .. duelist.name .. ">, type <" .. duelist.type .. "> of group <" .. duelist.groupName .. "> of coa <" .. duelist.coa .. "> in zone <" .. theZone.name .. "> as duelist", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
duelist.active = false
|
duelist.active = false
|
||||||
@ -63,6 +68,20 @@ function duel.createDuelZone(theZone)
|
|||||||
end
|
end
|
||||||
|
|
||||||
theZone.state = "waiting" -- FSM, init to waiting state
|
theZone.state = "waiting" -- FSM, init to waiting state
|
||||||
|
theZone.duelTriggerMethod = theZone:getStringFromZoneProperty("duelTriggerMethod", "change")
|
||||||
|
if theZone:hasProperty("on?") then
|
||||||
|
theZone.duelOnFlag = theZone:getStringFromZoneProperty("on?", "*none")
|
||||||
|
theZone.lastDuelOn = theZone:getFlagValue(theZone.duelOnFlag)
|
||||||
|
end
|
||||||
|
if theZone:hasProperty("off?") then
|
||||||
|
theZone.duelOffFlag = theZone:getStringFromZoneProperty("off?", "*none")
|
||||||
|
theZone.lastDuelOff = theZone:getFlagValue(theZone.duelOffFlag)
|
||||||
|
end
|
||||||
|
theZone.onStart = theZone:getBoolFromZoneProperty("onStart", true)
|
||||||
|
theZone.active = true
|
||||||
|
if not theZone.onStart then
|
||||||
|
theZone.active = false
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -77,8 +96,8 @@ function duel.closeSlotsForZoneAndCoaExceptGroupNamed(theZone, coa, groupName)
|
|||||||
if (theDuelist.coa == coa) and (dgName ~= groupName) then
|
if (theDuelist.coa == coa) and (dgName ~= groupName) then
|
||||||
if duel.verbose then
|
if duel.verbose then
|
||||||
trigger.action.outText("+++duel: closing SSB slot for group <" .. dgName .. ">, coa <" .. theDuelist.coa .. ">", 30)
|
trigger.action.outText("+++duel: closing SSB slot for group <" .. dgName .. ">, coa <" .. theDuelist.coa .. ">", 30)
|
||||||
trigger.action.setUserFlag(dgName,100) -- anything but 0 means closed
|
|
||||||
end
|
end
|
||||||
|
trigger.action.setUserFlag(dgName,100) -- anything but 0 means closed
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -90,8 +109,8 @@ function duel.openSlotsForZoneAndCoa(theZone, coa)
|
|||||||
if (theDuelist.coa == coa) then
|
if (theDuelist.coa == coa) then
|
||||||
if duel.verbose then
|
if duel.verbose then
|
||||||
trigger.action.outText("+++duel: opening SSB slot for group <" .. theDuelist.groupName .. ">, coa <" .. theDuelist.coa .. ">", 30)
|
trigger.action.outText("+++duel: opening SSB slot for group <" .. theDuelist.groupName .. ">, coa <" .. theDuelist.coa .. ">", 30)
|
||||||
trigger.action.setUserFlag(theDuelist.groupName, 0) -- 0 means OPEN
|
|
||||||
end
|
end
|
||||||
|
trigger.action.setUserFlag(theDuelist.groupName, 0) -- 0 means OPEN
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -112,8 +131,15 @@ function duel.checkReopenSlotsForZoneAndCoa(theZone, coa)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if allUnengaged then
|
if allUnengaged then
|
||||||
|
if duel.verbose then
|
||||||
|
trigger.action.outText("+++duel: will open all slots for <" .. theZone:getName() .. ">, coa <" .. coa .. ">", 30)
|
||||||
|
end
|
||||||
duel.openSlotsForZoneAndCoa(theZone, coa)
|
duel.openSlotsForZoneAndCoa(theZone, coa)
|
||||||
theZone.state = "waiting"
|
theZone.state = "waiting"
|
||||||
|
else
|
||||||
|
if duel.verbose then
|
||||||
|
trigger.action.outText("+++duel: unable to reopenslots for <" .. theZone:getName() .. ">, coa <" .. coa .. ">, still engaged", 30)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -132,8 +158,45 @@ function duel.duelistEnteredArena(theUnit, theDuelist)
|
|||||||
trigger.action.outText("Player <" .. player .. "> entered arena <" .. theZone:getName() .. "> in unit <" .. unitName .. "> of group <" .. groupName .. "> type <" .. theDuelist.type .. ">, belongs to coalition <" .. coa .. ">", 30)
|
trigger.action.outText("Player <" .. player .. "> entered arena <" .. theZone:getName() .. "> in unit <" .. unitName .. "> of group <" .. groupName .. "> type <" .. theDuelist.type .. ">, belongs to coalition <" .. coa .. ">", 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- close all slots for this zone and coalition
|
-- remember this player should they go missing
|
||||||
|
local playerData = {}
|
||||||
|
playerData.playerName = player
|
||||||
|
playerData.unitName = unitName
|
||||||
|
playerData.lastSeen = timer.getTime()
|
||||||
|
playerData.theZone = theZone
|
||||||
|
playerData.coa = coa
|
||||||
|
|
||||||
|
-- see if we are updating an existing player.
|
||||||
|
-- this will require a cleanup of the last time they
|
||||||
|
-- were here
|
||||||
|
if duel.activePlayers[player] then
|
||||||
|
-- we need to update slots and flags if player has chosen a
|
||||||
|
-- different unit
|
||||||
|
local lastData = duel.activePlayers[player]
|
||||||
|
if lastData.unitName ~= unitName then
|
||||||
|
if duel.verbose then
|
||||||
|
trigger.action.outText("Duel: player changed slots. Cleaning up", 30)
|
||||||
|
end
|
||||||
|
duel.checkReopenSlotsForZoneAndCoa(lastData.theZone, lastData.coa)
|
||||||
|
else
|
||||||
|
if duel.verbose then
|
||||||
|
trigger.action.outText("Duel: player re-slotted, no update required", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
duel.activePlayers[player] = playerData
|
||||||
|
|
||||||
|
-- close all slots for this zone and coalition if it is active
|
||||||
|
if theZone.active then
|
||||||
|
if theZone.verbose or duel.verbose then
|
||||||
|
trigger.action.outText("+++duel: zone <" .. theZone:getName() .. ">, closing coa <" .. coa .. "> slots except for player's <" .. player .. "> group <" .. groupName .. ">", 30)
|
||||||
|
end
|
||||||
duel.closeSlotsForZoneAndCoaExceptGroupNamed(theZone, coa, groupName)
|
duel.closeSlotsForZoneAndCoaExceptGroupNamed(theZone, coa, groupName)
|
||||||
|
else
|
||||||
|
if theZone.verbose or duel.verbose then
|
||||||
|
trigger.action.outText("+++duel: zone <" .. theZone:getName() .. "> currently not active, not closing slots", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -155,6 +218,12 @@ function duel:onEvent(event)
|
|||||||
-- unit that entered is player controlled, and duelist
|
-- unit that entered is player controlled, and duelist
|
||||||
duel.duelistEnteredArena(theUnit, duel.allDuelists[unitName])
|
duel.duelistEnteredArena(theUnit, duel.allDuelists[unitName])
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if event.id == 21 then
|
||||||
|
if duel.verbose then
|
||||||
|
trigger.action.outText("DUEL: player left unit <" .. theUnit:getName() .. ">", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -166,6 +235,7 @@ function duel.update()
|
|||||||
timer.scheduleFunction(duel.update, {}, timer.getTime() + 1/duel.ups)
|
timer.scheduleFunction(duel.update, {}, timer.getTime() + 1/duel.ups)
|
||||||
|
|
||||||
-- find units that have disappeared, and react accordingly
|
-- find units that have disappeared, and react accordingly
|
||||||
|
--[[--
|
||||||
for unitName, theDuelist in pairs (duel.allDuelists) do
|
for unitName, theDuelist in pairs (duel.allDuelists) do
|
||||||
local theZone = theDuelist.zone
|
local theZone = theDuelist.zone
|
||||||
if theDuelist.active then
|
if theDuelist.active then
|
||||||
@ -185,10 +255,54 @@ function duel.update()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
--]]--
|
||||||
|
|
||||||
|
-- now check the active players and their units
|
||||||
|
local now = timer.getTime()
|
||||||
|
local filtered = {}
|
||||||
|
for playerName, playerData in pairs(duel.activePlayers) do
|
||||||
|
local unitName = playerData.unitName
|
||||||
|
local theUnit = Unit.getByName(unitName)
|
||||||
|
if theUnit and Unit.isExist(theUnit) then
|
||||||
|
-- all is well, nothing to do except update time stamp
|
||||||
|
playerData.lastSeen = now
|
||||||
|
filtered[playerName] = playerData
|
||||||
|
else
|
||||||
|
-- unit has disappeared. let's see how long
|
||||||
|
local delta = math.floor(now - playerData.lastSeen)
|
||||||
|
if duel.verbose then
|
||||||
|
trigger.action.outText("player <" .. playerName .. ">'s unit is gone for <" .. delta .. "> seconds now.", 30)
|
||||||
|
end
|
||||||
|
-- if gone long enough, open all slots and delete player entry
|
||||||
|
if delta < (duel.keepSlot + 1) then
|
||||||
|
filtered[playerName] = playerData -- remember me
|
||||||
|
else
|
||||||
|
if duel.verbose then
|
||||||
|
trigger.action.outText("Time's up, all slots reopen now, player lost tabs on <" .. unitName .. ">", 30)
|
||||||
|
end
|
||||||
|
-- update duelist data (if required)
|
||||||
|
|
||||||
|
-- open all slots in that zone for player's coa
|
||||||
|
duel.checkReopenSlotsForZoneAndCoa(playerData.theZone, playerData.coa)
|
||||||
|
|
||||||
|
-- not remembered
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
duel.activePlayers = filtered
|
||||||
|
|
||||||
-- now handle FSM for each zone separately
|
-- now handle FSM for each zone separately
|
||||||
for zoneName, theZone in pairs(duel.duelZones) do
|
for zoneName, theZone in pairs(duel.duelZones) do
|
||||||
|
-- first, check if they have been turned on or off
|
||||||
|
if theZone:testZoneFlag(theZone.duelOnFlag, theZone.duelTriggerMethod, "lastDuelOn") then
|
||||||
|
theZone.active = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if theZone:testZoneFlag(theZone.duelOffFlag, theZone.duelTriggerMethod, "lastDuelOff") then
|
||||||
|
theZone.active = false
|
||||||
|
duel.openSlotsForZoneAndCoa(theZone, 1)
|
||||||
|
duel.openSlotsForZoneAndCoa(theZone, 2)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -205,6 +319,8 @@ function duel.readConfigZone()
|
|||||||
duel.verbose = theZone.verbose
|
duel.verbose = theZone.verbose
|
||||||
duel.ups = theZone:getNumberFromZoneProperty("ups", 1)
|
duel.ups = theZone:getNumberFromZoneProperty("ups", 1)
|
||||||
|
|
||||||
|
duel.keepSlot = theZone:getNumberFromZoneProperty("keepSlot", 30) -- grace period (in seconds) after unit vanishes in which they can re-slot via Briefing screen
|
||||||
|
|
||||||
duel.inside = theZone:getBoolFromZoneProperty("inside", true)
|
duel.inside = theZone:getBoolFromZoneProperty("inside", true)
|
||||||
duel.gracePeriod = theZone:getNumberFromZoneProperty("gracePeriod", 30)
|
duel.gracePeriod = theZone:getNumberFromZoneProperty("gracePeriod", 30)
|
||||||
duel.keepScore = theZone:getBoolFromZoneProperty("score", true)
|
duel.keepScore = theZone:getBoolFromZoneProperty("score", true)
|
||||||
|
|||||||
406
modules/noGap.lua
Normal file
406
modules/noGap.lua
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
noGap = {}
|
||||||
|
noGap.version = "1.0.0"
|
||||||
|
|
||||||
|
noGap.verbose = false
|
||||||
|
noGap.ignoreMe = "-ng" -- ignore altogether
|
||||||
|
noGap.spIgnore = "-sp" -- only single-player ignored
|
||||||
|
noGap.isMP = false
|
||||||
|
noGap.enabled = true
|
||||||
|
noGap.timeOut = 0 -- in seconds, after that static restores, set to 0 to disable
|
||||||
|
|
||||||
|
noGap.requiredLibs = {
|
||||||
|
"dcsCommon",
|
||||||
|
"cfxZones",
|
||||||
|
"cfxMX",
|
||||||
|
}
|
||||||
|
--[[--
|
||||||
|
Written and (c) 2023 by Christian Franz
|
||||||
|
|
||||||
|
Based on stopGap. Unlike stopGap, noGap
|
||||||
|
works on unit-level (stop-Gap works on group level)
|
||||||
|
Advantage: multiple-ship player groups look better, less code
|
||||||
|
Disadvantage: incompatibe with SSB/slotBlock
|
||||||
|
|
||||||
|
What it does:
|
||||||
|
Replace all player units with static aircraft until the first time
|
||||||
|
that a player slots into that plane. Static is then replaced with live player unit.
|
||||||
|
|
||||||
|
DOES NOT SUPPORT SHIP-BASED AIRCRAFT
|
||||||
|
|
||||||
|
For multiplayer, NoGapGUI must run on the server (only server)
|
||||||
|
|
||||||
|
STRONGLY RECOMMENDED FOR MISSION DESIGNERS:
|
||||||
|
- Use 'start from ground hot/cold' to be able to control initial aircraft orientation
|
||||||
|
|
||||||
|
To selectively exempt player units from noGap, add a '-ng' to their name. To exclude them from singleplayer only, use '-sp'
|
||||||
|
Alternatively, use noGap zones (DML only)
|
||||||
|
|
||||||
|
Version History
|
||||||
|
1.0.0 - Initial version
|
||||||
|
|
||||||
|
--]]--
|
||||||
|
|
||||||
|
noGap.standInUnits = {} -- static replacement, if filled; indexed by name
|
||||||
|
noGap.liveUnits = {} -- live in-game units, checked regularly
|
||||||
|
noGap.allPlayerUnits = {} -- for update check to get server notification
|
||||||
|
noGap.noGapZones = {} -- DML only
|
||||||
|
|
||||||
|
function noGap.staticMXFromUnitMX(theGroup, theUnit)
|
||||||
|
-- enter with MX data blocks
|
||||||
|
-- build a static object from mx unit data
|
||||||
|
local theStatic = {}
|
||||||
|
theStatic.x = theUnit.x
|
||||||
|
theStatic.y = theUnit.y
|
||||||
|
theStatic.livery_id = theUnit.livery_id -- if exists
|
||||||
|
theStatic.heading = theUnit.heading -- may need some attention
|
||||||
|
theStatic.type = theUnit.type
|
||||||
|
theStatic.name = theUnit.name -- same as ME unit
|
||||||
|
theStatic.cty = cfxMX.countryByName[theGroup.name]
|
||||||
|
return theStatic
|
||||||
|
end
|
||||||
|
|
||||||
|
function noGap.staticMXFromUnitName(uName)
|
||||||
|
local theGroup = cfxMX.playerUnit2Group[uName]
|
||||||
|
local theUnit = cfxMX.playerUnitByName[uName]
|
||||||
|
if theGroup and theUnit then
|
||||||
|
return noGap.staticMXFromUnitMX(theGroup, theUnit)
|
||||||
|
end
|
||||||
|
trigger.action.outText("+++noG: ERROR: can't find MX data for unit <" .. uName .. ">", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
function noGap.isGroundStart(theGroup)
|
||||||
|
-- look at route
|
||||||
|
if not theGroup.route then return false end
|
||||||
|
local route = theGroup.route
|
||||||
|
local points = route.points
|
||||||
|
if not points then return false end
|
||||||
|
local ip = points[1]
|
||||||
|
if not ip then return false end
|
||||||
|
local action = ip.action
|
||||||
|
if action == "Fly Over Point" then return false end
|
||||||
|
if action == "Turning Point" then return false end
|
||||||
|
if action == "Landing" then return false end
|
||||||
|
-- aircraft is on the ground - but is it in water (carrier)?
|
||||||
|
local u1 = theGroup.units[1]
|
||||||
|
local sType = land.getSurfaceType(u1) -- has fields x and y
|
||||||
|
if sType == 3 then return false end
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("noG: Player Group <" .. theGroup.name .. "> GROUND BASED: " .. action .. ", land type " .. sType, 30)
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function noGap.ignoreMXUnit(theUnit) -- DML-only
|
||||||
|
local p = {x=theUnit.x, y=0, z=theUnit.y}
|
||||||
|
for idx, theZone in pairs(noGap.noGapZones) do
|
||||||
|
if theZone.ngIgnore and cfxZones.pointInZone(p, theZone) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
-- only single-player: exclude units in spIgnore zones
|
||||||
|
if (not noGap.isMP) and
|
||||||
|
theZone.spIgnore and cfxZones.pointInZone(p, theZone) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function noGap.createStandInForMXData(group, theUnit) -- group, theUnit are MX data blocks
|
||||||
|
local sgMatch = theUnit.name:sub(-#noGap.ignoreMe) == noGap.ignoreMe or group.name:sub(-#noGap.ignoreMe) == noGap.ignoreMe
|
||||||
|
local spMatch = theUnit.name:sub(-#noGap.spIgnore) == noGap.spIgnore or group.name:sub(-#noGap.spIgnore) == noGap.spIgnore
|
||||||
|
local zoneIgnore = noGap.ignoreMXUnit(theUnit)
|
||||||
|
local inGameUnit = Unit.getByName(theUnit.name)
|
||||||
|
if (theUnit.skill == "Client" or theUnit.skill == "Player")
|
||||||
|
and (not sgMatch)
|
||||||
|
and (not spMatch)
|
||||||
|
and (not zoneIgnore)
|
||||||
|
then
|
||||||
|
-- remember this unit as one to check regularly
|
||||||
|
noGap.allPlayerUnits[theUnit.name] = "NG" .. theUnit.name
|
||||||
|
-- replace this unit with stand-in if not already in game
|
||||||
|
if inGameUnit and Unit.isExist(inGameUnit) then
|
||||||
|
-- already exists, do NOT allocate, and erase
|
||||||
|
-- any lingering data
|
||||||
|
noGap.standInUnits[theUnit.name] = nil -- forget static
|
||||||
|
noGap.liveUnits[theUnit.name] = inGameUnit -- remember live
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++noG: skipped - unit <" .. theUnit.name .. "> of <" .. group.name .. ">", 30)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- create a stand-in
|
||||||
|
-- and remember
|
||||||
|
local theStaticMX = noGap.staticMXFromUnitMX(group, theUnit)
|
||||||
|
local theStatic = coalition.addStaticObject(theStaticMX.cty, theStaticMX)
|
||||||
|
noGap.standInUnits[theUnit.name] = theStatic -- remember me
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++noG: unit <" .. theUnit.name .. "> of <" .. group.name .. "> nogapped", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function noGap.fillGaps()
|
||||||
|
-- turn on. May turn on any time, even during game
|
||||||
|
-- when we enter, all slots should be emptry
|
||||||
|
-- and we populate all slots. If slot in use, don't populate
|
||||||
|
-- with their static representations
|
||||||
|
-- a 'slot' is a player aircraft
|
||||||
|
-- iterate all groups that have at least one player and groundstart
|
||||||
|
-- as filtered by cfxMX
|
||||||
|
-- we need to access group because that contains start info
|
||||||
|
for gName, groupData in pairs (cfxMX.playerGroupByName) do
|
||||||
|
-- check to see if this group is on the ground at parking
|
||||||
|
-- by looking at the first waypoint
|
||||||
|
if noGap.isGroundStart(groupData) then
|
||||||
|
-- this is one of ours!
|
||||||
|
-- iterate all player units in this group,
|
||||||
|
-- and replace those units that are player units
|
||||||
|
local allUnits = groupData.units
|
||||||
|
for idx, unitData in pairs(allUnits) do
|
||||||
|
noGap.createStandInForMXData(groupData, unitData)
|
||||||
|
end
|
||||||
|
end -- if groundtstart
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function noGap.turnOff()
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++noG: Turning OFF", 30)
|
||||||
|
end
|
||||||
|
-- remove all stand-ins
|
||||||
|
for uName, standIn in pairs (noGap.standInUnits) do
|
||||||
|
StaticObject.destroy(standIn)
|
||||||
|
end
|
||||||
|
noGap.standInUnits = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
function noGap.turnOn()
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++noG: Turning on", 30)
|
||||||
|
end
|
||||||
|
-- populate all empty (non-taken) slots with stand-ins
|
||||||
|
noGap.fillGaps()
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- event handling
|
||||||
|
--
|
||||||
|
function noGap:onEvent(event)
|
||||||
|
if not event then return end
|
||||||
|
if not event.id then return end
|
||||||
|
if not event.initiator then return end
|
||||||
|
local theUnit = event.initiator
|
||||||
|
|
||||||
|
if event.id == 15 then -- we act on player unit birth
|
||||||
|
if (not theUnit.getPlayerName) or (not theUnit:getPlayerName()) then
|
||||||
|
return
|
||||||
|
end -- no player unit.
|
||||||
|
local uName = theUnit:getName()
|
||||||
|
|
||||||
|
if noGap.standInUnits[uName] then
|
||||||
|
-- remove static
|
||||||
|
StaticObject.destroy(noGap.standInUnits[uName])
|
||||||
|
noGap.standInUnits[uName] = nil
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++noG: removed static for <" ..uName .. ">, player inbound", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
noGap.liveUnits[uName] = theUnit
|
||||||
|
-- reset noGapGUI flag, it has done its job. Unit is live
|
||||||
|
-- we can reset it for next iteration
|
||||||
|
trigger.action.setUserFlag("NG"..uName, 0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- update, includes MP client check code
|
||||||
|
--
|
||||||
|
function noGap.update()
|
||||||
|
-- check every second.
|
||||||
|
timer.scheduleFunction(noGap.update, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
|
if not noGap.isMP then
|
||||||
|
local ngDetect = trigger.misc.getUserFlag("noGapGUI")
|
||||||
|
if ngDetect > 0 then
|
||||||
|
trigger.action.outText("noGap: MP activated <" .. ngDetect .. ">, will re-init", 30)
|
||||||
|
noGap.turnOff()
|
||||||
|
noGap.isMP = true
|
||||||
|
if noGap.enabled then
|
||||||
|
noGap.turnOn()
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- check if client signals for on? or off?
|
||||||
|
if noGap.turnOn and cfxZones.testZoneFlag(noGap, noGap.turnOnFlag, noGap.triggerMethod, "lastTurnOnFlag") -- warning: noGap is NOT a dmlZone, requires cfxZone invocation
|
||||||
|
then
|
||||||
|
if not noGap.enabled then
|
||||||
|
noGap.turnOn()
|
||||||
|
else
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++noG: ignored tun ON event, already active", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
noGap.enabled = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if noGap.turnOff and cfxZones.testZoneFlag(noGap, noGap.turnOffFlag, noGap.triggerMethod, "lastTurnOffFlag") then
|
||||||
|
if noGap.enabled then
|
||||||
|
noGap.turnOff()
|
||||||
|
end
|
||||||
|
noGap.enabled = false
|
||||||
|
end
|
||||||
|
|
||||||
|
if not noGap.enabled then return end
|
||||||
|
|
||||||
|
-- check if activeUnit has disappeared an returns to slot
|
||||||
|
local filtered = {}
|
||||||
|
for name, theUnit in pairs(noGap.liveUnits) do
|
||||||
|
if Unit.isExist(theUnit) then
|
||||||
|
-- unit still alive
|
||||||
|
filtered[name] = theUnit
|
||||||
|
else
|
||||||
|
-- unit disappeared, make static show up in slot
|
||||||
|
-- no copy to filtered
|
||||||
|
local theStaticMX = noGap.staticMXFromUnitName(name)
|
||||||
|
local theStatic = coalition.addStaticObject(theStaticMX.cty, theStaticMX)
|
||||||
|
noGap.standInUnits[name] = theStatic -- remember me
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++noG: unit <" .. name .. "> nogapped", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
noGap.liveUnits = filtered
|
||||||
|
|
||||||
|
-- check if noGapGUI signals slot interest by player
|
||||||
|
for name, ngName in pairs (noGap.allPlayerUnits) do
|
||||||
|
local ngFlag = trigger.misc.getUserFlag(ngName)
|
||||||
|
if ngFlag > 0 then
|
||||||
|
if noGap.standInUnits[name] then
|
||||||
|
-- static needs to be removed, server wants to occupy
|
||||||
|
StaticObject.destroy(noGap.standInUnits[name])
|
||||||
|
noGap.standInUnits[name] = nil
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++noG: removing static <" .. name .. "> for server request", 30)
|
||||||
|
end
|
||||||
|
-- set flag-based timer
|
||||||
|
if noGap.timeOut > 0 then
|
||||||
|
trigger.action.setUserFlag(ngName,-noGap.timeOut)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif ngFlag < 0 then
|
||||||
|
-- timer is running, count up to 0
|
||||||
|
ngFlag = ngFlag + 1
|
||||||
|
if ngFlag > -1 then
|
||||||
|
-- timeout. restore static. this may cause if crash if
|
||||||
|
-- player waited too long without actually slotting in.
|
||||||
|
ngFlag = 0
|
||||||
|
local theStaticMX = noGap.staticMXFromUnitName(name)
|
||||||
|
local theStatic = coalition.addStaticObject(theStaticMX.cty, theStaticMX)
|
||||||
|
noGap.standInUnits[name] = theStatic -- remember me
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++noG: unit <" .. name .. "> restored after timeout", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
trigger.action.setUserFlag(ngName, ngFlag)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- read stopGapZone (DML only)
|
||||||
|
--
|
||||||
|
function noGap.createNoGapZone(theZone)
|
||||||
|
local ng = theZone:getBoolFromZoneProperty("noGap", true)
|
||||||
|
if ng then theZone.ngIgnore = false else theZone.sgIgnore = true end
|
||||||
|
end
|
||||||
|
|
||||||
|
function noGap.createNoGapSPZone(theZone)
|
||||||
|
local sp = theZone:getBoolFromZoneProperty("noGapSP", true)
|
||||||
|
if sp then theZone.spIgnore = false else theZone.spIgnore = true end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Read Config Zone
|
||||||
|
--
|
||||||
|
noGap.name = "noGapConfig" -- cfxZones compatibility here
|
||||||
|
function noGap.readConfigZone(theZone)
|
||||||
|
-- currently nothing to do
|
||||||
|
noGap.verbose = theZone.verbose
|
||||||
|
noGap.enabled = theZone:getBoolFromZoneProperty("onStart", true)
|
||||||
|
noGap.timeOut = theZone:getNumberFromZoneProperty("timeOut", 0) -- default to off
|
||||||
|
if theZone:hasProperty("on?") then
|
||||||
|
noGap.turnOnFlag = theZone:getStringFromZoneProperty("on?", "*<none>")
|
||||||
|
noGap.lastTurnOnFlag = trigger.misc.getUserFlag(noGap.turnOnFlag)
|
||||||
|
end
|
||||||
|
if theZone:hasProperty("off?") then
|
||||||
|
noGap.turnOffFlag = theZone:getStringFromZoneProperty("off?", "*<none>")
|
||||||
|
noGap.lastTurnOffFlag = trigger.misc.getUserFlag(noGap.turnOffFlag)
|
||||||
|
end
|
||||||
|
noGap.triggerMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
|
||||||
|
if noGap.verbose then
|
||||||
|
trigger.action.outText("+++no: config read, verbose = YES", 30)
|
||||||
|
if noGap.enabled then
|
||||||
|
trigger.action.outText("+++noG: enabled", 30)
|
||||||
|
else
|
||||||
|
trigger.action.outText("+++noG: turned off", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- get going
|
||||||
|
--
|
||||||
|
function noGap.start()
|
||||||
|
if not dcsCommon.libCheck("cfx noGap",
|
||||||
|
noGap.requiredLibs)
|
||||||
|
then return false end
|
||||||
|
|
||||||
|
local sgDetect = trigger.misc.getUserFlag("noGapGUI")
|
||||||
|
noGap.isMP = sgDetect > 0
|
||||||
|
|
||||||
|
local theZone = cfxZones.getZoneByName("noGapConfig")
|
||||||
|
if not theZone then
|
||||||
|
theZone = cfxZones.createSimpleZone("noGapConfig")
|
||||||
|
end
|
||||||
|
noGap.readConfigZone(theZone)
|
||||||
|
|
||||||
|
-- collect exclusion zones
|
||||||
|
local pZones = cfxZones.zonesWithProperty("noGap")
|
||||||
|
for k, aZone in pairs(pZones) do
|
||||||
|
noGap.createNoGapZone(aZone)
|
||||||
|
noGap.noGapZones[aZone.name] = aZone
|
||||||
|
end
|
||||||
|
|
||||||
|
-- collect single-player exclusion zones
|
||||||
|
local pZones = cfxZones.zonesWithProperty("noGapSP")
|
||||||
|
for k, aZone in pairs(pZones) do
|
||||||
|
noGap.createNoGapSPZone(aZone)
|
||||||
|
noGap.noGapZones[aZone.name] = aZone
|
||||||
|
end
|
||||||
|
|
||||||
|
-- fill player slots with static objects
|
||||||
|
if noGap.enabled then
|
||||||
|
noGap.fillGaps()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- connect event handler
|
||||||
|
world.addEventHandler(noGap)
|
||||||
|
|
||||||
|
-- start update in 10 seconds
|
||||||
|
timer.scheduleFunction(noGap.update, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
|
-- say hi!
|
||||||
|
local mp = " (SP - <" .. sgDetect .. ">)"
|
||||||
|
if sgDetect > 0 then mp = " -- MP GUI Detected (" .. sgDetect .. ")!" end
|
||||||
|
trigger.action.outText("noGap v" .. noGap.version .. " running" .. mp, 30)
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if not noGap.start() then
|
||||||
|
trigger.action.outText("+++ aborted noGap v" .. noGap.version .. " -- startup failed", 30)
|
||||||
|
noGap = nil
|
||||||
|
end
|
||||||
@ -422,4 +422,3 @@ if not stopGap.start() then
|
|||||||
trigger.action.outText("+++ aborted stopGap v" .. stopGap.version .. " -- startup failed", 30)
|
trigger.action.outText("+++ aborted stopGap v" .. stopGap.version .. " -- startup failed", 30)
|
||||||
stopGap = nil
|
stopGap = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
wiper = {}
|
wiper = {}
|
||||||
wiper.version = "1.1.0"
|
wiper.version = "1.2.0"
|
||||||
wiper.verbose = false
|
wiper.verbose = false
|
||||||
wiper.ups = 1
|
wiper.ups = 1
|
||||||
wiper.requiredLibs = {
|
wiper.requiredLibs = {
|
||||||
@ -11,7 +11,10 @@ wiper.wipers = {}
|
|||||||
Version History
|
Version History
|
||||||
1.0.0 - Initial Version
|
1.0.0 - Initial Version
|
||||||
1.1.0 - added zone bounds check before wiping
|
1.1.0 - added zone bounds check before wiping
|
||||||
|
1.2.0 - OOP dmlZones
|
||||||
|
- categories can now be a list
|
||||||
|
- declutter opetion
|
||||||
|
- if first category is 'none', zone will not wipe at all but may declutter
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
@ -34,30 +37,47 @@ end
|
|||||||
-- read zone
|
-- read zone
|
||||||
--
|
--
|
||||||
function wiper.createWiperWithZone(theZone)
|
function wiper.createWiperWithZone(theZone)
|
||||||
theZone.triggerWiperFlag = cfxZones.getStringFromZoneProperty(theZone, "wipe?", "*<none>")
|
theZone.triggerWiperFlag = theZone:getStringFromZoneProperty("wipe?", "*<none>")
|
||||||
|
|
||||||
-- triggerWiperMethod
|
-- triggerWiperMethod
|
||||||
theZone.triggerWiperMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
|
theZone.triggerWiperMethod = theZone:getStringFromZoneProperty("triggerMethod", "change")
|
||||||
if cfxZones.hasProperty(theZone, "triggerWiperMethod") then
|
if theZone:hasProperty("triggerWiperMethod") then
|
||||||
theZone.triggerWiperMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerWiperMethod", "change")
|
theZone.triggerWiperMethod = theZone:getStringFromZoneProperty("triggerWiperMethod", "change")
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone.triggerWiperFlag then
|
if theZone.triggerWiperFlag then
|
||||||
theZone.lastTriggerWiperValue = cfxZones.getFlagValue(theZone.triggerWiperFlag, theZone)
|
theZone.lastTriggerWiperValue = theZone:getFlagValue(theZone.triggerWiperFlag)
|
||||||
end
|
end
|
||||||
|
|
||||||
local theCat = cfxZones.getStringFromZoneProperty(theZone, "category", "static")
|
local theCat = theZone:getStringFromZoneProperty("category", "none")
|
||||||
if cfxZones.hasProperty(theZone, "wipeCategory") then
|
if theZone:hasProperty("wipeCategory") then
|
||||||
theCat = cfxZones.getStringFromZoneProperty(theZone, "wipeCategory", "static")
|
theCat = theZone:getStringFromZoneProperty("wipeCategory", "none")
|
||||||
end
|
end
|
||||||
if cfxZones.hasProperty(theZone, "wipeCat") then
|
if cfxZones.hasProperty(theZone, "wipeCat") then
|
||||||
theCat = cfxZones.getStringFromZoneProperty(theZone, "wipeCat", "static")
|
theCat = theZone:getStringFromZoneProperty("wipeCat", "none")
|
||||||
end
|
end
|
||||||
|
local allCats = {}
|
||||||
|
if dcsCommon.containsString(theCat, ",") then
|
||||||
|
allCats = dcsCommon.splitString(theCat, ",")
|
||||||
|
allCats = dcsCommon.trimArray(allCats)
|
||||||
|
else
|
||||||
|
allCats = {dcsCommon.trim(theCat)}
|
||||||
|
end
|
||||||
|
-- translate to category for each entry
|
||||||
|
theZone.wipeCategory = {}
|
||||||
|
if allCats[1] == "none" then
|
||||||
|
-- theZone.wipeCategory = {} -- no category to wipe
|
||||||
|
else
|
||||||
|
for idx, aCat in pairs (allCats) do
|
||||||
|
table.insert(theZone.wipeCategory, dcsCommon.string2ObjectCat(aCat))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- theZone.wipeCategory = dcsCommon.string2ObjectCat(theCat)
|
||||||
|
|
||||||
theZone.wipeCategory = dcsCommon.string2ObjectCat(theCat)
|
theZone.declutter = theZone:getBoolFromZoneProperty("declutter", false)
|
||||||
|
|
||||||
if cfxZones.hasProperty(theZone, "wipeNamed") then
|
if theZone:hasProperty("wipeNamed") then
|
||||||
theZone.wipeNamed = cfxZones.getStringFromZoneProperty(theZone, "wipeNamed", "<no name given>")
|
theZone.wipeNamed = theZone:getStringFromZoneProperty("wipeNamed", "<no name given>")
|
||||||
theZone.oWipeNamed = theZone.wipeNamed -- save original
|
theZone.oWipeNamed = theZone.wipeNamed -- save original
|
||||||
-- assemble list of all names to wipe, including wildcard
|
-- assemble list of all names to wipe, including wildcard
|
||||||
local allNames = {}
|
local allNames = {}
|
||||||
@ -78,15 +98,13 @@ function wiper.createWiperWithZone(theZone)
|
|||||||
end
|
end
|
||||||
theDict[shortName] = ew
|
theDict[shortName] = ew
|
||||||
if wiper.verbose or theZone.verbose then
|
if wiper.verbose or theZone.verbose then
|
||||||
trigger.action.outText("+++wpr: dict [".. shortName .."] = " .. dcsCommon.bool2Text(ew),30)
|
trigger.action.outText("+++wpr: dict [".. shortName .."], '*' = " .. dcsCommon.bool2Text(ew) .. " for <" .. theZone:getName() .. ">",30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
theZone.wipeNamed = theDict
|
theZone.wipeNamed = theDict
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
theZone.wipeInventory = cfxZones.getBoolFromZoneProperty(theZone, "wipeInventory", false)
|
theZone.wipeInventory = theZone:getBoolFromZoneProperty("wipeInventory", false)
|
||||||
|
|
||||||
if wiper.verbose or theZone.verbose then
|
if wiper.verbose or theZone.verbose then
|
||||||
trigger.action.outText("+++wpr: new wiper zone <".. theZone.name ..">", 30)
|
trigger.action.outText("+++wpr: new wiper zone <".. theZone.name ..">", 30)
|
||||||
@ -166,11 +184,14 @@ function wiper.isTriggered(theZone)
|
|||||||
}
|
}
|
||||||
-- set up remaining arguments
|
-- set up remaining arguments
|
||||||
local cat = theZone.wipeCategory -- Object.Category.STATIC
|
local cat = theZone.wipeCategory -- Object.Category.STATIC
|
||||||
|
-- WARNING: as of version 1.2.0 cat is now a TABLE!!!
|
||||||
|
-- world.searchObjects supports cat tables according to https://wiki.hoggitworld.com/view/DCS_func_searchObjects
|
||||||
|
|
||||||
|
if #cat > 0 then
|
||||||
-- now call search
|
-- now call search
|
||||||
world.searchObjects(cat, args, wiper.objectHandler, collector)
|
world.searchObjects(cat, args, wiper.objectHandler, collector)
|
||||||
if #collector < 1 and (wiper.verbose or theZone.verbose) then
|
if #collector < 1 and (wiper.verbose or theZone.verbose) then
|
||||||
trigger.action.outText("+++wpr: world search returned zero elements for <" .. theZone.name .. "> (cat=" .. theZone.wipeCategory .. ")",30)
|
trigger.action.outText("+++wpr: world search returned zero elements for <" .. theZone.name .. "> (cat=<" .. dcsCommon.array2string(theZone.wipeCategory) .. ">)",30)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- wipe'em!
|
-- wipe'em!
|
||||||
@ -216,7 +237,19 @@ function wiper.isTriggered(theZone)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
if theZone.verbose or wiper.verbose then
|
||||||
|
trigger.action.outText("+++wpr: <" .. theZone:getName() .. "> has no categories to remove, skipping", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- declutter pass if requested
|
||||||
|
if theZone.declutter then
|
||||||
|
if theZone.verbose or wiper.verbose then
|
||||||
|
trigger.action.outText("+++wpr: decluttering <" .. theZone:getName() .. ">", 30)
|
||||||
|
end
|
||||||
|
theZone:declutterZone()
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
35
server modules/noGapGUI.lua
Normal file
35
server modules/noGapGUI.lua
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
noGapGUI = {}
|
||||||
|
noGapGUI.version = "1.0.0"
|
||||||
|
noGapGUI.fVal = 1 -- tell noGap to remove static
|
||||||
|
noGapGUI.verbose = false
|
||||||
|
--
|
||||||
|
-- Server Plug-In for noGap mission script, only required for server
|
||||||
|
-- Put into (main DCS save folder)/Scripts/Hooks/ and restart DCS
|
||||||
|
--
|
||||||
|
function noGapGUI.onPlayerTryChangeSlot(playerID, side, slotID)
|
||||||
|
if not slotID then return end
|
||||||
|
if slotID == "" then return end
|
||||||
|
if not DCS.isServer() then return end
|
||||||
|
if not DCS.isMultiplayer() then return end
|
||||||
|
|
||||||
|
local uName = DCS.getUnitProperty(slotID, DCS.UNIT_NAME)
|
||||||
|
if not uName then return end
|
||||||
|
local ngName = "NG" .. uName
|
||||||
|
-- tell all clients to remove this unit's static if they are deployed
|
||||||
|
net.dostring_in("server", " trigger.action.setUserFlag(\""..ngName.."\", " .. noGapGUI.fVal .. "); ")
|
||||||
|
if noGapGUI.verbose then
|
||||||
|
net.send_chat("+++NG: readying unit <" .. ngName .. "> for slotting")
|
||||||
|
else
|
||||||
|
net.log("+++noGapGUI: readying unit <" .. ngName .. "> for slotting")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function noGapGUI.onSimulationStart()
|
||||||
|
net.dostring_in("server", " trigger.action.setUserFlag(\"noGapGUI\", 0); ")
|
||||||
|
if not DCS.isServer() then return end
|
||||||
|
if not DCS.isMultiplayer() then return end
|
||||||
|
net.dostring_in("server", " trigger.action.setUserFlag(\"noGapGUI\", 200); ") -- tells client that MP is active
|
||||||
|
end
|
||||||
|
|
||||||
|
DCS.setUserCallbacks(noGapGUI)
|
||||||
|
net.log("noGapGUI v." .. noGapGUI.version .. " started.")
|
||||||
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user