Version 1.3.3

PlayerScore flag score
stopGap single player
This commit is contained in:
Christian Franz 2023-06-21 15:06:54 +02:00
parent 3b6f22ab78
commit 3f0de87b07
11 changed files with 228 additions and 25 deletions

Binary file not shown.

Binary file not shown.

View File

@ -1,5 +1,5 @@
cfxMX = {}
cfxMX.version = "1.2.5"
cfxMX.version = "1.2.6"
cfxMX.verbose = false
--[[--
Mission data decoder. Access to ME-built mission structures
@ -25,6 +25,8 @@ cfxMX.verbose = false
- groupCoalitionByName
1.2.4 - playerUnit2Group cross index
1.2.5 - unitIDbyName index added
1.2.6 - cfxMX.allTrainsByName
- train carve-outs for vehicles
--]]--
cfxMX.groupNamesByID = {}
cfxMX.groupIDbyName = {}
@ -39,6 +41,7 @@ cfxMX.allHeloByName = {}
cfxMX.allGroundByName = {}
cfxMX.allSeaByName = {}
cfxMX.allStaticByName = {}
cfxMX.allTrainsByName = {}
cfxMX.playerGroupByName = {} -- returns data only if a player is in group
cfxMX.playerUnitByName = {} -- returns data only if this is a player unit
@ -76,6 +79,7 @@ function cfxMX.getGroupFromDCSbyName(aName, fetchOriginal)
obj_type_name == "plane" or
obj_type_name == "vehicle" or
obj_type_name == "static"
-- note: trains are 'vehicle' here
then -- (so it's not id or name)
local category = obj_type_name
if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's at least one group!
@ -86,6 +90,9 @@ function cfxMX.getGroupFromDCSbyName(aName, fetchOriginal)
if not fetchOriginal then
theGroup = dcsCommon.clone(group_data)
end
-- train carve-out: if first unit's type == "Train", change
-- category to "train"
if group_data.units[1] and group_data.units[1].type == "Train" then category = "train" end
return theGroup, category, countryID
end
end
@ -200,6 +207,7 @@ function cfxMX.createCrossReferences()
obj_type_name == "plane" or
obj_type_name == "vehicle" or
obj_type_name == "static" -- what about "cargo"?
-- not that trains appear as 'vehicle'
then -- (so it's not id or name)
local category = obj_type_name
if ((type(obj_type_data) == 'table') and obj_type_data.group and (type(obj_type_data.group) == 'table') and (#obj_type_data.group > 0)) then --there's at least one group!
@ -213,6 +221,11 @@ function cfxMX.createCrossReferences()
linkUnit = group_data.route.points[1].linkUnit
cfxMX.linkByName[aName] = linkUnit
end
if group_data.units[1] and group_data.units[1].type == "Train" then
category = "train"
obj_type_name = "train"
end
cfxMX.groupTypeByName[aName] = category
cfxMX.groupNamesByID[aID] = aName
cfxMX.groupIDbyName[aName] = aID
@ -231,6 +244,8 @@ function cfxMX.createCrossReferences()
cfxMX.allGroundByName[aName] = group_data
elseif obj_type_name == "static" then
cfxMX.allStaticByName[aName] = group_data
elseif obj_type_name == "train" then
cfxMX.allTrainsByName[aName] = group_data
else
-- should be impossible, but still
trigger.action.outText("+++MX: <" .. obj_type_name .. "> unknown type for <" .. aName .. ">", 30)
@ -268,6 +283,7 @@ function cfxMX.catText2ID(inText)
if c == "vehicle" then outCat = 2 end
if c == "train" then outCat = 4 end
if c == "static" then outCat = -1 end
--trigger.action.outText("cat2text: in <" .. inText .. "> out <" .. outCat .. ">", 30)
return outCat
end

View File

@ -1,5 +1,5 @@
cfxPlayerScore = {}
cfxPlayerScore.version = "2.1.1"
cfxPlayerScore.version = "2.2.0"
cfxPlayerScore.name = "cfxPlayerScore" -- compatibility with flag bangers
cfxPlayerScore.badSound = "Death BRASS.wav"
cfxPlayerScore.scoreSound = "Quest Snare 3.wav"
@ -80,6 +80,7 @@ cfxPlayerScore.firstSave = true -- to force overwrite
- new scoreSummaryForPlayersOfCoalition()
- new noGrief option in config
- improved guards when checking ownership (nil zone owner)
2.0.0 - score flags for red and blue
--]]--
@ -1396,6 +1397,38 @@ function cfxPlayerScore.update()
end
end
-- check score flags
if cfxPlayerScore.blueTriggerFlags then
local coa = 2
for tName, tVal in pairs(cfxPlayerScore.blueTriggerFlags) do
local newVal = trigger.misc.getUserFlag(tName)
if tVal ~= newVal then
-- score!
cfxPlayerScore.coalitionScore[coa] = cfxPlayerScore.coalitionScore[coa] + cfxPlayerScore.blueTriggerScore[tName]
cfxPlayerScore.blueTriggerFlags[tName] = newVal
if cfxPlayerScore.announcer then
trigger.action.outTextForCoalition(coa, "BLUE goal [" .. tName .. "] achieved, new BLUE coalition score is " .. cfxPlayerScore.coalitionScore[coa], 30)
trigger.action.outSoundForCoalition(coa, cfxPlayerScore.scoreSound)
end
end
end
end
if cfxPlayerScore.redTriggerFlags then
local coa = 1
for tName, tVal in pairs(cfxPlayerScore.redTriggerFlags) do
local newVal = trigger.misc.getUserFlag(tName)
if tVal ~= newVal then
-- score!
cfxPlayerScore.coalitionScore[coa] = cfxPlayerScore.coalitionScore[coa] + cfxPlayerScore.redTriggerScore[tName]
cfxPlayerScore.redTriggerFlags[tName] = newVal
if cfxPlayerScore.announcer then
trigger.action.outTextForCoalition(coa, "RED goal [" .. tName .. "] achieved, new RED coalition score is " .. cfxPlayerScore.coalitionScore[coa], 30)
trigger.action.outSoundForCoalition(coa, cfxPlayerScore.scoreSound)
end
end
end
end
end
--
-- start
@ -1418,10 +1451,42 @@ function cfxPlayerScore.start()
trigger.action.outText("+++scr: read score table", 30)
end
-- read score tiggers and values
cfxPlayerScore.redTriggerFlags = nil
cfxPlayerScore.blueTriggerFlags = nil
local theZone = cfxZones.getZoneByName("redScoreFlags")
if theZone then
-- read flags into redTriggerScore
cfxPlayerScore.redTriggerScore = cfxZones.getAllZoneProperties(theZone, false, true) -- use case, all numbers
-- init their flag handlers
cfxPlayerScore.redTriggerFlags = {}
trigger.action.outText("+++pScr: read RED score table", 30)
for tName, tScore in pairs(cfxPlayerScore.redTriggerScore) do
if tScore == 0 then
trigger.action.outText("+++pScr: WARNING - RED triggered score <" .. tName .. "> has zero score value!", 30)
end
cfxPlayerScore.redTriggerFlags[tName] = trigger.misc.getUserFlag(tName)
end
end
local theZone = cfxZones.getZoneByName("blueScoreFlags")
if theZone then
-- read flags into redTriggerScore
cfxPlayerScore.blueTriggerScore = cfxZones.getAllZoneProperties(theZone, false, true) -- case sensitive, numbers only
-- init their flag handlers
cfxPlayerScore.blueTriggerFlags = {}
trigger.action.outText("+++pScr: read BLUE score table", 30)
for tName, tScore in pairs(cfxPlayerScore.blueTriggerScore) do
if tScore == 0 then
trigger.action.outText("+++pScr: WARNING - BLUE triggered score <" .. tName .. "> has zero score value!", 30)
end
cfxPlayerScore.blueTriggerFlags[tName] = trigger.misc.getUserFlag(tName)
end
end
-- now read my config zone
local theZone = cfxZones.getZoneByName("playerScoreConfig")
if not theZone then
trigger.action.outText("+++scr: no config!", 30)
trigger.action.outText("+++pScr: no config!", 30)
theZone = cfxZones.createSimpleZone("playerScoreConfig")
end
cfxPlayerScore.readConfigZone(theZone)

View File

@ -1,5 +1,5 @@
cfxZones = {}
cfxZones.version = "3.1.1"
cfxZones.version = "3.1.2"
-- cf/x zone management module
-- reads dcs zones and makes them accessible and mutable
@ -131,6 +131,7 @@ cfxZones.version = "3.1.1"
new getRGBAVectorFromZoneProperty()
- 3.1.1 - getRGBAVectorFromZoneProperty now supports #RRGGBBAA and #RRGGBB format
- owner for all, default 0
- 3.1.2 - getAllZoneProperties has numbersOnly option
--]]--
cfxZones.verbose = false
@ -1947,8 +1948,9 @@ end
-- ===================
--
function cfxZones.getAllZoneProperties(theZone, caseInsensitive) -- return as dict
function cfxZones.getAllZoneProperties(theZone, caseInsensitive, numbersOnly) -- return as dict
if not caseInsensitive then caseInsensitive = false end
if not numbersOnly then numbersOnly = false end
if not theZone then return {} end
local dcsProps = theZone.properties -- zone properties in dcs format
@ -1960,7 +1962,12 @@ function cfxZones.getAllZoneProperties(theZone, caseInsensitive) -- return as di
local theKey = "dummy"
if string.len(theProp.key) > 0 then theKey = theProp.key end
if caseInsensitive then theKey = theKey:upper() end
props[theKey] = theProp.value
local v = theProp.value
if numbersOnly then
v = tonumber(v)
if not v then v = 0 end
end
props[theKey] = v
end
return props
end

View File

@ -1,5 +1,5 @@
dcsCommon = {}
dcsCommon.version = "2.8.8"
dcsCommon.version = "2.8.9"
--[[-- VERSION HISTORY
2.2.6 - compassPositionOfARelativeToB
- clockPositionOfARelativeToB
@ -153,6 +153,10 @@ dcsCommon.version = "2.8.8"
2.8.8 - new hexString2RGBA()
- new playerName2Coalition()
- new coalition2Text()
2.8.9 - vAdd supports xy and xyz
- vSub supports xy and xyz
- vMultScalar supports xy and xyz
--]]--
-- dcsCommon is a library of common lua functions
@ -2684,7 +2688,9 @@ function dcsCommon.vAdd(a, b)
if not b then b = {x = 0, y = 0, z = 0} end
r.x = a.x + b.x
r.y = a.y + b.y
r.z = a.z + b.z
if a.z and b.z then
r.z = a.z + b.z
end
return r
end
@ -2694,7 +2700,9 @@ function dcsCommon.vSub(a, b)
if not b then b = {x = 0, y = 0, z = 0} end
r.x = a.x - b.x
r.y = a.y - b.y
r.z = a.z - b.z
if a.z and b.z then
r.z = a.z - b.z
end
return r
end
@ -2704,7 +2712,9 @@ function dcsCommon.vMultScalar(a, f)
if not f then f = 0 end
r.x = a.x * f
r.y = a.y * f
r.z = a.z * f
if a.z and b.z then
r.z = a.z * f
end
return r
end

View File

@ -1,8 +1,11 @@
stopGap = {}
stopGap.version = "1.0.4 STANDALONE"
stopGap.version = "1.0.6 STANDALONE"
stopGap.verbose = false
stopGap.ssbEnabled = true
stopGap.ignoreMe = "-sg"
stopGap.spIgnore = "-sp" -- only single-player ignored
stopGap.isMP = false
--[[--
Written and (c) 2023 by Christian Franz
@ -23,7 +26,9 @@ stopGap.ignoreMe = "-sg"
1.0.1 - update / replace statics after slots become free
1.0.3 - server plug-in logic for SSB, sgGUI
1.0.4 - player units or groups that end in '-sg' are not stop-gapped
1.0.5 - (DML-only additions)
1.0.6 - can detect stopGapGUI active on server
- supports "-sp" for single-player only suppress
--]]--
stopGap.standInGroups ={}
@ -124,7 +129,7 @@ function stopGap.isGroundStart(theGroup)
local sType = land.getSurfaceType(u1) -- has fields x and y
if sType == 3 then return false end
if stopGap.verbose then
if false then
trigger.action.outText("Player Group <" .. theGroup.name .. "> GROUND BASED: " .. action .. " land type " .. sType, 30)
end
return true
@ -134,14 +139,24 @@ function stopGap.createStandInsForMXGroup(group)
local allUnits = group.units
if group.name:sub(-#stopGap.ignoreMe) == stopGap.ignoreMe then
if stopGap.verbose then
trigger.action.outText("<<skipping group " .. group.name .. ">>", 30)
trigger.action.outText("<< '-sg' skipping group " .. group.name .. ">>", 30)
end
return nil
end
if (not stopGap.isMP) and group.name:sub(-#stopGap.spIgnore) == stopGap.spIgnore then
if stopGap.verbose then
trigger.action.outText("<<'-sp' !SP! skipping group " .. group.name .. ">>", 30)
end
return nil
end
local theStaticGroup = {}
for idx, theUnit in pairs (allUnits) do
local sgMatch = theUnit.name:sub(-#stopGap.ignoreMe) == stopGap.ignoreMe
local spMatch = theUnit.name:sub(-#stopGap.spIgnore) == stopGap.spIgnore
if stopGap.isMP then spMatch = false end -- only single-player
if (theUnit.skill == "Client" or theUnit.skill == "Player")
and (theUnit.name:sub(-#stopGap.ignoreMe) ~= stopGap.ignoreMe)
and (not sgMatch)
and (not spMatch)
then
local theStaticMX = stopGap.staticMXFromUnitMX(group, theUnit)
local theStatic = coalition.addStaticObject(theStaticMX.cty, theStaticMX)
@ -189,6 +204,21 @@ function stopGap.initGaps()
end
end
function stopGap.turnOff()
-- remove all stand-ins
for gName, standIn in pairs (stopGap.standInGroups) do
for name, theStatic in pairs(standIn) do
StaticObject.destroy(theStatic)
end
end
stopGap.standInGroups = {}
end
function stopGap.turnOn()
-- populate all empty (non-taken) slots with stand-ins
stopGap.initGaps()
end
--
-- event handling
--
@ -234,6 +264,16 @@ function stopGap.update()
-- check every 1 second
timer.scheduleFunction(stopGap.update, {}, timer.getTime() + 1)
if not stopGap.isMP then
local sgDetect = trigger.misc.getUserFlag("stopGapGUI")
if sgDetect > 0 then
trigger.action.outText("stopGap: MP activated <" .. sgDetect .. ">, will re-init", 30)
stopGap.turnOff()
stopGap.isMP = true
stopGap.turnOn()
end
end
-- check if slots can be refilled or need to be vacated (MP)
for name, theGroup in pairs(stopGap.myGroups) do
if not stopGap.standInGroups[name] then
@ -296,6 +336,11 @@ end
-- get going
--
function stopGap.start()
-- check MP status, usually client is not synched to
-- server, yet so it will initially fail, and re-init in update()
local sgDetect = trigger.misc.getUserFlag("stopGapGUI")
stopGap.isMP = sgDetect > 0
-- run a cross reference on all mission data for palyer info
cfxMX.createCrossReferences()
-- fill player slots with static objects
@ -308,7 +353,9 @@ function stopGap.start()
timer.scheduleFunction(stopGap.update, {}, timer.getTime() + 1)
-- say hi!
trigger.action.outText("stopGap v" .. stopGap.version .. " running", 30)
local mp = " (SP - <" .. sgDetect .. ">)"
if sgDetect > 0 then mp = " -- MP GUI Detected (" .. sgDetect .. ")!" end
trigger.action.outText("stopGap v" .. stopGap.version .. " running" .. mp, 30)
return true
end

View File

@ -1,8 +1,11 @@
stopGap = {}
stopGap.version = "1.0.5"
stopGap.version = "1.0.6"
stopGap.verbose = false
stopGap.ssbEnabled = true
stopGap.ignoreMe = "-sg"
stopGap.spIgnore = "-sp" -- only single-player ignored
stopGap.isMP = false
stopGap.requiredLibs = {
"dcsCommon",
"cfxZones",
@ -36,6 +39,7 @@ stopGap.requiredLibs = {
1.0.3 - server plug-in logic
1.0.4 - player units or groups that end in '-sg' are not stop-gapped
1.0.5 - triggerMethod
1.0.6 - spIgnore '-sp'
--]]--
stopGap.standInGroups = {}
@ -86,12 +90,17 @@ function stopGap.isGroundStart(theGroup)
return true
end
function stopGap.ignoreMXUnit(theUnit)
function stopGap.ignoreMXUnit(theUnit) -- DML-only
local p = {x=theUnit.x, y=0, z=theUnit.y}
for idx, theZone in pairs(stopGap.stopGapZones) do
if theZone.sgIgnore and cfxZones.pointInZone(p, theZone) then
return true
end
-- only single-player: exclude units in spIgnore zones
if (not stopGap.isMP) and
theZone.spIgnore and cfxZones.pointInZone(p, theZone) then
return true
end
end
return false
end
@ -104,13 +113,24 @@ function stopGap.createStandInsForMXGroup(group)
end
return nil
end
if (not stopGap.isMP) and group.name:sub(-#stopGap.spIgnore) == stopGap.spIgnore then
if stopGap.verbose then
trigger.action.outText("<<'-sp' !SP! skipping group " .. group.name .. ">>", 30)
end
return nil
end
local theStaticGroup = {}
for idx, theUnit in pairs (allUnits) do
local sgMatch = theUnit.name:sub(-#stopGap.ignoreMe) == stopGap.ignoreMe
local spMatch = theUnit.name:sub(-#stopGap.spIgnore) == stopGap.spIgnore
local zoneIgnore = stopGap.ignoreMXUnit(theUnit)
if stopGap.isMP then spMatch = false end -- only single-player
if (theUnit.skill == "Client" or theUnit.skill == "Player")
and (theUnit.name:sub(-#stopGap.ignoreMe) ~= stopGap.ignoreMe)
and (not stopGap.ignoreMXUnit(theUnit))
then
and (not sgMatch)
and (not spMatch)
and (not zoneIgnore)
then
local theStaticMX = stopGap.staticMXFromUnitMX(group, theUnit)
local theStatic = coalition.addStaticObject(theStaticMX.cty, theStaticMX)
theStaticGroup[theUnit.name] = theStatic -- remember me
@ -215,8 +235,21 @@ end
function stopGap.update()
-- check every second.
timer.scheduleFunction(stopGap.update, {}, timer.getTime() + 1)
-- check if signal for on? or off?
if not stopGap.isMP then
local sgDetect = trigger.misc.getUserFlag("stopGapGUI")
if sgDetect > 0 then
trigger.action.outText("stopGap: MP activated <" .. sgDetect .. ">, will re-init", 30)
stopGap.turnOff()
stopGap.isMP = true
if stopGap.enabled then
stopGap.turnOn()
end
return
end
end
-- check if signal for on? or off?
if stopGap.turnOn and cfxZones.testZoneFlag(stopGap, stopGap.turnOnFlag, stopGap.triggerMethod, "lastTurnOnFlag") then
if not stopGap.enabled then
stopGap.turnOn()
@ -299,6 +332,11 @@ function stopGap.createStopGapZone(theZone)
if sg then theZone.sgIgnore = false else theZone.sgIgnore = true end
end
function stopGap.createStopGapSPZone(theZone)
local sp = cfxZones.getBoolFromZoneProperty(theZone, "stopGapSP", true)
if sp then theZone.spIgnore = false else theZone.spIgnore = true end
end
--
-- Read Config Zone
--
@ -335,6 +373,9 @@ function stopGap.start()
stopGap.requiredLibs)
then return false end
local sgDetect = trigger.misc.getUserFlag("stopGapGUI")
stopGap.isMP = sgDetect > 0
local theZone = cfxZones.getZoneByName("stopGapConfig")
if not theZone then
theZone = cfxZones.createSimpleZone("stopGapConfig")
@ -348,6 +389,13 @@ function stopGap.start()
stopGap.stopGapZones[aZone.name] = aZone
end
-- collect single-player exclusion zones
local pZones = cfxZones.zonesWithProperty("stopGapSP")
for k, aZone in pairs(pZones) do
stopGap.createStopGapSPZone(aZone)
stopGap.stopGapZones[aZone.name] = aZone
end
-- fill player slots with static objects
if stopGap.enabled then
stopGap.initGaps()
@ -360,7 +408,10 @@ function stopGap.start()
timer.scheduleFunction(stopGap.update, {}, timer.getTime() + 1)
-- say hi!
trigger.action.outText("stopGap v" .. stopGap.version .. " running", 30)
local mp = " (SP - <" .. sgDetect .. ">)"
if sgDetect > 0 then mp = " -- MP GUI Detected (" .. sgDetect .. ")!" end
trigger.action.outText("stopGap v" .. stopGap.version .. " running" .. mp, 30)
return true
end

View File

@ -1,5 +1,5 @@
stopGapGUI = {}
stopGapGUI.version = "1.0.0"
stopGapGUI.version = "1.0.1"
stopGapGUI.fVal = -300 -- 5 minutes max block
--
-- Server Plug-In for StopGap mission script, only required for server
@ -19,4 +19,11 @@ function stopGapGUI.onPlayerTryChangeSlot(playerID, side, slotID)
net.send_chat("+++SG: readying group <" .. sgName .. "> for slotting")
end
function stopGapGUI.onSimulationStart()
net.dostring_in("server", " trigger.action.setUserFlag(\"stopGapGUI\", 0); ")
if not DCS.isServer() then return end
if not DCS.isMultiplayer() then return end
net.dostring_in("server", " trigger.action.setUserFlag(\"stopGapGUI\", 200); ") -- tells client that MP is active
end
DCS.setUserCallbacks(stopGapGUI)

Binary file not shown.