mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 1.5.1
DCS 2.9 Fixes, TDZ
This commit is contained in:
parent
a3cffa58d1
commit
663038db0a
Binary file not shown.
Binary file not shown.
145
modules/TDZ.lua
145
modules/TDZ.lua
@ -1,5 +1,5 @@
|
||||
tdz = {}
|
||||
tdz.version = "1.0.0"
|
||||
tdz.version = "1.0.1"
|
||||
tdz.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
"cfxZones", -- Zones, of course
|
||||
@ -7,6 +7,14 @@ tdz.requiredLibs = {
|
||||
--[[--
|
||||
VERSION HISTORY
|
||||
1.0.0 - Initial version
|
||||
1.0.1 - visible
|
||||
rwFill, rwFrame
|
||||
tdzFill, tdzFrame
|
||||
extend, expand
|
||||
left, right
|
||||
multiple zone support
|
||||
hops detection improvement
|
||||
helo attribute
|
||||
|
||||
--]]--
|
||||
|
||||
@ -18,10 +26,6 @@ tdz.timeoutAfter = 120 -- seconds.
|
||||
-- rwy draw procs
|
||||
--
|
||||
function tdz.rotateXZPolyInRads(thePoly, rads)
|
||||
if not rads then
|
||||
trigger.action.outText("rotateXZPolyInRads (inner): no rads", 30)
|
||||
return
|
||||
end
|
||||
local c = math.cos(rads)
|
||||
local s = math.sin(rads)
|
||||
for idx, p in pairs(thePoly) do
|
||||
@ -33,23 +37,15 @@ function tdz.rotateXZPolyInRads(thePoly, rads)
|
||||
end
|
||||
|
||||
function tdz.rotateXZPolyAroundCenterInRads(thePoly, center, rads)
|
||||
if not rads then
|
||||
trigger.action.outText("rotateXZPolyAroundCenterInRads: no rads", 30)
|
||||
return
|
||||
end
|
||||
local negCtr = {x = -center.x, y = -center.y, z = -center.z}
|
||||
tdz.translatePoly(thePoly, negCtr)
|
||||
if not rads then
|
||||
trigger.action.outText("WHOA! rotateXZPolyAroundCenterInRads: no rads", 30)
|
||||
return
|
||||
end
|
||||
tdz.rotateXZPolyInRads(thePoly, rads)
|
||||
tdz.translatePoly(thePoly, center)
|
||||
end
|
||||
|
||||
function tdz.rotateXZPolyAroundCenterInDegrees(thePoly, center, degrees)
|
||||
tdz.rotateXZPolyAroundCenterInRads(thePoly, center, degrees * 0.0174533)
|
||||
end
|
||||
--function tdz.rotateXZPolyAroundCenterInDegrees(thePoly, center, degrees)
|
||||
-- tdz.rotateXZPolyAroundCenterInRads(thePoly, center, degrees * 0.0174533)
|
||||
--end
|
||||
|
||||
function tdz.translatePoly(thePoly, v) -- straight rot, translate to 0 first
|
||||
for idx, aPoint in pairs(thePoly) do
|
||||
@ -87,6 +83,7 @@ function tdz.createTDZ(theZone)
|
||||
local theBase = dcsCommon.getClosestAirbaseTo(p) -- never get FARPS
|
||||
theZone.base = theBase
|
||||
theZone.baseName = theBase:getName()
|
||||
theZone.helos = false
|
||||
|
||||
-- get closest runway to TDZ
|
||||
-- may get a bit hairy, so let's find a good way
|
||||
@ -102,6 +99,7 @@ function tdz.createTDZ(theZone)
|
||||
end
|
||||
end
|
||||
local bearing = nearestRwy.course * (-1)
|
||||
if bearing < 0 then bearing = bearing + math.pi * 2 end
|
||||
theZone.bearing = bearing
|
||||
rwname = math.floor(dcsCommon.bearing2degrees(bearing)/10 + 0.5) -- nice number
|
||||
degrees = math.floor(dcsCommon.bearing2degrees(bearing) * 10) / 10
|
||||
@ -109,6 +107,11 @@ function tdz.createTDZ(theZone)
|
||||
if degrees > 360 then degrees = degrees - 360 end
|
||||
if rwname < 0 then rwname = rwname + 36 end
|
||||
if rwname > 36 then rwname = rwname - 36 end
|
||||
|
||||
if tdz.verbose or theZone.verbose then
|
||||
trigger.action.outText("TDZ: <" .. theZone.name .. "> attached to airfield " .. theZone.baseName .. " RW main (LEFT) is " .. rwname .. "0", 30)
|
||||
end
|
||||
|
||||
local opName = rwname + 18
|
||||
if opName > 36 then opName = opName - 36 end
|
||||
if rwname < 10 then rwname = "0"..rwname end
|
||||
@ -116,30 +119,45 @@ function tdz.createTDZ(theZone)
|
||||
theZone.rwName = rwname .. "/" .. opName
|
||||
theZone.opName = opName .. "/" .. rwname
|
||||
local rwLen = nearestRwy.length
|
||||
rwLen = rwLen + 2 * theZone:getNumberFromZoneProperty("extend", 0)
|
||||
local rwWid = nearestRwy.width
|
||||
rwWid = rwWid + 2 * theZone:getNumberFromZoneProperty("expand", 0)
|
||||
local pos = nearestRwy.position
|
||||
-- p1 is for distance to centerline calculation, defining a point
|
||||
-- length away in direction bearing, setting up the line
|
||||
-- theZone.rwCenter, theZone.p1
|
||||
theZone.rwCenter = pos
|
||||
local p1 = {x = pos.x + math.cos(bearing) * rwLen, y = 0, z = pos.z + math.sin(bearing) * rwLen}
|
||||
theZone.visible = theZone:getBoolFromZoneProperty("visible", true)
|
||||
theZone.rwP1 = p1
|
||||
theZone.starts = theZone:getNumberFromZoneProperty("starts", 0)
|
||||
theZone.ends = theZone:getNumberFromZoneProperty("ends", 610) -- m = 2000 ft
|
||||
theZone.opposing = theZone:getBoolFromZoneProperty("opposing", true)
|
||||
theZone.left = theZone:getBoolFromZoneProperty("left", true)
|
||||
theZone.right = theZone:getBoolFromZoneProperty("right", true)
|
||||
|
||||
theZone.runwayZone = tdz.calcTDZone(theZone.name .. "-" .. rwname .. "main", pos, rwLen, rwWid, bearing)
|
||||
theZone.runwayZone:drawZone({0, 0, 0, 1}, {0, 0, 0, 0}) -- black outline
|
||||
theZone.rwFrame = theZone:getRGBAVectorFromZoneProperty("rwFrame", {0, 0, 0, 1}) -- black
|
||||
theZone.rwFill = theZone:getRGBAVectorFromZoneProperty("rwFill", {0, 0, 0, 0}) -- nothing
|
||||
if theZone.visible then
|
||||
theZone.runwayZone:drawZone(theZone.rwFrame, theZone.rwFill)
|
||||
end
|
||||
local theTDZone = tdz.calcTDZone(theZone.name .. "-" .. rwname, pos, rwLen, rwWid, bearing, theZone.starts / rwLen, theZone.ends/rwLen)
|
||||
-- to do: mark the various zones of excellence in different colors, or at least the excellent one with more color
|
||||
theTDZone:drawZone({0, 1, 0, 1}, {0, 1, 0, .25})
|
||||
|
||||
theZone.tdzFrame = theZone:getRGBAVectorFromZoneProperty("tdzFrame", {0, 1, 0, 1}) -- green 100%
|
||||
theZone.tdzFill = theZone:getRGBAVectorFromZoneProperty("tdzFill", {0, 1, 0, 0.25}) -- 25% green
|
||||
if theZone.visible and theZone.left then
|
||||
theTDZone:drawZone(theZone.tdzFrame, theZone.tdzFill)
|
||||
end
|
||||
|
||||
theZone.normTDZone = theTDZone
|
||||
if theZone.opposing then
|
||||
theTDZone = tdz.calcTDZone(theZone.name .. "-" .. opName, pos, rwLen, rwWid, bearing + math.pi, theZone.starts / rwLen, theZone.ends/rwLen)
|
||||
theTDZone:drawZone({0, 1, 0, 1}, {0, 1, 0, .25})
|
||||
theZone.opTDZone = theTDZone
|
||||
theZone.opBearing = bearing + math.pi
|
||||
end
|
||||
theTDZone = tdz.calcTDZone(theZone.name .. "-" .. opName, pos, rwLen, rwWid, bearing + math.pi, theZone.starts / rwLen, theZone.ends/rwLen)
|
||||
if theZone.visible and theZone.right then
|
||||
theTDZone:drawZone(theZone.tdzFrame, theZone.tdzFill)
|
||||
end
|
||||
theZone.opTDZone = theTDZone
|
||||
theZone.opBearing = bearing + math.pi
|
||||
if theZone.opBearing > 2 * math.pi then theZone.opBearing = theZone.opBearing - math.pi * 2 end
|
||||
|
||||
if theZone:hasProperty("landed!") then
|
||||
theZone.landedFlag = theZone:getStringFromZoneProperty("landed!", "none")
|
||||
end
|
||||
@ -163,28 +181,68 @@ function tdz.playerLanded(theUnit, playerName)
|
||||
-- make sure unit names match?
|
||||
local entry = tdz.watchlist[playerName]
|
||||
entry.hops = entry.hops + 1 -- uh oh.
|
||||
return
|
||||
end
|
||||
|
||||
-- we may want to filter helicopters
|
||||
|
||||
-- see if we touched down inside of one of our watched zones
|
||||
-- and the directionality (left = landing dir, right = opDir)
|
||||
-- matches
|
||||
local p = theUnit:getPoint()
|
||||
local theGroup = theUnit:getGroup()
|
||||
local cat = theGroup:getCategory() -- DCS 2.9: no issues with groups...
|
||||
local gID = theGroup:getID()
|
||||
local hdg = dcsCommon.getUnitHeading(theUnit)
|
||||
local msg = ""
|
||||
local theZone = nil
|
||||
local opposite = false
|
||||
local dHdg, dOpHdg
|
||||
for idx, aRunway in pairs(tdz.allTdz) do
|
||||
local theRunway = aRunway.runwayZone
|
||||
if theRunway:pointInZone(p) then
|
||||
-- touchdown!
|
||||
theZone = aRunway
|
||||
if theZone.touchDownFlag then
|
||||
theZone.pollFlag(theZone.touchDownFlag, theZone.method)
|
||||
local allowUnit = (cat ~= 1) or aRunway.helos -- 1 = helos
|
||||
if allowUnit and theRunway:pointInZone(p) then -- touched down
|
||||
dHdg = math.abs(aRunway.bearing - hdg) -- 0..Pi
|
||||
dOpHdg = math.abs(aRunway.opBearing - hdg)
|
||||
opposite = false
|
||||
if tdz.verbose or aRunway.verbose then
|
||||
trigger.action.outText("TDZ: landing inside <" .. aRunway.name .. ">, myHdg = <" .. math.floor(hdg * 57.2958) .. ">, dHdg = <" .. dHdg * 57.29 .. ">, dOpHdg = <" .. dOpHdg * 57.29 .. ">, rw = <" .. math.floor(aRunway.bearing * 57.2958) .. ">, rwOp = <" .. math.floor(aRunway.opBearing * 57.2958) .. ">", 30)
|
||||
end
|
||||
|
||||
if dOpHdg < dHdg then
|
||||
opposite = true
|
||||
dHdg = dOpHdg
|
||||
if tdz.verbose or aRunway.verbose then
|
||||
trigger.action.outText("TDZ: landing inside <" .. aRunway.name .. ">, *OPPOSING*", 30)
|
||||
end
|
||||
else
|
||||
if tdz.verbose or aRunway.verbose then
|
||||
trigger.action.outText("TDZ: landing inside <" .. aRunway.name .. ">, ---INLINE---", 30)
|
||||
end
|
||||
end
|
||||
-- see if directionality matches
|
||||
if ((opposite == false) and aRunway.left) or
|
||||
((opposite == true) and aRunway.right)
|
||||
then
|
||||
theZone = aRunway -- FOUND!
|
||||
if theZone.touchDownFlag then
|
||||
theZone.pollFlag(theZone.touchDownFlag, theZone.method)
|
||||
end
|
||||
trigger.action.outTextForGroup(gID, "Touchdown! Come to a FULL STOP for evaluation", 30)
|
||||
else
|
||||
if aRunway.verbose or tdz.verbose then
|
||||
trigger.action.outText("TDZ: ignored touchdown in runway for zone <" .. aRunway.name .. ">, directionality filtered.", 30)
|
||||
end
|
||||
end
|
||||
trigger.action.outTextForGroup(gID, "Touchdown! Come to a FULL STOP for evaluation", 30)
|
||||
end
|
||||
end
|
||||
if not theZone then return end -- no landing eval zone hit
|
||||
if not theZone then
|
||||
if tdz.verbose then
|
||||
trigger.action.outText("TDZ: no touchdown inside zones registered", 30)
|
||||
end
|
||||
return
|
||||
end -- no landing eval zone hit
|
||||
-- Warning: finds the LAST that matches inZone and left/right
|
||||
|
||||
-- start a new watchlist entry
|
||||
local entry = {}
|
||||
@ -200,14 +258,6 @@ function tdz.playerLanded(theUnit, playerName)
|
||||
entry.theZone = theZone
|
||||
|
||||
-- see if we are in main or opposite direction
|
||||
local hdg = dcsCommon.getUnitHeading(theUnit)
|
||||
local dHdg = math.abs(theZone.bearing - hdg) -- 0..Pi
|
||||
local dOpHdg = math.abs(theZone.opBearing - hdg)
|
||||
local opposite = false
|
||||
if dOpHdg < dHdg then
|
||||
opposite = true
|
||||
dHdg = dOpHdg
|
||||
end
|
||||
if dHdg > math.pi * 1.5 then -- > 270+
|
||||
dHdg = dHdg - math.pi * 1.5
|
||||
elseif dHdg > math.pi / 2 then -- > 90+
|
||||
@ -223,12 +273,12 @@ function tdz.playerLanded(theUnit, playerName)
|
||||
local kkm = math.floor(vel * 19.4383) / 10
|
||||
entry.msg = entry.msg .. "\nLanded heading " .. lHdg .. "°, diverging by " .. dHdg .. "° from runway heading, velocity at touchdown " .. vkm .. " kmh/" .. kkm .. " kts, touchdown " .. offcenter .. " m off centerline\n"
|
||||
|
||||
-- inside TDZ?
|
||||
-- inside TDZ? Directionality was already checked
|
||||
local tdZone = theZone.normTDZone
|
||||
if opposite and theZone.opposing then
|
||||
|
||||
if opposite then
|
||||
tdZone = theZone.opTDZone
|
||||
end
|
||||
|
||||
if tdZone:pointInZone(p) then
|
||||
-- yes, how far behind threshold
|
||||
-- project point onto line to see how far inside
|
||||
@ -333,6 +383,11 @@ end
|
||||
-- Start
|
||||
--
|
||||
function tdz.readConfigZone()
|
||||
local theZone = cfxZones.getZoneByName("tdzConfig")
|
||||
if not theZone then
|
||||
theZone = cfxZones.createSimpleZone("tdzConfig")
|
||||
end
|
||||
tdz.verbose = theZone.verbose
|
||||
end
|
||||
|
||||
function tdz.start()
|
||||
@ -362,4 +417,4 @@ end
|
||||
if not tdz.start() then
|
||||
trigger.action.outText("cf/x TDZ aborted: missing libraries", 30)
|
||||
tdz = nil
|
||||
end
|
||||
end
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
autoCSAR = {}
|
||||
autoCSAR.version = "1.1.0"
|
||||
autoCSAR.version = "2.0.0"
|
||||
autoCSAR.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
"cfxZones", -- Zones, of course
|
||||
@ -13,6 +13,7 @@ autoCSAR.trackedEjects = {} -- we start tracking on eject
|
||||
1.0.0 - Initial Version
|
||||
1.1.0 - allow open water CSAR, fake pilot with GRG Soldier
|
||||
- can be disabled by seaCSAR = false
|
||||
2.0.0 - OOP, code clean-up
|
||||
--]]--
|
||||
|
||||
function autoCSAR.removeGuy(args)
|
||||
@ -32,7 +33,6 @@ end
|
||||
function autoCSAR.createNewCSAR(theUnit)
|
||||
if not csarManager then
|
||||
trigger.action.outText("+++aCSAR: CSAR Manager not loaded, aborting", 30)
|
||||
-- return
|
||||
end
|
||||
-- enter with unit from landing_after_eject event
|
||||
-- unit has no group
|
||||
@ -50,12 +50,8 @@ function autoCSAR.createNewCSAR(theUnit)
|
||||
|
||||
-- for later expansion
|
||||
local theGroup = theUnit:getGroup()
|
||||
if theGroup then
|
||||
-- now happens for faked sea CSAR units
|
||||
--trigger.action.outText("We have a group for <" .. theUnit:getName() .. ">", 30)
|
||||
end
|
||||
|
||||
-- now, if theUnit is over open water, this will be killed instantly
|
||||
-- if theUnit is over open water, it is killed instantly by DCS
|
||||
-- and must therefore be replaced with a stand-in
|
||||
local pPoint = theUnit:getPoint()
|
||||
pPoint.y = pPoint.z -- make it getSurfaceType compatible
|
||||
@ -93,7 +89,6 @@ function autoCSAR.createNewCSAR(theUnit)
|
||||
end
|
||||
|
||||
function autoCSAR:onEvent(event)
|
||||
-- trigger.action.outText("autoCSAR: event = " .. event.id, 30)
|
||||
if event.id == 31 then -- landing_after_eject, does not happen at sea
|
||||
-- to prevent double invocations for same process
|
||||
-- check that we are still tracking this ejection
|
||||
@ -105,11 +100,6 @@ function autoCSAR:onEvent(event)
|
||||
return
|
||||
end
|
||||
autoCSAR.createNewCSAR(event.initiator)
|
||||
-- autoCSAR.trackedEjects[event.initiator] = nil
|
||||
-- trigger.action.outText("autocsar: LAE for " .. autoCSAR.trackedEjects[event.initiator], 30)
|
||||
-- else
|
||||
-- trigger.action.outText("autoCSAR: ignored LAE event", 30)
|
||||
-- end
|
||||
end
|
||||
end
|
||||
|
||||
@ -118,11 +108,7 @@ function autoCSAR:onEvent(event)
|
||||
-- see if this happened over open water and immediately
|
||||
-- create a seaCSAR
|
||||
|
||||
--local uid = tonumber(event.initiator:getID())
|
||||
-- trigger.action.outText("autoCSAR: started tracking - chair + pilot", 30)
|
||||
-- autoCSAR.trackedEjects[event.initiator] = "chair+pilot" -- start with this
|
||||
if autoCSAR.isOverWater(event.initiator) then
|
||||
--trigger.action.outText("attempting to walk on water", 30)
|
||||
autoCSAR.createNewCSAR(event.initiator)
|
||||
end
|
||||
|
||||
@ -132,38 +118,6 @@ function autoCSAR:onEvent(event)
|
||||
end
|
||||
end
|
||||
|
||||
--[[--
|
||||
if event.id == 33 then -- separate chair from pilot
|
||||
if event.initiator then
|
||||
--local uid = tonumber(event.initiator:getID())
|
||||
--local pid = tonumber(event.target:getID())
|
||||
--if uid == 0 then
|
||||
--trigger.action.outText("uid = 0, abort tracking", 30)
|
||||
--return
|
||||
--end
|
||||
trigger.action.outText("autoCSAR: track change from seat to pilot <" .. event.target:getName() .. ">", 30)
|
||||
autoCSAR.trackedEjects[event.initiator] = "chair only"
|
||||
autoCSAR.trackedEjects[event.target] = "pilot"
|
||||
end
|
||||
end
|
||||
|
||||
if event.id == 9 then -- pilot dead
|
||||
if event.initiator then
|
||||
--local uid = tonumber(event.initiator:getID())
|
||||
trigger.action.outText("autoCSAR: pilot id=xxx dead", 30)
|
||||
if autoCSAR.trackedEjects[event.initiator] then
|
||||
trigger.action.outText("confirm tracked pilot dead after ejection", 30)
|
||||
if autoCSAR.isOverWater(event.initiator) then
|
||||
trigger.action.outText("attempt to walk on water", 30)
|
||||
autoCSAR.createNewCSAR(event.initiator)
|
||||
end
|
||||
autoCSAR.trackedEjects[event.initiator] = nil
|
||||
end
|
||||
else
|
||||
trigger.action.outText("autoCSAR - no initiator for zed", 30)
|
||||
end
|
||||
end
|
||||
--]]--
|
||||
|
||||
end
|
||||
|
||||
@ -175,18 +129,18 @@ function autoCSAR.readConfigZone()
|
||||
trigger.action.outText("+++aCSAR: NO config zone!", 30)
|
||||
end
|
||||
end
|
||||
|
||||
autoCSAR.redCSAR = cfxZones.getBoolFromZoneProperty(theZone, "red", true)
|
||||
if cfxZones.hasProperty(theZone, "redCSAR") then
|
||||
autoCSAR.redCSAR = cfxZones.getBoolFromZoneProperty(theZone, "redCSAR", true)
|
||||
autoCSAR.verbose = theZone.verbose
|
||||
autoCSAR.redCSAR = theZone:getBoolFromZoneProperty("red", true)
|
||||
if theZone:hasProperty("redCSAR") then
|
||||
autoCSAR.redCSAR = theZone:getBoolFromZoneProperty("redCSAR", true)
|
||||
end
|
||||
|
||||
autoCSAR.blueCSAR = cfxZones.getBoolFromZoneProperty(theZone, "blue", true)
|
||||
if cfxZones.hasProperty(theZone, "blueCSAR") then
|
||||
autoCSAR.blueCSAR = cfxZones.getBoolFromZoneProperty(theZone, "blueCSAR", true)
|
||||
autoCSAR.blueCSAR = theZone:getBoolFromZoneProperty("blue", true)
|
||||
if theZone:hasProperty("blueCSAR") then
|
||||
autoCSAR.blueCSAR = theZone:getBoolFromZoneProperty("blueCSAR", true)
|
||||
end
|
||||
|
||||
autoCSAR.seaCSAR = cfxZones.getBoolFromZoneProperty(theZone, "seaCSAR", true)
|
||||
autoCSAR.seaCSAR = theZone:getBoolFromZoneProperty("seaCSAR", true)
|
||||
|
||||
if autoCSAR.verbose then
|
||||
trigger.action.outText("+++aCSAR: read config", 30)
|
||||
|
||||
@ -166,6 +166,9 @@ function cfxOwnedZones.addOwnedZone(aZone)
|
||||
|
||||
cfxOwnedZones.zones[aZone] = aZone
|
||||
cfxOwnedZones.drawZoneInMap(aZone)
|
||||
if aZone.verbose or cfxOwnedZones.verbose then
|
||||
trigger.action.outText("+++owdZ: detected zone <" .. aZone.name .. ">", 30)
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
@ -326,6 +329,7 @@ function cfxOwnedZones.update()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- count blue units
|
||||
for idx, aGroup in pairs(allBlue) do
|
||||
if Group.isExist(aGroup) then
|
||||
@ -345,6 +349,11 @@ function cfxOwnedZones.update()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if theZone.verbose then
|
||||
trigger.action.outText("+++owdZ: zone <" .. theZone.name .. ">: red inside: <" .. theZone.numRed .. ">, blue inside: <>" .. theZone.numBlue, 30)
|
||||
end
|
||||
|
||||
-- trigger.action.outText(theZone.name .. " blue: " .. theZone.numBlue .. " red " .. theZone.numRed, 30)
|
||||
local lastOwner = theZone.owner
|
||||
local newOwner = 0 -- neutral is default
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxPlayerScore = {}
|
||||
cfxPlayerScore.version = "2.2.0"
|
||||
cfxPlayerScore.version = "3.0.0"
|
||||
cfxPlayerScore.name = "cfxPlayerScore" -- compatibility with flag bangers
|
||||
cfxPlayerScore.badSound = "Death BRASS.wav"
|
||||
cfxPlayerScore.scoreSound = "Quest Snare 3.wav"
|
||||
@ -80,7 +80,12 @@ 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
|
||||
2.2.0 - score flags for red and blue
|
||||
3.0.0 - dmlFlags OOP
|
||||
- redScore#
|
||||
- blueScore#
|
||||
- sceneryObject detection improvements
|
||||
- DCS 2.9 safe
|
||||
|
||||
--]]--
|
||||
|
||||
@ -120,19 +125,19 @@ cfxPlayerScore.landing = 0 -- if > 0 it scores as feat
|
||||
cfxPlayerScore.unit2player = {} -- lookup and reverse look-up
|
||||
|
||||
function cfxPlayerScore.addSafeZone(theZone)
|
||||
theZone.scoreSafe = cfxZones.getCoalitionFromZoneProperty(theZone, "scoreSafe", 0)
|
||||
theZone.scoreSafe = theZone:getCoalitionFromZoneProperty("scoreSafe", 0)
|
||||
table.insert(cfxPlayerScore.safeZones, theZone)
|
||||
end
|
||||
|
||||
function cfxPlayerScore.addKillZone(theZone)
|
||||
theZone.killZone = cfxZones.getCoalitionFromZoneProperty(theZone, "killZone", 0) -- value currently ignored
|
||||
theZone.duet = cfxZones.getBoolFromZoneProperty(theZone, "duet", false) -- does killer have to be in zone?
|
||||
theZone.killZone = theZone:getCoalitionFromZoneProperty("killZone", 0) -- value currently ignored
|
||||
theZone.duet = theZone:getBoolFromZoneProperty("duet", false) -- does killer have to be in zone?
|
||||
table.insert(cfxPlayerScore.killZones, theZone)
|
||||
end
|
||||
|
||||
function cfxPlayerScore.addFeatZone(theZone)
|
||||
theZone.coalition = cfxZones.getCoalitionFromZoneProperty(theZone, "feat", 0) -- who can earn, 0 for all sides
|
||||
theZone.featType = cfxZones.getStringFromZoneProperty(theZone, "featType", "kill")
|
||||
theZone.coalition = theZone:getCoalitionFromZoneProperty("feat", 0) -- who can earn, 0 for all sides
|
||||
theZone.featType = theZone:getStringFromZoneProperty("featType", "kill")
|
||||
theZone.featType = string.upper(theZone.featType)
|
||||
if theZone.featType == "LAND" then theZone.featType = "LANDING" end
|
||||
if theZone.featType ~= "KILL" and
|
||||
@ -141,12 +146,12 @@ function cfxPlayerScore.addFeatZone(theZone)
|
||||
then
|
||||
theZone.featType = "KILL"
|
||||
end
|
||||
theZone.featDesc = cfxZones.getStringFromZoneProperty(theZone, "description", "(some feat)")
|
||||
theZone.featNum = cfxZones.getNumberFromZoneProperty(theZone, "awardLimit", -1) -- how many times this can be awarded, -1 is infinite
|
||||
theZone.ppOnce = cfxZones.getBoolFromZoneProperty(theZone, "awardOnce", false)
|
||||
theZone.featDesc = theZone:getStringFromZoneProperty("description", "(some feat)")
|
||||
theZone.featNum = ctheZone:getNumberFromZoneProperty("awardLimit", -1) -- how many times this can be awarded, -1 is infinite
|
||||
theZone.ppOnce = theZone:getBoolFromZoneProperty("awardOnce", false)
|
||||
theZone.awardedTo = {} -- by player name: true/false
|
||||
table.insert(cfxPlayerScore.featZones, theZone)
|
||||
if cfxPlayerScore.verbose then
|
||||
if cfxPlayerScore.verbose or theZone.verbose then
|
||||
trigger.action.outText("+++ feat zone <" .. theZone.name .. "> read: [" .. theZone.featDesc .. "] for <" .. theZone.featType .. ">", 30)
|
||||
end
|
||||
end
|
||||
@ -284,8 +289,15 @@ function cfxPlayerScore.cat2BaseScore(inCat)
|
||||
end
|
||||
|
||||
function cfxPlayerScore.object2score(inVictim) -- does not have group
|
||||
if not inVictim then return end
|
||||
if not inVictim then return 0 end
|
||||
local inName = inVictim:getName()
|
||||
if dcsCommon.isSceneryObject(inVictim) then
|
||||
local desc = inVictim:getDesc()
|
||||
if not desc then return 0 end
|
||||
-- same as object destruct detector to
|
||||
-- avoid ID changes
|
||||
inName = desc.typeName
|
||||
end
|
||||
if not inName then return 0 end
|
||||
if type(inName) == "number" then
|
||||
inName = tostring(inName)
|
||||
@ -323,7 +335,7 @@ end
|
||||
|
||||
function cfxPlayerScore.unit2score(inUnit)
|
||||
local vicGroup = inUnit:getGroup()
|
||||
local vicCat = vicGroup:getCategory()
|
||||
local vicCat = vicGroup:getCategory()-- group cat, not 2.9 affected
|
||||
local vicType = inUnit:getTypeName()
|
||||
local vicName = inUnit:getName()
|
||||
if type(vicName) == "number" then vicName = tostring(vicName) end
|
||||
@ -879,18 +891,7 @@ function cfxPlayerScore.killDetected(theEvent)
|
||||
-- see which weapon was used. gun kills score 2x
|
||||
local killMeth = ""
|
||||
local killWeap = theEvent.weapon
|
||||
--[[--
|
||||
if killWeap then
|
||||
local killWeapType = killWeap:getCategory()
|
||||
if killWeapType == 0 then
|
||||
killMeth = " with GUNS"
|
||||
scoreMod = scoreMod * 2
|
||||
else
|
||||
local kWeapon = killWeap:getTypeName()
|
||||
killMeth = " with " .. kWeapon
|
||||
end
|
||||
end
|
||||
--]]--
|
||||
|
||||
if pk then
|
||||
vicDesc = victim:getPlayerName() .. " in " .. vicDesc
|
||||
scoreMod = scoreMod * cfxPlayerScore.pkMod
|
||||
@ -1266,6 +1267,17 @@ function cfxPlayerScore.readConfigZone(theZone)
|
||||
theZone, "reportCoalition", false) -- also show coalition score
|
||||
|
||||
cfxPlayerScore.noGrief = cfxZones.getBoolFromZoneProperty(theZone, "noGrief", true) -- noGrief = only add positive score
|
||||
|
||||
if theZone:hasProperty("redScore#") then
|
||||
cfxPlayerScore.redScoreOut = theZone:getStringFromZoneProperty("redScore#")
|
||||
theZone:setFlagValue(cfxPlayerScore.redScoreOut, cfxPlayerScore.coalitionScore[1])
|
||||
end
|
||||
|
||||
if theZone:hasProperty("blueScore#") then
|
||||
cfxPlayerScore.blueScoreOut = theZone:getStringFromZoneProperty("blueScore#")
|
||||
theZone:setFlagValue(cfxPlayerScore.blueScoreOut, cfxPlayerScore.coalitionScore[2])
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
--
|
||||
@ -1304,6 +1316,13 @@ function cfxPlayerScore.loadData()
|
||||
if theData.coalitionScore then
|
||||
cfxPlayerScore.coalitionScore = theData.coalitionScore
|
||||
end
|
||||
if cfxPlayerScore.redScoreOut then
|
||||
cfxZones.setFlagValue(cfxPlayerScore.redScoreOut, cfxPlayerScore.coalitionScore[1], cfxPlayerScore)
|
||||
end
|
||||
if cfxPlayerScore.blueScoreOut then
|
||||
cfxZones.setFlagValue(cfxPlayerScore.blueScoreOut, cfxPlayerScore.coalitionScore[2], cfxPlayerScore)
|
||||
end
|
||||
|
||||
local featData = theData.featData
|
||||
if featData then
|
||||
for name, data in pairs(featData) do
|
||||
@ -1429,6 +1448,14 @@ function cfxPlayerScore.update()
|
||||
end
|
||||
end
|
||||
end
|
||||
-- set output flags if they are set
|
||||
if cfxPlayerScore.redScoreOut then
|
||||
cfxZones.setFlagValue(cfxPlayerScore.redScoreOut, cfxPlayerScore.coalitionScore[1], cfxPlayerScore)
|
||||
end
|
||||
|
||||
if cfxPlayerScore.blueScoreOut then
|
||||
cfxZones.setFlagValue(cfxPlayerScore.blueScoreOut, cfxPlayerScore.coalitionScore[2], cfxPlayerScore)
|
||||
end
|
||||
end
|
||||
--
|
||||
-- start
|
||||
@ -1443,12 +1470,9 @@ function cfxPlayerScore.start()
|
||||
-- read my score table
|
||||
-- identify and process a score table zones
|
||||
local theZone = cfxZones.getZoneByName("playerScoreTable")
|
||||
if not theZone then
|
||||
-- trigger.action.outText("+++scr: no score table!", 30)
|
||||
else
|
||||
if theZone then
|
||||
-- read all into my types registry, replacing whatever is there
|
||||
cfxPlayerScore.typeScore = cfxZones.getAllZoneProperties(theZone)
|
||||
-- trigger.action.outText("+++scr: read score table", 30)
|
||||
end
|
||||
|
||||
-- read score tiggers and values
|
||||
@ -1486,13 +1510,10 @@ function cfxPlayerScore.start()
|
||||
-- now read my config zone
|
||||
local theZone = cfxZones.getZoneByName("playerScoreConfig")
|
||||
if not theZone then
|
||||
-- trigger.action.outText("+++pScr: no config!", 30)
|
||||
theZone = cfxZones.createSimpleZone("playerScoreConfig")
|
||||
end
|
||||
cfxPlayerScore.readConfigZone(theZone)
|
||||
-- trigger.action.outText("+++scr: read config", 30)
|
||||
|
||||
|
||||
|
||||
-- read all scoreSafe zones
|
||||
local safeZones = cfxZones.zonesWithProperty("scoreSafe")
|
||||
for k, aZone in pairs(safeZones) do
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxZones = {}
|
||||
cfxZones.version = "4.0.9"
|
||||
cfxZones.version = "4.0.10"
|
||||
|
||||
-- cf/x zone management module
|
||||
-- reads dcs zones and makes them accessible and mutable
|
||||
@ -65,6 +65,7 @@ cfxZones.version = "4.0.9"
|
||||
- createPolyZone now correctly sets zone.point
|
||||
- createPolyZone now correctly inits dcsOrigin
|
||||
- createCircleZone noew correctly inits dcsOrigin
|
||||
- 4.0.10 - getBoolFromZoneProperty also supports "on" (=true) and "off" (=false)
|
||||
--]]--
|
||||
|
||||
--
|
||||
@ -2380,13 +2381,13 @@ function cfxZones.getBoolFromZoneProperty(theZone, theProperty, defaultVal)
|
||||
if defaultVal == false then
|
||||
-- only go true if exact match to yes or true
|
||||
theBool = false
|
||||
theBool = (p == 'true') or (p == 'yes') or p == "1"
|
||||
theBool = (p == 'true') or (p == 'yes') or (p == "1") or (p == "on")
|
||||
return theBool
|
||||
end
|
||||
|
||||
local theBool = true
|
||||
-- only go false if exactly no or false or "0"
|
||||
theBool = (p ~= 'false') and (p ~= 'no') and (p ~= "0")
|
||||
theBool = (p ~= 'false') and (p ~= 'no') and (p ~= "0") and (p~="off")
|
||||
return theBool
|
||||
end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
civAir = {}
|
||||
civAir.version = "3.0.0"
|
||||
civAir.version = "3.0.1"
|
||||
--[[--
|
||||
1.0.0 initial version
|
||||
1.1.0 exclude list for airfields
|
||||
@ -42,6 +42,9 @@ civAir.version = "3.0.0"
|
||||
new CAM attribute
|
||||
deafault to one Yak-40 if neither
|
||||
support for 'civil_liveries' zone
|
||||
3.0.1 protest option, on by default
|
||||
protest action
|
||||
spawning now works correctly for groupType
|
||||
|
||||
--]]--
|
||||
|
||||
@ -183,6 +186,7 @@ function civAir.readConfigZone()
|
||||
end
|
||||
end
|
||||
|
||||
civAir.protest = theZone:getBoolFromZoneProperty("protest", true)
|
||||
end
|
||||
|
||||
function civAir.addTypesAndLiveries(rawIn)
|
||||
@ -333,7 +337,7 @@ function civAir.getTwoAirbases()
|
||||
end
|
||||
|
||||
function civAir.parkingIsFree(fromWP)
|
||||
-- iterate over all currently registres flights and make
|
||||
-- iterate over all currently registred flights and make
|
||||
-- sure that their location isn't closer than 10m to my new parking
|
||||
local loc = {}
|
||||
loc.x = fromWP.x
|
||||
@ -469,6 +473,7 @@ function civAir.createFlight(name, theTypeString, fromAirfield, toAirfield, inAi
|
||||
dcsCommon.addRoutePointForGroupData(theGroup, toWP)
|
||||
|
||||
-- spawn
|
||||
local groupCat = Group.Category.AIRPLANE
|
||||
local theSpawnedGroup = coalition.addGroup(civAir.owner, groupCat, theGroup) -- 82 is UN peacekeepers
|
||||
if zoneApproach then
|
||||
-- track this flight to target zone
|
||||
@ -576,7 +581,6 @@ function civAir.update()
|
||||
for name, group in pairs (civAir.activePlanes) do
|
||||
if not group:isExist() then
|
||||
table.insert(removeMe, name) -- mark for deletion
|
||||
--Group.destroy(group) -- may break
|
||||
end
|
||||
end
|
||||
|
||||
@ -648,8 +652,45 @@ function civAir.update()
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- onEvent: detect hits / kills
|
||||
--
|
||||
function civAir:onEvent(event)
|
||||
if not civAir.protest then return end
|
||||
|
||||
if not event.initiator then return end
|
||||
local theUnit = event.initiator
|
||||
if not Unit.isExist(theUnit) then return end
|
||||
if event.id == 28 then -- kill event
|
||||
-- check if the unit that was willed is one of mine
|
||||
local target = event.target
|
||||
if not target then return end
|
||||
if not target.getGroup then return end
|
||||
local theGroup = target:getGroup()
|
||||
if not theGroup then return end
|
||||
local theName = theGroup:getName()
|
||||
|
||||
-- see if theName matches one of my flights
|
||||
local theFlight = civAir.activePlanes[theName]
|
||||
if not theFlight then return end
|
||||
|
||||
-- if we get here, a civ plane got killed
|
||||
if not theUnit.getPlayerName then return end
|
||||
local thePlayer = theUnit:getPlayerName()
|
||||
if not thePlayer then return end
|
||||
|
||||
-- now protest!
|
||||
local details = ""
|
||||
if event.weapon and event.weapon:getTypeName() then
|
||||
details = " was attacked with a < .. event.weapon.getTypeName() .. > and"
|
||||
end
|
||||
trigger.action.outText("\n======== N E W S F L A S H ========\nUnarmed civilian flight <" .. theName .. ">" .. details .. " has become a victim of war crime. Sadly, all lives on board of the civil flight were lost.\n\nArmed Forced pilot <" .. thePlayer .. "> and their <" .. theUnit:getTypeName() .. "> were reported lethally armed and weapons hot in the same area; <" .. thePlayer .. "> is ordered to remand to base immediately, pending court-martial.\n\n====== E N D M E S S A G E ======\n", 30)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- misc stuff
|
||||
--
|
||||
function civAir.doDebug(any)
|
||||
trigger.action.outText("cf/x civTraffic debugger.", 30)
|
||||
local desc = "Active Planes:"
|
||||
@ -737,6 +778,9 @@ function civAir.start()
|
||||
-- start outbound tracking
|
||||
civAir.trackOutbound()
|
||||
|
||||
-- sign up for events
|
||||
world.addEventHandler(civAir)
|
||||
|
||||
-- say hi!
|
||||
trigger.action.outText("cf/x civAir v" .. civAir.version .. " started.", 30)
|
||||
return true
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
csarManager = {}
|
||||
csarManager.version = "2.3.1"
|
||||
csarManager.version = "2.3.2"
|
||||
csarManager.verbose = false
|
||||
csarManager.ups = 1
|
||||
|
||||
@ -73,6 +73,7 @@ csarManager.ups = 1
|
||||
- delay asynch OK (message only)
|
||||
- offset zone on randomized soldier
|
||||
- smokeDist
|
||||
- 2.3.2 - DCS 2.9 getCategory() fix
|
||||
|
||||
INTEGRATES AUTOMATICALLY WITH playerScore IF INSTALLED
|
||||
|
||||
@ -320,8 +321,9 @@ function csarManager.preProcessor(event)
|
||||
-- make sure it has an initiator
|
||||
if not event.initiator then return false end -- no initiator
|
||||
local theUnit = event.initiator
|
||||
local cat = theUnit:getCategory()
|
||||
if cat ~= Unit.Category.HELICOPTER then
|
||||
if not theUnit.getDesc then return fase end -- not a unit
|
||||
local cat = theUnit:getDesc().category --theUnit:getCategory()
|
||||
if cat ~= 1 then -- Unit.Category.HELICOPTER
|
||||
return false
|
||||
end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
dcsCommon = {}
|
||||
dcsCommon.version = "2.9.6"
|
||||
dcsCommon.version = "2.9.8"
|
||||
--[[-- VERSION HISTORY
|
||||
2.2.6 - compassPositionOfARelativeToB
|
||||
- clockPositionOfARelativeToB
|
||||
@ -176,7 +176,8 @@ dcsCommon.version = "2.9.6"
|
||||
2.9.4 - new bearing2degrees()
|
||||
2.9.5 - distanceOfPointPToLineXZ(p, p1, p2)
|
||||
2.9.6 - new addToTableIfNew()
|
||||
|
||||
2.9.7 - createSimpleRoutePointData also accepts speed
|
||||
2.9.8 - isSceneryObject(theUnit) optimization, DCS 2.9 safe
|
||||
--]]--
|
||||
|
||||
-- dcsCommon is a library of common lua functions
|
||||
@ -1525,7 +1526,8 @@ dcsCommon.version = "2.9.6"
|
||||
return rp
|
||||
end
|
||||
|
||||
function dcsCommon.createSimpleRoutePointData(p, alt)
|
||||
function dcsCommon.createSimpleRoutePointData(p, alt, speed)
|
||||
if not speed then speed = 133 end
|
||||
if not alt then alt = 8000 end -- 24'000 feet
|
||||
local rp = {}
|
||||
rp.x = p.x
|
||||
@ -1534,7 +1536,7 @@ dcsCommon.version = "2.9.6"
|
||||
rp.action = "Turning Point"
|
||||
rp.type = "Turning Point"
|
||||
|
||||
rp.speed = 133; -- in m/s? If so, that's 360 km/h
|
||||
rp.speed = speed; -- in m/s? If so, that's 360 km/h
|
||||
rp.alt_type = "BARO"
|
||||
return rp
|
||||
end
|
||||
@ -2877,7 +2879,8 @@ end
|
||||
--
|
||||
function dcsCommon.isSceneryObject(theUnit)
|
||||
if not theUnit then return false end
|
||||
return theUnit.getCoalition == nil -- scenery objects do not return a coalition
|
||||
return Object.getCategory(theUnit) == 5
|
||||
-- return theUnit.getCoalition == nil -- scenery objects do not return a coalition
|
||||
end
|
||||
|
||||
function dcsCommon.isTroopCarrierType(theType, carriers)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
pulseFlags = {}
|
||||
pulseFlags.version = "2.0.0"
|
||||
pulseFlags.version = "2.0.1"
|
||||
pulseFlags.verbose = false
|
||||
pulseFlags.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
@ -41,7 +41,7 @@ pulseFlags.requiredLibs = {
|
||||
- 1.3.3 removed 'pulsing' when pausing, so we can restart
|
||||
- 2.0.0 dmlZones / OOP
|
||||
using method on all outputs
|
||||
|
||||
- 2.0.1 activateZoneFlag now works correctly
|
||||
|
||||
--]]--
|
||||
|
||||
@ -238,7 +238,7 @@ function pulseFlags.update()
|
||||
|
||||
-- see if we got a pause or activate command
|
||||
-- activatePulseFlag
|
||||
if aZone:testZoneFlag(activatePulseFlag, aZone.pulseTriggerMethod, "lastActivateValue") then
|
||||
if aZone:testZoneFlag(aZone.activatePulseFlag, aZone.pulseTriggerMethod, "lastActivateValue") then
|
||||
if pulseFlags.verbose or aZone.verbose then
|
||||
trigger.action.outText("+++pulF: activating <" .. aZone.name .. ">", 30)
|
||||
end
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
-- theDebugger
|
||||
debugger = {}
|
||||
debugger.version = "1.1.2"
|
||||
debugger.version = "2.0.0"
|
||||
debugDemon = {}
|
||||
debugDemon.version = "1.1.2"
|
||||
debugDemon.version = "2.0.0"
|
||||
|
||||
debugger.verbose = false
|
||||
debugger.ups = 4 -- every 0.25 second
|
||||
@ -23,7 +23,12 @@ debugger.log = ""
|
||||
- save <name>
|
||||
1.1.1 - warning when trying to set a flag to a non-int
|
||||
1.1.2 - remove command
|
||||
|
||||
2.0.0 - dmlZones OOP
|
||||
- eventmon command
|
||||
- all, off, event #
|
||||
- standard events
|
||||
- adding events
|
||||
- events? attribute from any zone
|
||||
|
||||
--]]--
|
||||
|
||||
@ -39,7 +44,68 @@ debugger.debugZones = {}
|
||||
debugger.debugUnits = {}
|
||||
debugger.debugGroups = {}
|
||||
debugger.debugObjects = {}
|
||||
debugger.showEvents = {}
|
||||
|
||||
debugDemon.eventList = {
|
||||
["0"] = "S_EVENT_INVALID = 0",
|
||||
["1"] = "S_EVENT_SHOT = 1",
|
||||
["2"] = "S_EVENT_HIT = 2",
|
||||
["3"] = "S_EVENT_TAKEOFF = 3",
|
||||
["4"] = "S_EVENT_LAND = 4",
|
||||
["5"] = "S_EVENT_CRASH = 5",
|
||||
["6"] = "S_EVENT_EJECTION = 6",
|
||||
["7"] = "S_EVENT_REFUELING = 7",
|
||||
["8"] = "S_EVENT_DEAD = 8",
|
||||
["9"] = "S_EVENT_PILOT_DEAD = 9",
|
||||
["10"] = "S_EVENT_BASE_CAPTURED = 10",
|
||||
["11"] = "S_EVENT_MISSION_START = 11",
|
||||
["12"] = "S_EVENT_MISSION_END = 12",
|
||||
["13"] = "S_EVENT_TOOK_CONTROL = 13",
|
||||
["14"] = "S_EVENT_REFUELING_STOP = 14",
|
||||
["15"] = "S_EVENT_BIRTH = 15",
|
||||
["16"] = "S_EVENT_HUMAN_FAILURE = 16",
|
||||
["17"] = "S_EVENT_DETAILED_FAILURE = 17",
|
||||
["18"] = "S_EVENT_ENGINE_STARTUP = 18",
|
||||
["19"] = "S_EVENT_ENGINE_SHUTDOWN = 19",
|
||||
["20"] = "S_EVENT_PLAYER_ENTER_UNIT = 20",
|
||||
["21"] = "S_EVENT_PLAYER_LEAVE_UNIT = 21",
|
||||
["22"] = "S_EVENT_PLAYER_COMMENT = 22",
|
||||
["23"] = "S_EVENT_SHOOTING_START = 23",
|
||||
["24"] = "S_EVENT_SHOOTING_END = 24",
|
||||
["25"] = "S_EVENT_MARK_ADDED = 25",
|
||||
["26"] = "S_EVENT_MARK_CHANGE = 26",
|
||||
["27"] = "S_EVENT_MARK_REMOVED = 27",
|
||||
["28"] = "S_EVENT_KILL = 28",
|
||||
["29"] = "S_EVENT_SCORE = 29",
|
||||
["30"] = "S_EVENT_UNIT_LOST = 30",
|
||||
["31"] = "S_EVENT_LANDING_AFTER_EJECTION = 31",
|
||||
["32"] = "S_EVENT_PARATROOPER_LENDING = 32",
|
||||
["33"] = "S_EVENT_DISCARD_CHAIR_AFTER_EJECTION = 33",
|
||||
["34"] = "S_EVENT_WEAPON_ADD = 34",
|
||||
["35"] = "S_EVENT_TRIGGER_ZONE = 35",
|
||||
["36"] = "S_EVENT_LANDING_QUALITY_MARK = 36",
|
||||
["37"] = "S_EVENT_BDA = 37",
|
||||
["38"] = "S_EVENT_AI_ABORT_MISSION = 38",
|
||||
["39"] = "S_EVENT_DAYNIGHT = 39",
|
||||
["40"] = "S_EVENT_FLIGHT_TIME = 40",
|
||||
["41"] = "S_EVENT_PLAYER_SELF_KILL_PILOT = 41",
|
||||
["42"] = "S_EVENT_PLAYER_CAPTURE_AIRFIELD = 42",
|
||||
["43"] = "S_EVENT_EMERGENCY_LANDING = 43",
|
||||
["44"] = "S_EVENT_UNIT_CREATE_TASK = 44",
|
||||
["45"] = "S_EVENT_UNIT_DELETE_TASK = 45",
|
||||
["46"] = "S_EVENT_SIMULATION_START = 46",
|
||||
["47"] = "S_EVENT_WEAPON_REARM = 47",
|
||||
["48"] = "S_EVENT_WEAPON_DROP = 48",
|
||||
["49"] = "S_EVENT_UNIT_TASK_TIMEOUT = 49",
|
||||
["50"] = "S_EVENT_UNIT_TASK_STAGE = 50",
|
||||
["51"] = "S_EVENT_MAC_SUBTASK_SCORE = 51",
|
||||
["52"] = "S_EVENT_MAC_EXTRA_SCORE = 52",
|
||||
["53"] = "S_EVENT_MISSION_RESTART = 53",
|
||||
["54"] = "S_EVENT_MISSION_WINNER = 54",
|
||||
["55"] = "S_EVENT_POSTPONED_TAKEOFF = 55",
|
||||
["56"] = "S_EVENT_POSTPONED_LAND = 56",
|
||||
["57"] = "S_EVENT_MAX = 57",
|
||||
}
|
||||
--
|
||||
-- Logging & saving
|
||||
--
|
||||
@ -110,13 +176,13 @@ end
|
||||
--
|
||||
function debugger.createDebuggerWithZone(theZone)
|
||||
-- watchflag input trigger
|
||||
theZone.debugInputMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
|
||||
if cfxZones.hasProperty(theZone, "debugTriggerMethod") then
|
||||
theZone.debugInputMethod = cfxZones.getStringFromZoneProperty(theZone, "debugTriggerMethod", "change")
|
||||
elseif cfxZones.hasProperty(theZone, "inputMethod") then
|
||||
theZone.debugInputMethod = cfxZones.getStringFromZoneProperty(theZone, "inputMethod", "change")
|
||||
elseif cfxZones.hasProperty(theZone, "sayWhen") then
|
||||
theZone.debugInputMethod = cfxZones.getStringFromZoneProperty(theZone, "sayWhen", "change")
|
||||
theZone.debugInputMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
|
||||
if theZone.hasProperty("debugTriggerMethod") then
|
||||
theZone.debugInputMethod = theZone:getStringFromZoneProperty("debugTriggerMethod", "change")
|
||||
elseif theZone:hasProperty("inputMethod") then
|
||||
theZone.debugInputMethod = theZone:getStringFromZoneProperty(theZone, "inputMethod", "change")
|
||||
elseif theZone:hasProperty("sayWhen") then
|
||||
theZone.debugInputMethod = theZone:getStringFromZoneProperty("sayWhen", "change")
|
||||
end
|
||||
|
||||
-- say who we are and what we are monitoring
|
||||
@ -125,13 +191,13 @@ function debugger.createDebuggerWithZone(theZone)
|
||||
end
|
||||
|
||||
-- read main debug array
|
||||
local theFlags = cfxZones.getStringFromZoneProperty(theZone, "debug?", "<none>")
|
||||
local theFlags = theZone:getStringFromZoneProperty("debug?", "<none>")
|
||||
-- now, create an array from that
|
||||
local flagArray = cfxZones.flagArrayFromString(theFlags)
|
||||
local valueArray = {}
|
||||
-- now establish current values
|
||||
for idx, aFlag in pairs(flagArray) do
|
||||
local fVal = cfxZones.getFlagValue(aFlag, theZone)
|
||||
local fVal = theZone:getFlagValue(aFlag)
|
||||
if debugger.verbose or theZone.verbose then
|
||||
debugger.outText(" monitoring flag <" .. aFlag .. ">, inital value is <" .. fVal .. ">", 30)
|
||||
end
|
||||
@ -140,28 +206,44 @@ function debugger.createDebuggerWithZone(theZone)
|
||||
theZone.flagArray = flagArray
|
||||
theZone.valueArray = valueArray
|
||||
|
||||
|
||||
|
||||
-- DML output method
|
||||
theZone.debugOutputMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
|
||||
if cfxZones.hasProperty(theZone, "outputMethod") then
|
||||
theZone.debugOutputMethod = cfxZones.getStringFromZoneProperty(theZone, "outputMethod", "inc")
|
||||
theZone.debugOutputMethod = theZone:getStringFromZoneProperty("method", "inc")
|
||||
if theZone:hasProperty("outputMethod") then
|
||||
theZone.debugOutputMethod = theZone:getStringFromZoneProperty("outputMethod", "inc")
|
||||
end
|
||||
if cfxZones.hasProperty(theZone, "debugMethod") then
|
||||
theZone.debugOutputMethod = cfxZones.getStringFromZoneProperty(theZone, "debugMethod", "inc")
|
||||
if theZone:hasProperty("debugMethod") then
|
||||
theZone.debugOutputMethod = theZone:getStringFromZoneProperty("debugMethod", "inc")
|
||||
end
|
||||
|
||||
-- notify!
|
||||
if cfxZones.hasProperty(theZone, "notify!") then
|
||||
theZone.debugNotify = cfxZones.getStringFromZoneProperty(theZone, "notify!", "<none>")
|
||||
if theZone:hasProperty("notify!") then
|
||||
theZone.debugNotify = theZone:getStringFromZoneProperty("notify!", "<none>")
|
||||
end
|
||||
|
||||
-- debug message, can use all messenger vals plus <f> for flag name
|
||||
-- we use out own default
|
||||
-- with <f> meaning flag name, <p> previous value, <c> current value
|
||||
theZone.debugMsg = cfxZones.getStringFromZoneProperty(theZone, "debugMsg", "---debug: <t> -- Flag <f> changed from <p> to <c> [<z>]")
|
||||
|
||||
|
||||
theZone.debugMsg = theZone:getStringFromZoneProperty("debugMsg", "---debug: <t> -- Flag <f> changed from <p> to <c> [<z>]")
|
||||
end
|
||||
|
||||
function debugger.createEventMonWithZone(theZone)
|
||||
local theFlags = theZone:getStringFromZoneProperty("events?", "<none>")
|
||||
local flagArray = cfxZones.flagArrayFromString(theFlags)
|
||||
local valueArray = {}
|
||||
-- now establish current values
|
||||
if debugger.verbose or theZone.verbose then
|
||||
debugger.outText("*** monitoring events defined in <" .. theZone.name .. ">:", 30)
|
||||
end
|
||||
for idx, aFlag in pairs(flagArray) do
|
||||
|
||||
local evt = tonumber(aFlag)
|
||||
if evt and (debugger.verbose or theZone.verbose) then
|
||||
if evt < 0 then evt = 0 end
|
||||
if evt > 57 then evt = 57 end
|
||||
debugger.showEvents[evt] = debugDemon.eventList[tostring(evt)]
|
||||
debugger.outText(" monitoring event <" .. debugger.showEvents[evt] .. ">", 30)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
@ -457,6 +539,17 @@ function debugger.start()
|
||||
debugger.outText("***Warning: Zone <" .. aZone.name .. "> has a 'debug' flag. Are you perhaps missing a '?'", 30)
|
||||
end
|
||||
|
||||
local attrZones = cfxZones.getZonesWithAttributeNamed("events?")
|
||||
for k, aZone in pairs(attrZones) do
|
||||
debugger.createEventMonWithZone(aZone) -- process attributes
|
||||
end
|
||||
|
||||
local attrZones = cfxZones.getZonesWithAttributeNamed("events")
|
||||
for k, aZone in pairs(attrZones) do
|
||||
debugger.outText("***Warning: Zone <" .. aZone.name .. "> has a 'debug' flag. Are you perhaps missing a '?'", 30)
|
||||
end
|
||||
-- events
|
||||
|
||||
-- say if we are active
|
||||
if debugger.verbose then
|
||||
if debugger.active then
|
||||
@ -493,7 +586,8 @@ debugDemon.verbose = false
|
||||
Version History
|
||||
1.0.0 - initial version
|
||||
1.1.0 - save command, requires persistence
|
||||
|
||||
2.0.0 - eventmon
|
||||
- dml zones OOP
|
||||
--]]--
|
||||
|
||||
debugDemon.requiredLibs = {
|
||||
@ -518,6 +612,10 @@ end
|
||||
-- very simple: look if text begins with special sequence, and if so,
|
||||
-- call the command processor.
|
||||
function debugDemon:onEvent(theEvent)
|
||||
-- first order of business: call the event monitor
|
||||
debugDemon.doEventMon(theEvent)
|
||||
|
||||
-- now process our own
|
||||
-- while we can hook into any of the three events,
|
||||
-- we curently only utilize CHANGE Mark
|
||||
if not (theEvent.id == world.event.S_EVENT_MARK_ADDED) and
|
||||
@ -655,6 +753,10 @@ debugger.outText("*** debugger: commands are:" ..
|
||||
"\n " .. debugDemon.markOfDemon .. "compare -- compare snapshot flag values with current" ..
|
||||
"\n " .. debugDemon.markOfDemon .. "note <your note> -- add <your note> to the text log" ..
|
||||
"\n\n " .. debugDemon.markOfDemon .. "remove <group/unit/object name> -- remove named item from mission" ..
|
||||
|
||||
"\n\n " .. debugDemon.markOfDemon .. "eventmon [all | off | <number> | ?] -- show events for all | none | event <number> | list" ..
|
||||
"\n\n " .. debugDemon.markOfDemon .. "q <Lua Var> -- Query value of Lua variable <Lua Var>" ..
|
||||
"\n " .. debugDemon.markOfDemon .. "w <Lua Var> [=] <Lua Value> -- Write <Lua Value> to variable <Lua Var>" ..
|
||||
"\n\n " .. debugDemon.markOfDemon .. "start -- starts debugger" ..
|
||||
"\n " .. debugDemon.markOfDemon .. "stop -- stop debugger" ..
|
||||
|
||||
@ -893,17 +995,7 @@ function debugDemon.processSnapCommand(args, event)
|
||||
end
|
||||
|
||||
-- set up snapshot
|
||||
local snapshot = debugDemon.createSnapshot(allObservers) --{}
|
||||
--[[--
|
||||
for idx, theZone in pairs(allObservers) do
|
||||
-- iterate each observer
|
||||
for idy, flagName in pairs (theZone.flagArray) do
|
||||
local fullName = cfxZones.expandFlagName(flagName, theZone)
|
||||
local fVal = trigger.misc.getUserFlag(fullName)
|
||||
snapshot[fullName] = fVal
|
||||
end
|
||||
end
|
||||
--]]--
|
||||
local snapshot = debugDemon.createSnapshot(allObservers)
|
||||
|
||||
local sz = dcsCommon.getSizeOfTable(snapshot)
|
||||
debugDemon.snapshot = snapshot
|
||||
@ -1176,6 +1268,141 @@ function debugDemon.processRemoveCommand(args, event)
|
||||
debugger.outText("*** remove: did not find anything called <" .. aName .. "> to remove", 30)
|
||||
return true
|
||||
end
|
||||
|
||||
function debugDemon.doEventMon(theEvent)
|
||||
if not theEvent then return end
|
||||
local ID = theEvent.id
|
||||
if debugger.showEvents[ID] then
|
||||
-- we show this event
|
||||
m = "*** event <" .. debugger.showEvents[ID] .. ">"
|
||||
-- see if we have initiator
|
||||
if theEvent.initiator then
|
||||
local theUnit = theEvent.initiator
|
||||
if Unit.isExist(theUnit) then
|
||||
m = m .. " for "
|
||||
if theUnit.getPlayerName and theUnit:getPlayerName() then
|
||||
m = m .. "player = " .. theUnit:getPlayerName() .. " in "
|
||||
end
|
||||
m = m .. "unit <" .. theUnit:getName() .. ">"
|
||||
end
|
||||
end
|
||||
debugger.outText(m, 30)
|
||||
end
|
||||
end
|
||||
|
||||
function debugDemon.processEventMonCommand(args, event)
|
||||
-- turn event monito on/off
|
||||
-- syntax: -eventmon on|off
|
||||
local aParam = dcsCommon.trim(event.remainder)
|
||||
if not aParam or aParam:len() < 1 then
|
||||
aParam = "all"
|
||||
end
|
||||
aParam = string.upper(aParam)
|
||||
evtNum = tonumber(aParam)
|
||||
if aParam == "ON" or aParam == "ALL" then
|
||||
-- debugger.eventmon = true
|
||||
debugger.outText("*** eventmon: turned ON, showing ALL events", 30)
|
||||
local events = {}
|
||||
for idx,evt in pairs(debugDemon.eventList) do
|
||||
events[tonumber(idx)] = evt
|
||||
end
|
||||
debugger.showEvents = events
|
||||
elseif evtNum then -- add the numbered to
|
||||
debugger.eventmon = false
|
||||
if evtNum <= 0 then evtNum = 0 end
|
||||
if evtNum >= 57 then evtNum = 35 end
|
||||
debugger.showEvents[evtNum] = debugDemon.eventList[tostring(evtNum)]
|
||||
debugger.outText("*** eventmon: added event <" .. debugger.showEvents[evtNum] .. ">", 30)
|
||||
elseif aParam == "OFF" then
|
||||
debugger.showEvents = {}
|
||||
debugger.outText("*** eventmon: removed all events from monitor list", 30)
|
||||
elseif aParam == "?" then
|
||||
local m = "*** eventmon: currently tracking these events:"
|
||||
for idx, evt in pairs(debugger.showEvents) do
|
||||
m = m .. "\n" .. evt
|
||||
end
|
||||
debugger.outText(m .. "\n*** end of list", 30)
|
||||
else
|
||||
debugger.outText("*** eventmon: unknown parameter <" .. event.remainder .. ">", 30)
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
--
|
||||
-- read and write directly to Lua tables
|
||||
--
|
||||
|
||||
function debugDemon.processQueryCommand(args, event)
|
||||
-- syntax -q <name> with name a (qualified) Lua table reference
|
||||
local theName = args[1]
|
||||
-- local p = args [2]
|
||||
-- trigger.action.outText("args1 = " .. theName, 30)
|
||||
-- if args[2] then trigger.action.outText("param = " .. args[2], 30) end
|
||||
if not theName then
|
||||
debugger.outText("*** q: missing Lua table/element name.", 30)
|
||||
return false -- allows correction
|
||||
end
|
||||
theName = dcsCommon.stringRemainsStartingWith(event.remainder, theName)
|
||||
|
||||
-- put this into a string, and execute it
|
||||
local exec = "return " .. theName
|
||||
local f = loadstring(exec)
|
||||
local res
|
||||
if pcall(f) then
|
||||
res = f()
|
||||
if type(res) == "boolean" then
|
||||
res = "[BOOL FALSE]"
|
||||
if res then res = "[BOOL TRUE]" end
|
||||
elseif type(res) == "table" then res = "[Lua Table]"
|
||||
elseif type(res) == "nil" then res = "[NIL]"
|
||||
elseif type(res) == "function" then res = "[Lua Function]"
|
||||
elseif type(res) == "number" or type(res) == "string" then
|
||||
res = res .. " (a " .. type(res) .. ")"
|
||||
else res = "[Lua " .. type(res) .. "]"
|
||||
end
|
||||
else
|
||||
res = "[Lua error]"
|
||||
end
|
||||
|
||||
debugger.outText("[" .. dcsCommon.nowString() .. "] <" .. theName .. "> = ".. res, 30)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function debugDemon.processWriteCommand(args, event)
|
||||
-- syntax -w <name> <value> with name a (qualified) Lua table reference and value a Lua value (including strings, with quotes of course). {} means an empty set etc. you CAN call into DCS MSE with this, and create a lot of havoc.
|
||||
-- also, allow "=" semantic, -w p = {x=1, y=2}
|
||||
|
||||
local theName = args[1]
|
||||
if not theName then
|
||||
debugger.outText("*** w: missing Lua table/element name.", 30)
|
||||
return false -- allows correction
|
||||
end
|
||||
local param = args [2]
|
||||
if param == "=" then param = args[3] end
|
||||
if not param then
|
||||
debugger.outText("*** w: missing value to set to")
|
||||
return false
|
||||
end
|
||||
|
||||
param = dcsCommon.stringRemainsStartingWith(event.remainder, param)
|
||||
|
||||
-- put this into a string, and execute it
|
||||
local exec = theName .. " = " .. param
|
||||
local f = loadstring(exec)
|
||||
local res
|
||||
if pcall(f) then
|
||||
res = "<" .. theName .. "> set to <" .. param .. ">"
|
||||
else
|
||||
res = "[Unable to set - Lua error]"
|
||||
end
|
||||
|
||||
debugger.outText("[" .. dcsCommon.nowString() .. "] " .. res, 30)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- init and start
|
||||
--
|
||||
@ -1246,7 +1473,10 @@ function debugDemon.init()
|
||||
debugDemon.addCommndProcessor("help", debugDemon.processHelpCommand)
|
||||
|
||||
debugDemon.addCommndProcessor("remove", debugDemon.processRemoveCommand)
|
||||
|
||||
|
||||
debugDemon.addCommndProcessor("eventmon", debugDemon.processEventMonCommand)
|
||||
debugDemon.addCommndProcessor("q", debugDemon.processQueryCommand)
|
||||
debugDemon.addCommndProcessor("w", debugDemon.processWriteCommand)
|
||||
return true
|
||||
end
|
||||
|
||||
@ -1272,7 +1502,7 @@ end
|
||||
if debugDemon.init() then
|
||||
debugDemon.start()
|
||||
else
|
||||
trigger.action.outText("*** interactive flag debugger failed to initialize.", 30)
|
||||
trigger.action.outText("*** interactive debugger failed to initialize.", 30)
|
||||
debugDemon = {}
|
||||
end
|
||||
|
||||
@ -1287,7 +1517,9 @@ end
|
||||
-q x.y returns table, 12 elements
|
||||
-q a.b.x returns number 12
|
||||
-q d.e.f returns string "asdasda..."
|
||||
-q sada reuturs <nil>
|
||||
-q sada returs <nil>
|
||||
|
||||
- xref: which zones/attributes reference a flag, g.g. '-xref go'
|
||||
|
||||
- dml version can config to start with events list, e.g. 1, 4, 7
|
||||
--]]--
|
||||
|
||||
BIN
tutorial & demo missions/demo - Landing Lessons.miz
Normal file
BIN
tutorial & demo missions/demo - Landing Lessons.miz
Normal file
Binary file not shown.
BIN
tutorial & demo missions/demo - player score to win.miz
Normal file
BIN
tutorial & demo missions/demo - player score to win.miz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user