diff --git a/Doc/DML Documentation.pdf b/Doc/DML Documentation.pdf index 0265fd8..4a9a61b 100644 Binary files a/Doc/DML Documentation.pdf and b/Doc/DML Documentation.pdf differ diff --git a/Doc/DML Quick Reference.pdf b/Doc/DML Quick Reference.pdf index 6e057af..f5734cf 100644 Binary files a/Doc/DML Quick Reference.pdf and b/Doc/DML Quick Reference.pdf differ diff --git a/modules/TDZ.lua b/modules/TDZ.lua index 852854f..4549abb 100644 --- a/modules/TDZ.lua +++ b/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 \ No newline at end of file +end diff --git a/modules/autoCSAR.lua b/modules/autoCSAR.lua index a856961..d02e469 100644 --- a/modules/autoCSAR.lua +++ b/modules/autoCSAR.lua @@ -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) diff --git a/modules/cfxOwnedZones.lua b/modules/cfxOwnedZones.lua index afc0c8a..4cabbc4 100644 --- a/modules/cfxOwnedZones.lua +++ b/modules/cfxOwnedZones.lua @@ -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 diff --git a/modules/cfxPlayerScore.lua b/modules/cfxPlayerScore.lua index a218352..161f9bb 100644 --- a/modules/cfxPlayerScore.lua +++ b/modules/cfxPlayerScore.lua @@ -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 diff --git a/modules/cfxZones.lua b/modules/cfxZones.lua index 9d7a568..d352bab 100644 --- a/modules/cfxZones.lua +++ b/modules/cfxZones.lua @@ -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 diff --git a/modules/civAir.lua b/modules/civAir.lua index 7461c7a..7de8f10 100644 --- a/modules/civAir.lua +++ b/modules/civAir.lua @@ -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 diff --git a/modules/csarManager2.lua b/modules/csarManager2.lua index 3cde9cb..ba5d2e0 100644 --- a/modules/csarManager2.lua +++ b/modules/csarManager2.lua @@ -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 diff --git a/modules/dcsCommon.lua b/modules/dcsCommon.lua index 8054dc5..c7e27d6 100644 --- a/modules/dcsCommon.lua +++ b/modules/dcsCommon.lua @@ -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) diff --git a/modules/pulseFlags.lua b/modules/pulseFlags.lua index ab293f8..cdb2ac5 100644 --- a/modules/pulseFlags.lua +++ b/modules/pulseFlags.lua @@ -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 diff --git a/modules/theDebugger.lua b/modules/theDebugger.lua index 5bafaba..2c9a8cb 100644 --- a/modules/theDebugger.lua +++ b/modules/theDebugger.lua @@ -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 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?", "") + local theFlags = theZone:getStringFromZoneProperty("debug?", "") -- 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!", "") + if theZone:hasProperty("notify!") then + theZone.debugNotify = theZone:getStringFromZoneProperty("notify!", "") end -- debug message, can use all messenger vals plus for flag name -- we use out own default -- with meaning flag name,

previous value, current value - theZone.debugMsg = cfxZones.getStringFromZoneProperty(theZone, "debugMsg", "---debug: -- Flag changed from

to []") - - + theZone.debugMsg = theZone:getStringFromZoneProperty("debugMsg", "---debug: -- Flag changed from

to []") +end + +function debugger.createEventMonWithZone(theZone) + local theFlags = theZone:getStringFromZoneProperty("events?", "") + 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 -- add to the text log" .. "\n\n " .. debugDemon.markOfDemon .. "remove -- remove named item from mission" .. + + "\n\n " .. debugDemon.markOfDemon .. "eventmon [all | off | | ?] -- show events for all | none | event | list" .. + "\n\n " .. debugDemon.markOfDemon .. "q -- Query value of Lua variable " .. + "\n " .. debugDemon.markOfDemon .. "w [=] -- Write to variable " .. "\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 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 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 + -q sada returs - 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 --]]-- diff --git a/tutorial & demo missions/demo - Landing Lessons.miz b/tutorial & demo missions/demo - Landing Lessons.miz new file mode 100644 index 0000000..2118c0d Binary files /dev/null and b/tutorial & demo missions/demo - Landing Lessons.miz differ diff --git a/tutorial & demo missions/demo - player score to win.miz b/tutorial & demo missions/demo - player score to win.miz new file mode 100644 index 0000000..4dc8745 Binary files /dev/null and b/tutorial & demo missions/demo - player score to win.miz differ