mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 1.3.2
Sitting Ducks PlayerScore improvements Colors for Owned Zones
This commit is contained in:
parent
3d058a12f2
commit
3b6f22ab78
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
|||||||
cfxOwnedZones = {}
|
cfxOwnedZones = {}
|
||||||
cfxOwnedZones.version = "2.0.0"
|
cfxOwnedZones.version = "2.0.1"
|
||||||
cfxOwnedZones.verbose = false
|
cfxOwnedZones.verbose = false
|
||||||
cfxOwnedZones.announcer = true
|
cfxOwnedZones.announcer = true
|
||||||
cfxOwnedZones.name = "cfxOwnedZones"
|
cfxOwnedZones.name = "cfxOwnedZones"
|
||||||
@ -21,6 +21,7 @@ cfxOwnedZones.name = "cfxOwnedZones"
|
|||||||
- heloCap option
|
- heloCap option
|
||||||
- fixWingCap option
|
- fixWingCap option
|
||||||
- filter water owned zones for groundTroops
|
- filter water owned zones for groundTroops
|
||||||
|
2.0.1 - RGBA colors can be entered hex style #ff340799
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
cfxOwnedZones.requiredLibs = {
|
cfxOwnedZones.requiredLibs = {
|
||||||
@ -839,7 +840,5 @@ end
|
|||||||
|
|
||||||
dont count zones that cant be conquered for allBlue/allRed
|
dont count zones that cant be conquered for allBlue/allRed
|
||||||
|
|
||||||
define color with #FF008080
|
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxPlayerScore = {}
|
cfxPlayerScore = {}
|
||||||
cfxPlayerScore.version = "2.0.1"
|
cfxPlayerScore.version = "2.1.1"
|
||||||
cfxPlayerScore.name = "cfxPlayerScore" -- compatibility with flag bangers
|
cfxPlayerScore.name = "cfxPlayerScore" -- compatibility with flag bangers
|
||||||
cfxPlayerScore.badSound = "Death BRASS.wav"
|
cfxPlayerScore.badSound = "Death BRASS.wav"
|
||||||
cfxPlayerScore.scoreSound = "Quest Snare 3.wav"
|
cfxPlayerScore.scoreSound = "Quest Snare 3.wav"
|
||||||
@ -72,6 +72,14 @@ cfxPlayerScore.firstSave = true -- to force overwrite
|
|||||||
- immediate awarding of all negative scores, even if deferred
|
- immediate awarding of all negative scores, even if deferred
|
||||||
2.0.1 - corrected access to nowString()
|
2.0.1 - corrected access to nowString()
|
||||||
- more robust config reading
|
- more robust config reading
|
||||||
|
2.1.0 - coalition score
|
||||||
|
- reportCoalition switch
|
||||||
|
- persist coalition score
|
||||||
|
- add score to coalition when scoring player
|
||||||
|
2.1.1 - check ownership of scoreSafe zone upon touch-down
|
||||||
|
- new scoreSummaryForPlayersOfCoalition()
|
||||||
|
- new noGrief option in config
|
||||||
|
- improved guards when checking ownership (nil zone owner)
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
@ -79,14 +87,16 @@ cfxPlayerScore.requiredLibs = {
|
|||||||
"dcsCommon", -- this is doing score keeping
|
"dcsCommon", -- this is doing score keeping
|
||||||
"cfxZones", -- zones for config
|
"cfxZones", -- zones for config
|
||||||
}
|
}
|
||||||
cfxPlayerScore.playerScore = {} -- init to empty
|
cfxPlayerScore.playerScore = {} -- indexed by playerName
|
||||||
|
cfxPlayerScore.coalitionScore = {} -- score per coalition
|
||||||
|
cfxPlayerScore.coalitionScore[1] = 0 -- init red
|
||||||
|
cfxPlayerScore.coalitionScore[2] = 0 -- init blue
|
||||||
cfxPlayerScore.deferred = false -- on deferred, we only award after landing, and erase on any form of re-slot
|
cfxPlayerScore.deferred = false -- on deferred, we only award after landing, and erase on any form of re-slot
|
||||||
cfxPlayerScore.delayAfterLanding = 10 -- seconds after landing
|
cfxPlayerScore.delayAfterLanding = 10 -- seconds after landing
|
||||||
cfxPlayerScore.safeZones = {} -- safe zones to land in
|
cfxPlayerScore.safeZones = {} -- safe zones to land in
|
||||||
cfxPlayerScore.featZones = {} -- zones that define feats
|
cfxPlayerScore.featZones = {} -- zones that define feats
|
||||||
cfxPlayerScore.killZones = {} -- when set, kills only count here
|
cfxPlayerScore.killZones = {} -- when set, kills only count here
|
||||||
|
|
||||||
|
|
||||||
-- typeScore: dictionary sorted by typeString for score
|
-- typeScore: dictionary sorted by typeString for score
|
||||||
-- extend to add more types. It is used by unitType2score to
|
-- extend to add more types. It is used by unitType2score to
|
||||||
-- determine the base unit score
|
-- determine the base unit score
|
||||||
@ -107,7 +117,6 @@ cfxPlayerScore.train = 5
|
|||||||
cfxPlayerScore.landing = 0 -- if > 0 it scores as feat
|
cfxPlayerScore.landing = 0 -- if > 0 it scores as feat
|
||||||
|
|
||||||
cfxPlayerScore.unit2player = {} -- lookup and reverse look-up
|
cfxPlayerScore.unit2player = {} -- lookup and reverse look-up
|
||||||
--cfxPlayerScore.player2unit = {} -- to detect death and destruction
|
|
||||||
|
|
||||||
function cfxPlayerScore.addSafeZone(theZone)
|
function cfxPlayerScore.addSafeZone(theZone)
|
||||||
theZone.scoreSafe = cfxZones.getCoalitionFromZoneProperty(theZone, "scoreSafe", 0)
|
theZone.scoreSafe = cfxZones.getCoalitionFromZoneProperty(theZone, "scoreSafe", 0)
|
||||||
@ -154,29 +163,25 @@ function cfxPlayerScore.featsForLocation(name, loc, coa, featType, killer, victi
|
|||||||
-- and location of victim for kill
|
-- and location of victim for kill
|
||||||
-- coa is coalition of landing unit
|
-- coa is coalition of landing unit
|
||||||
-- and coalition of killer for kill
|
-- and coalition of killer for kill
|
||||||
-- trigger.action.outText("enter feat check for <" .. featType .. ">", 30)
|
|
||||||
if not coa then coa = 0 end
|
if not coa then coa = 0 end
|
||||||
if not featType then featType = "KILL" end
|
if not featType then featType = "KILL" end
|
||||||
featType = string.upper(featType)
|
featType = string.upper(featType)
|
||||||
local theFeats = {}
|
local theFeats = {}
|
||||||
for idx, theZone in pairs(cfxPlayerScore.featZones) do
|
for idx, theZone in pairs(cfxPlayerScore.featZones) do
|
||||||
-- trigger.action.outText("featcheck: <" .. theZone.name .. ">", 30)
|
|
||||||
local canAward = true
|
local canAward = true
|
||||||
|
|
||||||
-- check if it can be awarded
|
-- check if it can be awarded
|
||||||
if theZone.featNum == 0 then
|
if theZone.featNum == 0 then
|
||||||
canAward = false
|
canAward = false
|
||||||
-- trigger.action.outText(" - failed featNum", 30)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone.featType ~= featType then
|
if theZone.featType ~= featType then
|
||||||
canAward = false
|
canAward = false
|
||||||
--trigger.action.outText(" - failed type check (look for <" .. featType .. ">, got <" .. theZone.featType .. ">", 30)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if not (theZone.coalition == 0 or theZone.coalition == coa) then
|
if not (theZone.coalition == 0 or theZone.coalition == coa) then
|
||||||
canAward = false
|
canAward = false
|
||||||
-- trigger.action.outText(" - failed coa check ", 30)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if featType == "PVP" then
|
if featType == "PVP" then
|
||||||
@ -191,21 +196,17 @@ function cfxPlayerScore.featsForLocation(name, loc, coa, featType, killer, victi
|
|||||||
|
|
||||||
if not cfxZones.pointInZone(loc, theZone) then
|
if not cfxZones.pointInZone(loc, theZone) then
|
||||||
canAward = false
|
canAward = false
|
||||||
-- trigger.action.outText(" - failed loc check ", 30)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if theZone.ppOnce then
|
if theZone.ppOnce then
|
||||||
if theZone.awardedTo[name] then
|
if theZone.awardedTo[name] then
|
||||||
canAward = false
|
canAward = false
|
||||||
--trigger.action.outText(" - already awarded fail ", 30)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if canAward then
|
if canAward then
|
||||||
table.insert(theFeats, theZone) -- jupp, add it
|
table.insert(theFeats, theZone) -- jupp, add it
|
||||||
--trigger.action.outText(" can award", 30)
|
|
||||||
else
|
else
|
||||||
--trigger.action.outText("FAIL.", 30)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -240,7 +241,6 @@ function cfxPlayerScore.preprocessWildcards(inMsg, aUnit, aVictim)
|
|||||||
theMsg = theMsg:gsub("<type>", aVictim:getTypeName())
|
theMsg = theMsg:gsub("<type>", aVictim:getTypeName())
|
||||||
-- victim may not have group. guard against that
|
-- victim may not have group. guard against that
|
||||||
-- happens if unit 'cooks off'
|
-- happens if unit 'cooks off'
|
||||||
--local gName = "(unknown)"
|
|
||||||
local aGroup = nil
|
local aGroup = nil
|
||||||
if aVictim.getGroup then
|
if aVictim.getGroup then
|
||||||
aVictim:getGroup()
|
aVictim:getGroup()
|
||||||
@ -290,9 +290,8 @@ function cfxPlayerScore.object2score(inVictim) -- does not have group
|
|||||||
inName = tostring(inName)
|
inName = tostring(inName)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- now, since 2.7x DCS turns units into static objects for
|
-- since 2.7x DCS turns units into static objects for
|
||||||
-- cooking off, so first thing we need to do is do a name check
|
-- cooking off, so first thing we need to do is do a name check
|
||||||
|
|
||||||
local objectScore = cfxPlayerScore.typeScore[inName]
|
local objectScore = cfxPlayerScore.typeScore[inName]
|
||||||
if not objectScore then
|
if not objectScore then
|
||||||
-- try the type desc
|
-- try the type desc
|
||||||
@ -384,6 +383,20 @@ function cfxPlayerScore.updateScoreForPlayerImmediate(playerName, score)
|
|||||||
local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)
|
local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)
|
||||||
thePlayerScore.score = thePlayerScore.score + score
|
thePlayerScore.score = thePlayerScore.score + score
|
||||||
cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)
|
cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)
|
||||||
|
-- if coalitionScore is active, trace player back to their current
|
||||||
|
-- coalition and add points to that coalition if positive
|
||||||
|
-- or always if noGrief is true
|
||||||
|
local pFaction = dcsCommon.playerName2Coalition(playerName)
|
||||||
|
if cfxPlayerScore.noGrief then
|
||||||
|
-- only on positive score
|
||||||
|
if (score > 0) and pFaction > 0 then
|
||||||
|
cfxPlayerScore.coalitionScore[pFaction] = cfxPlayerScore.coalitionScore[pFaction] + score
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if pFaction > 0 then
|
||||||
|
cfxPlayerScore.coalitionScore[pFaction] = cfxPlayerScore.coalitionScore[pFaction] + score
|
||||||
|
end
|
||||||
|
end
|
||||||
return thePlayerScore.score
|
return thePlayerScore.score
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -395,10 +408,6 @@ function cfxPlayerScore.updateScoreForPlayer(playerName, score)
|
|||||||
cfxPlayerScore.setPlayerScore(playerName, thePlayerScore) -- write-through. why? because it may be a new entry.
|
cfxPlayerScore.setPlayerScore(playerName, thePlayerScore) -- write-through. why? because it may be a new entry.
|
||||||
return thePlayerScore.score -- this is the old score!!!
|
return thePlayerScore.score -- this is the old score!!!
|
||||||
end
|
end
|
||||||
--local thePlayerScore = cfxPlayerScore.getPlayerScore(playerName)
|
|
||||||
--thePlayerScore.score = thePlayerScore.score + score
|
|
||||||
--cfxPlayerScore.setPlayerScore(playerName, thePlayerScore)
|
|
||||||
--return thePlayerScore.score
|
|
||||||
-- now write immediately
|
-- now write immediately
|
||||||
return cfxPlayerScore.updateScoreForPlayerImmediate(playerName, score)
|
return cfxPlayerScore.updateScoreForPlayerImmediate(playerName, score)
|
||||||
end
|
end
|
||||||
@ -524,13 +533,34 @@ function cfxPlayerScore.scoreTextForPlayerNamed(playerName)
|
|||||||
return cfxPlayerScore.playerScore2text(thePlayerScore)
|
return cfxPlayerScore.playerScore2text(thePlayerScore)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function cfxPlayerScore.scoreSummaryForPlayersOfCoalition(side)
|
||||||
|
-- only list players who are in the coalition RIGHT NOW
|
||||||
|
-- only list their score
|
||||||
|
if not side then side = -1 end
|
||||||
|
local desc = "\nCurrent score for players in " .. dcsCommon.coalition2Text(side) .." coalition:\n"
|
||||||
|
local count = 0
|
||||||
|
for pName, pScore in pairs(cfxPlayerScore.playerScore) do
|
||||||
|
local coa = dcsCommon.playerName2Coalition(pName)
|
||||||
|
if coa == side then
|
||||||
|
desc = desc .. pName ..": " .. pScore.score .. "\n"
|
||||||
|
count = count + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if count < 1 then
|
||||||
|
desc = desc .. " (No score yet)"
|
||||||
|
end
|
||||||
|
|
||||||
|
desc = desc .. "\n"
|
||||||
|
return desc
|
||||||
|
end
|
||||||
|
|
||||||
function cfxPlayerScore.scoreTextForAllPlayers(ranked)
|
function cfxPlayerScore.scoreTextForAllPlayers(ranked)
|
||||||
if not ranked then ranked = false end
|
if not ranked then ranked = false end
|
||||||
local theText = ""
|
local theText = ""
|
||||||
local isFirst = true
|
local isFirst = true
|
||||||
local theScores = cfxPlayerScore.playerScore
|
local theScores = cfxPlayerScore.playerScore
|
||||||
if cfxPlayerScore.verbose then
|
if cfxPlayerScore.verbose then
|
||||||
trigger.action.outText("+++pScr: Saving score - <" .. dcsCommon.getSizeOfTable(theScores) .. "> entries.", 30)
|
trigger.action.outText("+++pScr: Generating score - <" .. dcsCommon.getSizeOfTable(theScores) .. "> entries.", 30)
|
||||||
end
|
end
|
||||||
if ranked then
|
if ranked then
|
||||||
table.sort(theScores, function(left, right) return left.score < right.score end )
|
table.sort(theScores, function(left, right) return left.score < right.score end )
|
||||||
@ -548,6 +578,17 @@ function cfxPlayerScore.scoreTextForAllPlayers(ranked)
|
|||||||
isFirst = false
|
isFirst = false
|
||||||
rank = rank + 1
|
rank = rank + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if dcsCommon.getSizeOfTable(theScores) < 1 then
|
||||||
|
theText = theText .. " (No score yet)\n"
|
||||||
|
end
|
||||||
|
|
||||||
|
if cfxPlayerScore.reportCoalition then
|
||||||
|
--theText = theText .. "\n"
|
||||||
|
theText = theText .. "\nRED total: " .. cfxPlayerScore.coalitionScore[1]
|
||||||
|
theText = theText .. "\nBLUE total: " .. cfxPlayerScore.coalitionScore[2]
|
||||||
|
end
|
||||||
|
|
||||||
return theText
|
return theText
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -585,6 +626,10 @@ function cfxPlayerScore.awardScoreTo(killSide, theScore, killerName)
|
|||||||
trigger.action.outTextForCoalition(killSide, "Killscore: " .. theScore .. ", now " .. thePlayerRecord.scoreaccu .. " waiting for " .. killerName .. ", awarded after landing", 30)
|
trigger.action.outTextForCoalition(killSide, "Killscore: " .. theScore .. ", now " .. thePlayerRecord.scoreaccu .. " waiting for " .. killerName .. ", awarded after landing", 30)
|
||||||
else -- negative score or not deferred
|
else -- negative score or not deferred
|
||||||
trigger.action.outTextForCoalition(killSide, "Killscore: " .. theScore .. " for a total of " .. playerScore .. " for " .. killerName, 30)
|
trigger.action.outTextForCoalition(killSide, "Killscore: " .. theScore .. " for a total of " .. playerScore .. " for " .. killerName, 30)
|
||||||
|
|
||||||
|
if cfxPlayerScore.reportCoalition then
|
||||||
|
trigger.action.outTextForCoalition(killSide, "\nCoalition Total: " .. cfxPlayerScore.coalitionScore[killSide], 30)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -937,20 +982,6 @@ function cfxPlayerScore.handlePlayerLanding(theEvent)
|
|||||||
-- only continue if there is anything to award
|
-- only continue if there is anything to award
|
||||||
local killSize = dcsCommon.getSizeOfTable(theScore.killQueue)
|
local killSize = dcsCommon.getSizeOfTable(theScore.killQueue)
|
||||||
local featSize = dcsCommon.getSizeOfTable(theScore.featQueue)
|
local featSize = dcsCommon.getSizeOfTable(theScore.featQueue)
|
||||||
--trigger.action.outText("+++pScr: kS = <" .. killSize .. ">, fS = <" .. featSize .. ">, Accu = <" .. theScore.scoreaccu .. ">", 30)
|
|
||||||
|
|
||||||
-- to avoid possible race conditions with other modules that
|
|
||||||
-- trigger on landing, we always schedule the check in 10 seconds
|
|
||||||
--[[--
|
|
||||||
if killSize < 1 and
|
|
||||||
featSize < 1 and
|
|
||||||
theScore.scoreaccu < 1 then
|
|
||||||
if cfxPlayerScore.verbose then
|
|
||||||
trigger.action.outText("+++pScr: deferred and nothing to award after touchdown to <" .. playerName .. ">, returning", 30)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
--]]--
|
|
||||||
|
|
||||||
if cfxPlayerScore.verbose then
|
if cfxPlayerScore.verbose then
|
||||||
trigger.action.outText("+++pScr: prepping deferred score for <" .. playerName ..">", 30)
|
trigger.action.outText("+++pScr: prepping deferred score for <" .. playerName ..">", 30)
|
||||||
@ -964,8 +995,16 @@ function cfxPlayerScore.handlePlayerLanding(theEvent)
|
|||||||
local isSafe = false
|
local isSafe = false
|
||||||
for idx, theZone in pairs(cfxPlayerScore.safeZones) do
|
for idx, theZone in pairs(cfxPlayerScore.safeZones) do
|
||||||
if theZone.scoreSafe == 0 or theZone.scoreSafe == coa then
|
if theZone.scoreSafe == 0 or theZone.scoreSafe == coa then
|
||||||
if cfxZones.pointInZone(loc, theZone) then
|
-- make sure that this zone doesn't belong to the
|
||||||
isSafe = true
|
-- wrong faction (if owned zone)
|
||||||
|
if (theZone.owner == coa) or (theZone.owner == 0) or (theZone.owner == nil) then
|
||||||
|
if cfxZones.pointInZone(loc, theZone) then
|
||||||
|
isSafe = true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if cfxPlayerScore.verbose then
|
||||||
|
trigger.action.outText("+++pSc: Zone <" .. theZone.name .. ">: owner=<" .. theZone.owner .. ">, my coa=<" .. coa .. ">, no owner match")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -1015,6 +1054,7 @@ function cfxPlayerScore.scheduledAward(args)
|
|||||||
local isSafe = false
|
local isSafe = false
|
||||||
for idx, theZone in pairs(cfxPlayerScore.safeZones) do
|
for idx, theZone in pairs(cfxPlayerScore.safeZones) do
|
||||||
if theZone.scoreSafe == 0 or theZone.scoreSafe == coa then
|
if theZone.scoreSafe == 0 or theZone.scoreSafe == coa then
|
||||||
|
-- we no longer check ownership of zone, we did that when we landed
|
||||||
if cfxZones.pointInZone(loc, theZone) then
|
if cfxZones.pointInZone(loc, theZone) then
|
||||||
isSafe = true
|
isSafe = true
|
||||||
end
|
end
|
||||||
@ -1028,6 +1068,11 @@ function cfxPlayerScore.scheduledAward(args)
|
|||||||
|
|
||||||
|
|
||||||
local theScore = cfxPlayerScore.getPlayerScore(playerName)
|
local theScore = cfxPlayerScore.getPlayerScore(playerName)
|
||||||
|
local playerSide = dcsCommon.playerName2Coalition(playerName)
|
||||||
|
if playerSide < 1 then
|
||||||
|
trigger.action.outText("+++pScr: WARNING - unaffiliated player <" .. playerName .. ">, score award ignored", 30)
|
||||||
|
return
|
||||||
|
end
|
||||||
if dcsCommon.getSizeOfTable(theScore.killQueue) < 1 and
|
if dcsCommon.getSizeOfTable(theScore.killQueue) < 1 and
|
||||||
dcsCommon.getSizeOfTable(theScore.featQueue) < 1 and
|
dcsCommon.getSizeOfTable(theScore.featQueue) < 1 and
|
||||||
theScore.scoreaccu < 1 then
|
theScore.scoreaccu < 1 then
|
||||||
@ -1042,9 +1087,10 @@ function cfxPlayerScore.scheduledAward(args)
|
|||||||
-- when we get here we award all scores, kills, and feats
|
-- when we get here we award all scores, kills, and feats
|
||||||
local desc = "\nPlayer " .. playerName .. " is awarded:\n"
|
local desc = "\nPlayer " .. playerName .. " is awarded:\n"
|
||||||
-- score and total score
|
-- score and total score
|
||||||
if theScore.scoreaccu > 0 then
|
if theScore.scoreaccu > 0 then -- remember: negatives are immediate
|
||||||
theScore.score = theScore.score + theScore.scoreaccu
|
theScore.score = theScore.score + theScore.scoreaccu
|
||||||
desc = desc .. " score: " .. theScore.scoreaccu .. " for a new total of " .. theScore.score .. "\n"
|
desc = desc .. " score: " .. theScore.scoreaccu .. " for a new total of " .. theScore.score .. "\n"
|
||||||
|
cfxPlayerScore.coalitionScore[playerSide] = cfxPlayerScore.coalitionScore[playerSide] + theScore.scoreaccu
|
||||||
theScore.scoreaccu = 0
|
theScore.scoreaccu = 0
|
||||||
hasAward = true
|
hasAward = true
|
||||||
end
|
end
|
||||||
@ -1074,6 +1120,10 @@ function cfxPlayerScore.scheduledAward(args)
|
|||||||
end
|
end
|
||||||
theScore.featQueue = {}
|
theScore.featQueue = {}
|
||||||
|
|
||||||
|
if cfxPlayerScore.reportCoalition then
|
||||||
|
desc = desc .. "\nCoalition Total: " .. cfxPlayerScore.coalitionScore[playerSide]
|
||||||
|
end
|
||||||
|
|
||||||
-- output score
|
-- output score
|
||||||
desc = desc .. "\n"
|
desc = desc .. "\n"
|
||||||
if hasAward then
|
if hasAward then
|
||||||
@ -1129,7 +1179,8 @@ function cfxPlayerScore.handlePlayerEvent(theEvent)
|
|||||||
local playerName = thePlayerUnit:getPlayerName()
|
local playerName = thePlayerUnit:getPlayerName()
|
||||||
local theScore = cfxPlayerScore.getPlayerScore(playerName)
|
local theScore = cfxPlayerScore.getPlayerScore(playerName)
|
||||||
-- now re-init feat and score queues
|
-- now re-init feat and score queues
|
||||||
if theScore.scoreaccu > 0 then
|
|
||||||
|
if theScore.scoreaccu and theScore.scoreaccu > 0 then
|
||||||
trigger.action.outTextForCoalition(playerSide, "Player " .. playerName .. ", score of <" .. theScore.scoreaccu .. "> points discarded.", 30)
|
trigger.action.outTextForCoalition(playerSide, "Player " .. playerName .. ", score of <" .. theScore.scoreaccu .. "> points discarded.", 30)
|
||||||
end
|
end
|
||||||
theScore.scoreaccu = 0
|
theScore.scoreaccu = 0
|
||||||
@ -1209,6 +1260,11 @@ function cfxPlayerScore.readConfigZone(theZone)
|
|||||||
cfxPlayerScore.reportScore = cfxZones.getBoolFromZoneProperty(theZone, "reportScore", true)
|
cfxPlayerScore.reportScore = cfxZones.getBoolFromZoneProperty(theZone, "reportScore", true)
|
||||||
|
|
||||||
cfxPlayerScore.reportFeats = cfxZones.getBoolFromZoneProperty(theZone, "reportFeats", true)
|
cfxPlayerScore.reportFeats = cfxZones.getBoolFromZoneProperty(theZone, "reportFeats", true)
|
||||||
|
|
||||||
|
cfxPlayerScore.reportCoalition = cfxZones.getBoolFromZoneProperty(
|
||||||
|
theZone, "reportCoalition", false) -- also show coalition score
|
||||||
|
|
||||||
|
cfxPlayerScore.noGrief = cfxZones.getBoolFromZoneProperty(theZone, "noGrief", true) -- noGrief = only add positive score
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -1220,6 +1276,7 @@ function cfxPlayerScore.saveData()
|
|||||||
local theScore = dcsCommon.clone(cfxPlayerScore.playerScore)
|
local theScore = dcsCommon.clone(cfxPlayerScore.playerScore)
|
||||||
theData.theScore = theScore
|
theData.theScore = theScore
|
||||||
-- build feat zone list
|
-- build feat zone list
|
||||||
|
theData.coalitionScore = dcsCommon.clone(cfxPlayerScore.coalitionScore)
|
||||||
local featZones = {}
|
local featZones = {}
|
||||||
for idx, theZone in pairs(cfxPlayerScore.featZones) do
|
for idx, theZone in pairs(cfxPlayerScore.featZones) do
|
||||||
local theFeat = {}
|
local theFeat = {}
|
||||||
@ -1243,6 +1300,9 @@ function cfxPlayerScore.loadData()
|
|||||||
|
|
||||||
local theScore = theData.theScore
|
local theScore = theData.theScore
|
||||||
cfxPlayerScore.playerScore = theScore
|
cfxPlayerScore.playerScore = theScore
|
||||||
|
if theData.coalitionScore then
|
||||||
|
cfxPlayerScore.coalitionScore = theData.coalitionScore
|
||||||
|
end
|
||||||
local featData = theData.featData
|
local featData = theData.featData
|
||||||
if featData then
|
if featData then
|
||||||
for name, data in pairs(featData) do
|
for name, data in pairs(featData) do
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxPlayerScoreUI = {}
|
cfxPlayerScoreUI = {}
|
||||||
cfxPlayerScoreUI.version = "2.0.1"
|
cfxPlayerScoreUI.version = "2.1.0"
|
||||||
cfxPlayerScoreUI.verbose = false
|
cfxPlayerScoreUI.verbose = false
|
||||||
|
|
||||||
--[[-- VERSION HISTORY
|
--[[-- VERSION HISTORY
|
||||||
@ -7,11 +7,22 @@ cfxPlayerScoreUI.verbose = false
|
|||||||
- 1.0.3 - module check
|
- 1.0.3 - module check
|
||||||
- 2.0.0 - removed cfxPlayer dependency, handles own commands
|
- 2.0.0 - removed cfxPlayer dependency, handles own commands
|
||||||
- 2.0.1 - late start capability
|
- 2.0.1 - late start capability
|
||||||
|
- 2.1.0 - soundfile cleanup
|
||||||
|
- score summary for side
|
||||||
|
- allowAll
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
cfxPlayerScoreUI.requiredLibs = {
|
||||||
|
"dcsCommon", -- this is doing score keeping
|
||||||
|
"cfxZones", -- zones for config
|
||||||
|
"cfxPlayerScore",
|
||||||
|
}
|
||||||
|
cfxPlayerScoreUI.soundFile = "Quest Snare 3.wav"
|
||||||
cfxPlayerScoreUI.rootCommands = {} -- by unit's GROUP name, for player aircraft
|
cfxPlayerScoreUI.rootCommands = {} -- by unit's GROUP name, for player aircraft
|
||||||
|
cfxPlayerScoreUI.allowAll = true
|
||||||
|
cfxPlayerScoreUI.ranked = true
|
||||||
|
|
||||||
-- redirect: avoid the debug environ of missionCommand
|
-- redirect: avoid the debug environ of missionCommands
|
||||||
function cfxPlayerScoreUI.redirectCommandX(args)
|
function cfxPlayerScoreUI.redirectCommandX(args)
|
||||||
timer.scheduleFunction(cfxPlayerScoreUI.doCommandX, args, timer.getTime() + 0.1)
|
timer.scheduleFunction(cfxPlayerScoreUI.doCommandX, args, timer.getTime() + 0.1)
|
||||||
end
|
end
|
||||||
@ -22,14 +33,24 @@ function cfxPlayerScoreUI.doCommandX(args)
|
|||||||
local what = args[3] -- "score" or other commands
|
local what = args[3] -- "score" or other commands
|
||||||
local theGroup = Group.getByName(groupName)
|
local theGroup = Group.getByName(groupName)
|
||||||
local gid = theGroup:getID()
|
local gid = theGroup:getID()
|
||||||
|
local coa = theGroup:getCoalition()
|
||||||
|
|
||||||
if not cfxPlayerScore.scoreTextForPlayerNamed then
|
if not cfxPlayerScore.scoreTextForPlayerNamed then
|
||||||
trigger.action.outText("***pSGUI: CANNOT FIND PlayerScore MODULE", 30)
|
trigger.action.outText("***pSGUI: CANNOT FIND PlayerScore MODULE", 30)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local desc = cfxPlayerScore.scoreTextForPlayerNamed(playerName)
|
local desc = ""
|
||||||
|
if what == "score" then
|
||||||
|
desc = cfxPlayerScore.scoreTextForPlayerNamed(playerName)
|
||||||
|
elseif what == "allMySide" then
|
||||||
|
desc = cfxPlayerScore.scoreSummaryForPlayersOfCoalition(coa)
|
||||||
|
elseif what == "all" then
|
||||||
|
desc = "Score Table For All Players:\n" .. cfxPlayerScore.scoreTextForAllPlayers(cfxPlayerScoreUI.ranked)
|
||||||
|
else
|
||||||
|
desc = "PlayerScore UI: unknown command <" .. what .. ">"
|
||||||
|
end
|
||||||
trigger.action.outTextForGroup(gid, desc, 30)
|
trigger.action.outTextForGroup(gid, desc, 30)
|
||||||
trigger.action.outSoundForGroup(gid, "Quest Snare 3.wav")
|
trigger.action.outSoundForGroup(gid, cfxPlayerScoreUI.soundFile)
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
@ -59,8 +80,18 @@ function cfxPlayerScore.processPlayerUnit(theUnit)
|
|||||||
-- we need to install a group menu item for scores.
|
-- we need to install a group menu item for scores.
|
||||||
-- will persist through death
|
-- will persist through death
|
||||||
local commandTxt = "Show Score / Kills"
|
local commandTxt = "Show Score / Kills"
|
||||||
local theCommand = missionCommands.addCommandForGroup(gid, commandTxt, nil, cfxPlayerScoreUI.redirectCommandX, {groupName, playerName, "score"} )
|
local theMenu = missionCommands.addSubMenuForGroup(gid, "Show Score", nil)
|
||||||
cfxPlayerScoreUI.rootCommands[groupName] = theCommand
|
local theCommand = missionCommands.addCommandForGroup(gid, commandTxt, theMenu, cfxPlayerScoreUI.redirectCommandX, {groupName, playerName, "score"})
|
||||||
|
|
||||||
|
commandTxt = "Show my Side Score / Kills"
|
||||||
|
theCommand = missionCommands.addCommandForGroup(gid, commandTxt, theMenu, cfxPlayerScoreUI.redirectCommandX, {groupName, playerName, "allMySide"})
|
||||||
|
|
||||||
|
if cfxPlayerScoreUI.allowAll then
|
||||||
|
commandTxt = "Show All Player Scores"
|
||||||
|
theCommand = missionCommands.addCommandForGroup(gid, commandTxt, theMenu, cfxPlayerScoreUI.redirectCommandX, {groupName, playerName, "all"})
|
||||||
|
end
|
||||||
|
|
||||||
|
cfxPlayerScoreUI.rootCommands[groupName] = theMenu
|
||||||
|
|
||||||
if cfxPlayerScoreUI.verbose then
|
if cfxPlayerScoreUI.verbose then
|
||||||
trigger.action.outText("++pSGui: installed player score menu for group <" .. groupName .. ">", 30)
|
trigger.action.outText("++pSGui: installed player score menu for group <" .. groupName .. ">", 30)
|
||||||
@ -78,6 +109,9 @@ end
|
|||||||
-- Start
|
-- Start
|
||||||
--
|
--
|
||||||
function cfxPlayerScoreUI.start()
|
function cfxPlayerScoreUI.start()
|
||||||
|
if not dcsCommon.libCheck("cfx Player Score UI",
|
||||||
|
cfxPlayerScoreUI.requiredLibs)
|
||||||
|
then return false end
|
||||||
-- install the event handler for new player planes
|
-- install the event handler for new player planes
|
||||||
world.addEventHandler(cfxPlayerScoreUI)
|
world.addEventHandler(cfxPlayerScoreUI)
|
||||||
-- process all existing players (late start)
|
-- process all existing players (late start)
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxZones = {}
|
cfxZones = {}
|
||||||
cfxZones.version = "3.1.0"
|
cfxZones.version = "3.1.1"
|
||||||
|
|
||||||
-- 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
|
||||||
@ -129,6 +129,8 @@ cfxZones.version = "3.1.0"
|
|||||||
- 3.0.9 - new getFlareColorStringFromZoneProperty()
|
- 3.0.9 - new getFlareColorStringFromZoneProperty()
|
||||||
- 3.1.0 - new getRGBVectorFromZoneProperty()
|
- 3.1.0 - new getRGBVectorFromZoneProperty()
|
||||||
new getRGBAVectorFromZoneProperty()
|
new getRGBAVectorFromZoneProperty()
|
||||||
|
- 3.1.1 - getRGBAVectorFromZoneProperty now supports #RRGGBBAA and #RRGGBB format
|
||||||
|
- owner for all, default 0
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
cfxZones.verbose = false
|
cfxZones.verbose = false
|
||||||
@ -2245,6 +2247,13 @@ function cfxZones.getRGBAVectorFromZoneProperty(theZone, theProperty, defaultVal
|
|||||||
if not defaultVal then defaultVal = {1.0, 1.0, 1.0, 1.0} end
|
if not defaultVal then defaultVal = {1.0, 1.0, 1.0, 1.0} end
|
||||||
if #defaultVal ~=4 then defaultVal = {1.0, 1.0, 1.0, 1.0} end
|
if #defaultVal ~=4 then defaultVal = {1.0, 1.0, 1.0, 1.0} end
|
||||||
local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, "")
|
local s = cfxZones.getStringFromZoneProperty(theZone, theProperty, "")
|
||||||
|
s = dcsCommon.trim(s)
|
||||||
|
if s:sub(1,1) == "#" then
|
||||||
|
-- it's probably a "#RRGGBBAA" format hex string
|
||||||
|
local hVec = dcsCommon.hexString2RGBA(s)
|
||||||
|
if hVec then return hVec end
|
||||||
|
end
|
||||||
|
|
||||||
local sVec = dcsCommon.splitString(s, ",")
|
local sVec = dcsCommon.splitString(s, ",")
|
||||||
local nVec = {}
|
local nVec = {}
|
||||||
for i = 1, 4 do
|
for i = 1, 4 do
|
||||||
@ -2841,8 +2850,10 @@ function cfxZones.init()
|
|||||||
cfxZones.readFromDCS(true) -- true: erase old
|
cfxZones.readFromDCS(true) -- true: erase old
|
||||||
|
|
||||||
-- pre-read zone owner for all zones
|
-- pre-read zone owner for all zones
|
||||||
local pZones = cfxZones.zonesWithProperty("owner")
|
-- much like verbose, all zones have owner
|
||||||
for n, aZone in pairs(pZones) do
|
-- local pZones = cfxZones.zonesWithProperty("owner")
|
||||||
|
-- for n, aZone in pairs(pZones) do
|
||||||
|
for n, aZone in pairs(cfxZones.zones) do
|
||||||
aZone.owner = cfxZones.getCoalitionFromZoneProperty(aZone, "owner", 0)
|
aZone.owner = cfxZones.getCoalitionFromZoneProperty(aZone, "owner", 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
dcsCommon = {}
|
dcsCommon = {}
|
||||||
dcsCommon.version = "2.8.7"
|
dcsCommon.version = "2.8.8"
|
||||||
--[[-- VERSION HISTORY
|
--[[-- VERSION HISTORY
|
||||||
2.2.6 - compassPositionOfARelativeToB
|
2.2.6 - compassPositionOfARelativeToB
|
||||||
- clockPositionOfARelativeToB
|
- clockPositionOfARelativeToB
|
||||||
@ -150,7 +150,9 @@ dcsCommon.version = "2.8.7"
|
|||||||
2.8.7 - new flareColor2Num()
|
2.8.7 - new flareColor2Num()
|
||||||
- new flareColor2Text()
|
- new flareColor2Text()
|
||||||
- new iteratePlayers()
|
- new iteratePlayers()
|
||||||
|
2.8.8 - new hexString2RGBA()
|
||||||
|
- new playerName2Coalition()
|
||||||
|
- new coalition2Text()
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
-- dcsCommon is a library of common lua functions
|
-- dcsCommon is a library of common lua functions
|
||||||
@ -2955,6 +2957,14 @@ function dcsCommon.coalition2county(inCoalition)
|
|||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function dcsCommon.coalition2Text(coa)
|
||||||
|
if not coa then return "!nil!" end
|
||||||
|
if coa == 0 then return "NEUTRAL" end
|
||||||
|
if coa == 1 then return "RED" end
|
||||||
|
if coa == 2 then return "BLUE" end
|
||||||
|
return "?UNKNOWN?"
|
||||||
|
end
|
||||||
|
|
||||||
function dcsCommon.latLon2Text(lat, lon)
|
function dcsCommon.latLon2Text(lat, lon)
|
||||||
-- inspired by mist, thanks Grimes!
|
-- inspired by mist, thanks Grimes!
|
||||||
-- returns two strings: lat and lon
|
-- returns two strings: lat and lon
|
||||||
@ -3340,6 +3350,47 @@ function dcsCommon.spellString(inString)
|
|||||||
return res
|
return res
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- RGBA from hex
|
||||||
|
--
|
||||||
|
function dcsCommon.hexString2RGBA(inString)
|
||||||
|
-- enter with "#FF0020" (RGB) or "#FF00AB99" RGBA
|
||||||
|
-- check if it starts with #
|
||||||
|
if not inString then return nil end
|
||||||
|
if #inString ~= 7 and #inString ~=9 then return nil end
|
||||||
|
if inString:sub(1, 1) ~= "#" then return nil end
|
||||||
|
inString = inString:lower()
|
||||||
|
local red = tonumber("0x" .. inString:sub(2,3))
|
||||||
|
if not red then red = 0 end
|
||||||
|
local green = tonumber("0x" .. inString:sub(4,5))
|
||||||
|
if not green then green = 0 end
|
||||||
|
local blue = tonumber("0x" .. inString:sub(6,7))
|
||||||
|
if not blue then blue = 0 end
|
||||||
|
local alpha = 255
|
||||||
|
if #inString == 9 then
|
||||||
|
alpha = tonumber("0x" .. inString:sub(8,9))
|
||||||
|
end
|
||||||
|
if not alpha then alpha = 0 end
|
||||||
|
return {red/255, green/255, blue/255, alpha/255}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Player handling
|
||||||
|
--
|
||||||
|
function dcsCommon.playerName2Coalition(playerName)
|
||||||
|
if not playerName then return 0 end
|
||||||
|
local factions = {1,2}
|
||||||
|
for idx, theFaction in pairs(factions) do
|
||||||
|
local players = coalition.getPlayers(theFaction)
|
||||||
|
for idy, theUnit in pairs(players) do
|
||||||
|
local upName = theUnit:getPlayerName()
|
||||||
|
if upName == playerName then return theFaction end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- iterators
|
-- iterators
|
||||||
--
|
--
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
missionRestart = {}
|
missionRestart = {}
|
||||||
|
missionRestart.version = "1.0.0"
|
||||||
missionRestart.restarting = false
|
missionRestart.restarting = false
|
||||||
|
--
|
||||||
|
-- Restart this mission, irrespective of its name
|
||||||
|
-- Only works if run as multiplayer (sends commands to the server)
|
||||||
|
--
|
||||||
function missionRestart.restart()
|
function missionRestart.restart()
|
||||||
if missionRestart.restarting then return end
|
if missionRestart.restarting then return end
|
||||||
|
|
||||||
|
|||||||
75
modules/sittingDucks standalone.lua
Normal file
75
modules/sittingDucks standalone.lua
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
sittingDucks = {}
|
||||||
|
sittingDucks.verbose = false
|
||||||
|
sittingDucks.version = "1.0.0"
|
||||||
|
sittingDucks.ssbDisabled = 100 -- must match the setting of SSB, usually 100
|
||||||
|
sittingDucks.resupplyTime = -1 -- seconds until "reinforcements" reopen the slot, set to -1 to turn off, 3600 is one hour
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Destroying a client stand-in on an airfield will block that
|
||||||
|
-- Slot for players. Multiplayer only
|
||||||
|
-- WARNING: ENTIRE GROUP will be blocked when one aircraft is destroyed
|
||||||
|
--
|
||||||
|
-- MULTIPLAYER-ONLY. REQUIRES (on the server):
|
||||||
|
-- 1) SSB running on the server AND
|
||||||
|
-- 2) set SSB.kickReset = false
|
||||||
|
--
|
||||||
|
|
||||||
|
function sittingDucks:onEvent(event)
|
||||||
|
if not event then return end
|
||||||
|
if not event.id then return end
|
||||||
|
if not event.initiator then return end
|
||||||
|
|
||||||
|
-- home in on the kill event
|
||||||
|
if event.id == 8 then -- dead event
|
||||||
|
local theUnit = event.initiator
|
||||||
|
local deadName = theUnit:getName()
|
||||||
|
if not deadName then return end
|
||||||
|
-- look at stopGap's collection of stand-ins
|
||||||
|
for gName, staticGroup in pairs (stopGap.standInGroups) do
|
||||||
|
for uName, aStatic in pairs(staticGroup) do
|
||||||
|
if uName == deadName then -- yup, a stand-in. block entire group
|
||||||
|
local blockState = sittingDucks.ssbDisabled
|
||||||
|
trigger.action.setUserFlag(gName, blockState)
|
||||||
|
-- tell cfxSSBClient as well - if it's loaded
|
||||||
|
if cfxSSBClient and cfxSSBClient.slotState then
|
||||||
|
cfxSSBClient.slotState[gName] = blockState
|
||||||
|
end
|
||||||
|
if sittingDucks.verbose then
|
||||||
|
trigger.action.outText("SittingDuck: in group <" .. gName .. "> unit <" .. uName .. "> was destroyed on the ground, group blocked.", 30)
|
||||||
|
end
|
||||||
|
if sittingDucks.resupplyTime > 0 then
|
||||||
|
timer.scheduleFunction(sittingDucks.resupply, gName, timer.getTime() + sittingDucks.resupplyTime)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- re-supply: enable slots after some time
|
||||||
|
function sittingDucks.resupply(args)
|
||||||
|
local gName = args
|
||||||
|
trigger.action.setUserFlag(gName, 0)
|
||||||
|
if cfxSSBClient and cfxSSBClient.slotState then
|
||||||
|
cfxSSBClient.slotState[gName] = 0
|
||||||
|
end
|
||||||
|
if stopGap.standInGroups[gName] then -- should not happen, just in case
|
||||||
|
stopGap.removeStaticGapGroupNamed(gName)
|
||||||
|
end
|
||||||
|
if sittingDucks.verbose then
|
||||||
|
trigger.action.outText("SittingDuck: group <" .. gName .. "> re-supplied, slots reopened.", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- make sure stopGap is available
|
||||||
|
if stopGap and stopGap.start then
|
||||||
|
trigger.action.setUserFlag("SSB",100)
|
||||||
|
world.addEventHandler(sittingDucks)
|
||||||
|
trigger.action.outText("Sitting Ducks v" .. sittingDucks.version .. " running, SSB enabled", 30)
|
||||||
|
else
|
||||||
|
trigger.action.outText("Sitting Ducks requires stopGap to run", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
148
modules/sittingDucks.lua
Normal file
148
modules/sittingDucks.lua
Normal file
@ -0,0 +1,148 @@
|
|||||||
|
sittingDucks = {}
|
||||||
|
sittingDucks.verbose = false
|
||||||
|
sittingDucks.version = "1.0.0"
|
||||||
|
sittingDucks.ssbDisabled = 100 -- must match the setting of SSB, usually 100
|
||||||
|
sittingDucks.resupplyTime = -1 -- seconds until "reinforcements" reopen the slot, set to -1 to turn off, 3600 is one hour
|
||||||
|
sittingDucks.requiredLibs = {
|
||||||
|
"dcsCommon",
|
||||||
|
"cfxZones",
|
||||||
|
"stopGap",
|
||||||
|
}
|
||||||
|
--
|
||||||
|
-- Destroying a client stand-in on an airfield will block that
|
||||||
|
-- Slot for players. Multiplayer only
|
||||||
|
-- WARNING: ENTIRE GROUP will be blocked when one aircraft is destroyed
|
||||||
|
--
|
||||||
|
-- MULTIPLAYER-ONLY. REQUIRES (on the server):
|
||||||
|
-- 1) SSB running on the server AND
|
||||||
|
-- 2) set SSB.kickReset = false
|
||||||
|
--
|
||||||
|
|
||||||
|
function sittingDucks:onEvent(event)
|
||||||
|
if not event then return end
|
||||||
|
if not event.id then return end
|
||||||
|
if not event.initiator then return end
|
||||||
|
|
||||||
|
if not sittingDucks.enabled then return end -- olny look if we are turned on
|
||||||
|
|
||||||
|
-- home in on the kill event
|
||||||
|
if event.id == 8 then -- dead event
|
||||||
|
local theUnit = event.initiator
|
||||||
|
local deadName = theUnit:getName()
|
||||||
|
if not deadName then return end
|
||||||
|
-- look at stopGap's collection of stand-ins
|
||||||
|
for gName, staticGroup in pairs (stopGap.standInGroups) do
|
||||||
|
for uName, aStatic in pairs(staticGroup) do
|
||||||
|
if uName == deadName then -- yup, a stand-in. block entire group
|
||||||
|
local blockState = sittingDucks.ssbDisabled
|
||||||
|
trigger.action.setUserFlag(gName, blockState)
|
||||||
|
-- tell cfxSSBClient as well - if it's loaded
|
||||||
|
if cfxSSBClient and cfxSSBClient.slotState then
|
||||||
|
cfxSSBClient.slotState[gName] = blockState
|
||||||
|
end
|
||||||
|
if sittingDucks.verbose then
|
||||||
|
trigger.action.outText("SittingDucks: in group <" .. gName .. "> unit <" .. uName .. "> was destroyed on the ground, group blocked.", 30)
|
||||||
|
end
|
||||||
|
if sittingDucks.resupplyTime > 0 then
|
||||||
|
timer.scheduleFunction(sittingDucks.resupply, gName, timer.getTime() + sittingDucks.resupplyTime)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
-- re-supply: enable slots after some time
|
||||||
|
function sittingDucks.resupply(args)
|
||||||
|
local gName = args
|
||||||
|
trigger.action.setUserFlag(gName, 0)
|
||||||
|
if cfxSSBClient and cfxSSBClient.slotState then
|
||||||
|
cfxSSBClient.slotState[gName] = 0
|
||||||
|
end
|
||||||
|
if stopGap.standInGroups[gName] then -- should not happen, just in case
|
||||||
|
stopGap.removeStaticGapGroupNamed(gName)
|
||||||
|
end
|
||||||
|
if sittingDucks.verbose then
|
||||||
|
trigger.action.outText("SittingDucks: group <" .. gName .. "> re-supplied, slots reopened.", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Update
|
||||||
|
--
|
||||||
|
--
|
||||||
|
function sittingDucks.update()
|
||||||
|
-- check every second.
|
||||||
|
timer.scheduleFunction(sittingDucks.update, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
|
-- check if signal for on? or off?
|
||||||
|
if sittingDucks.turnOn and cfxZones.testZoneFlag(sittingDucks, sittingDucks.turnOnFlag, sittingDucks.triggerMethod, "lastTurnOnFlag") then
|
||||||
|
sittingDucks.enabled = true
|
||||||
|
end
|
||||||
|
|
||||||
|
if sittingDucks.turnOff and cfxZones.testZoneFlag(sittingDucks, sittingDucks.turnOffFlag, sittingDucks.triggerMethod, "lastTurnOffFlag") then
|
||||||
|
sittingDucks.enabled = false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Read Config & start
|
||||||
|
--
|
||||||
|
sittingDucks.name = "sittingDucksConfig" -- cfxZones compatibility here
|
||||||
|
function sittingDucks.readConfigZone(theZone)
|
||||||
|
-- currently nothing to do
|
||||||
|
sittingDucks.verbose = theZone.verbose
|
||||||
|
sittingDucks.resupplyTime = cfxZones.getNumberFromZoneProperty(theZone, "resupplyTime", -1)
|
||||||
|
sittingDucks.enabled = cfxZones.getBoolFromZoneProperty(theZone, "onStart", true)
|
||||||
|
sittingDucks.triggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
|
||||||
|
if cfxZones.hasProperty(theZone, "on?") then
|
||||||
|
sittingDucks.turnOnFlag = cfxZones.getStringFromZoneProperty(theZone, "on?", "*<none>")
|
||||||
|
sittingDucks.lastTurnOnFlag = trigger.misc.getUserFlag(sittingDucks.turnOnFlag)
|
||||||
|
end
|
||||||
|
if cfxZones.hasProperty(theZone, "off?") then
|
||||||
|
sittingDucks.turnOffFlag = cfxZones.getStringFromZoneProperty(theZone, "off?", "*<none>")
|
||||||
|
sittingDucks.lastTurnOffFlag = trigger.misc.getUserFlag(sittingDucks.turnOffFlag)
|
||||||
|
end
|
||||||
|
|
||||||
|
if sittingDucks.verbose then
|
||||||
|
trigger.action.outText("+++sitD: config read, verbose = YES", 30)
|
||||||
|
if sittingDucks.enabled then
|
||||||
|
trigger.action.outText("+++sitD: enabled", 30)
|
||||||
|
else
|
||||||
|
trigger.action.outText("+++sitD: turned off", 30)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function sittingDucks.start()
|
||||||
|
if not dcsCommon.libCheck("cfx Sitting Ducks",
|
||||||
|
stopGap.requiredLibs)
|
||||||
|
then return false end
|
||||||
|
|
||||||
|
local theZone = cfxZones.getZoneByName("sittingDucksConfig")
|
||||||
|
if not theZone then
|
||||||
|
theZone = cfxZones.createSimpleZone("sittingDucksConfig")
|
||||||
|
end
|
||||||
|
sittingDucks.readConfigZone(theZone)
|
||||||
|
|
||||||
|
-- turn on SSB
|
||||||
|
trigger.action.setUserFlag("SSB",100)
|
||||||
|
|
||||||
|
-- let's get set up
|
||||||
|
world.addEventHandler(sittingDucks) -- event handler in place
|
||||||
|
timer.scheduleFunction(sittingDucks.update, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
|
trigger.action.outText("Sitting Ducks v" .. sittingDucks.version .. " running, SSB enabled", 30)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
if not sittingDucks.start() then
|
||||||
|
trigger.action.outText("Sitting Ducks failed to start up.", 30)
|
||||||
|
sittingDucks = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
@ -1,5 +1,5 @@
|
|||||||
stopGap = {}
|
stopGap = {}
|
||||||
stopGap.version = "1.0.4"
|
stopGap.version = "1.0.5"
|
||||||
stopGap.verbose = false
|
stopGap.verbose = false
|
||||||
stopGap.ssbEnabled = true
|
stopGap.ssbEnabled = true
|
||||||
stopGap.ignoreMe = "-sg"
|
stopGap.ignoreMe = "-sg"
|
||||||
@ -35,6 +35,7 @@ stopGap.requiredLibs = {
|
|||||||
- stopGap Zones
|
- stopGap Zones
|
||||||
1.0.3 - server plug-in logic
|
1.0.3 - server plug-in logic
|
||||||
1.0.4 - player units or groups that end in '-sg' are not stop-gapped
|
1.0.4 - player units or groups that end in '-sg' are not stop-gapped
|
||||||
|
1.0.5 - triggerMethod
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
stopGap.standInGroups = {}
|
stopGap.standInGroups = {}
|
||||||
@ -216,14 +217,14 @@ function stopGap.update()
|
|||||||
timer.scheduleFunction(stopGap.update, {}, timer.getTime() + 1)
|
timer.scheduleFunction(stopGap.update, {}, timer.getTime() + 1)
|
||||||
|
|
||||||
-- check if signal for on? or off?
|
-- check if signal for on? or off?
|
||||||
if stopGap.turnOn and cfxZones.testZoneFlag(stopGap, stopGap.turnOnFlag, "change", "lastTurnOnFlag") then
|
if stopGap.turnOn and cfxZones.testZoneFlag(stopGap, stopGap.turnOnFlag, stopGap.triggerMethod, "lastTurnOnFlag") then
|
||||||
if not stopGap.enabled then
|
if not stopGap.enabled then
|
||||||
stopGap.turnOn()
|
stopGap.turnOn()
|
||||||
end
|
end
|
||||||
stopGap.enabled = true
|
stopGap.enabled = true
|
||||||
end
|
end
|
||||||
|
|
||||||
if stopGap.turnOff and cfxZones.testZoneFlag(stopGap, stopGap.turnOffFlag, "change", "lastTurnOffFlag") then
|
if stopGap.turnOff and cfxZones.testZoneFlag(stopGap, stopGap.turnOffFlag, stopGap.triggerMethod, "lastTurnOffFlag") then
|
||||||
if stopGap.enabled then
|
if stopGap.enabled then
|
||||||
stopGap.turnOff()
|
stopGap.turnOff()
|
||||||
end
|
end
|
||||||
@ -315,7 +316,7 @@ function stopGap.readConfigZone(theZone)
|
|||||||
stopGap.turnOffFlag = cfxZones.getStringFromZoneProperty(theZone, "off?", "*<none>")
|
stopGap.turnOffFlag = cfxZones.getStringFromZoneProperty(theZone, "off?", "*<none>")
|
||||||
stopGap.lastTurnOffFlag = trigger.misc.getUserFlag(stopGap.turnOffFlag)
|
stopGap.lastTurnOffFlag = trigger.misc.getUserFlag(stopGap.turnOffFlag)
|
||||||
end
|
end
|
||||||
|
stopGap.triggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
|
||||||
if stopGap.verbose then
|
if stopGap.verbose then
|
||||||
trigger.action.outText("+++StopG: config read, verbose = YES", 30)
|
trigger.action.outText("+++StopG: config read, verbose = YES", 30)
|
||||||
if stopGap.enabled then
|
if stopGap.enabled then
|
||||||
|
|||||||
BIN
tutorial & demo missions/demo - Caucasus Hangar.miz
Normal file
BIN
tutorial & demo missions/demo - Caucasus Hangar.miz
Normal file
Binary file not shown.
Binary file not shown.
BIN
tutorial & demo missions/demo - sitting ducks in a barrel.miz
Normal file
BIN
tutorial & demo missions/demo - sitting ducks in a barrel.miz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user