diff --git a/Doc/DML Documentation.pdf b/Doc/DML Documentation.pdf index 5351ee3..82a95c3 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 594d763..4d03ae5 100644 Binary files a/Doc/DML Quick Reference.pdf and b/Doc/DML Quick Reference.pdf differ diff --git a/modules/cloneZone.lua b/modules/cloneZone.lua index 492d924..9cf33d6 100644 --- a/modules/cloneZone.lua +++ b/modules/cloneZone.lua @@ -1,5 +1,5 @@ cloneZones = {} - cloneZones.version = "1.4.6" + cloneZones.version = "1.4.7" cloneZones.verbose = false cloneZones.requiredLibs = { "dcsCommon", -- always @@ -45,6 +45,7 @@ 1.4.5 - randomizeLoc, rndLoc keyword - cargo manager integration - pass cargo objects when present 1.4.6 - removed some verbosity for spawned aircraft with airfields on their routes + 1.4.7 - DML watchflag and DML Flag polish, method-->cloneMethod --]]-- @@ -236,7 +237,6 @@ theZone.lastDeSpawnValue = cfxZones.getFlagValue(theZone.deSpawnFlag, theZone) end - -- to be deprecated theZone.onStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", false) theZone.moveRoute = cfxZones.getBoolFromZoneProperty(theZone, "moveRoute", false) @@ -252,7 +252,10 @@ theZone.emptyBangFlag = cfxZones.getStringFromZoneProperty(theZone, "empty!", "") -- note string on number default end - theZone.method = cfxZones.getStringFromZoneProperty(theZone, "method", "inc") + theZone.cloneMethod = cfxZones.getStringFromZoneProperty(theZone, "cloneMethod", "inc") + if cfxZones.hasProperty(theZone, "method") then + theZone.cloneMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc") -- note string on number default + end if cfxZones.hasProperty(theZone, "masterOwner") then theZone.masterOwner = cfxZones.getStringFromZoneProperty(theZone, "masterOwner", "") @@ -1010,7 +1013,7 @@ end if aZone.emptyBangFlag then - cfxZones.pollFlag(aZone.emptyBangFlag, aZone.method, aZone) + cfxZones.pollFlag(aZone.emptyBangFlag, aZone.cloneMethod, aZone) if cloneZones.verbose then trigger.action.outText("+++clnZ: bang! on " .. aZone.emptyBangFlag, 30) end diff --git a/modules/csarManager2.lua b/modules/csarManager2.lua index f41bbf2..af8b40c 100644 --- a/modules/csarManager2.lua +++ b/modules/csarManager2.lua @@ -1,5 +1,5 @@ csarManager = {} -csarManager.version = "2.1.1" +csarManager.version = "2.1.3" csarManager.verbose = false csarManager.ups = 1 @@ -36,6 +36,12 @@ csarManager.ups = 1 - finally fixed smoke performance bug - csarManager.vectoring optional - 2.1.1 - zone-local verbosity + - 2.1.2 - 'downed' machinations (paranthese)S + - verbosity + - 2.1.3 - theMassObject now local + - winch pickup now also adds weight so they can be returned + - made some improvements to performance by making vars local + --]]-- -- modules that need to be loaded BEFORE I run @@ -202,13 +208,16 @@ function csarManager.createCSARMissionData(point, theSide, freq, name, numCrew, if not point then return nil end local newMission = {} newMission.side = theSide - if dcsCommon.stringStartsWith(name, "(downed) ") then + if dcsCommon.stringStartsWith(name, "downed ") then -- remove "downed" - it will be added again later - name = dcsCommon.removePrefix(name, "(downed) ") + name = dcsCommon.removePrefix(name, "downed ") + if csarManager.verbose then + trigger.action.outText("+++csar: 'downed' procced for <" .. name .. ">", 30) + end end if not inRadius then inRadius = csarManager.rescueRadius end - newMission.name = "(downed) " .. name .. "-" .. csarManager.missionID -- make it uuid-capable + newMission.name = "downed " .. name .. "-" .. csarManager.missionID -- make it uuid-capable newMission.zone = cfxZones.createSimpleZone(newMission.name, point, inRadius) --csarManager.rescueRadius) newMission.marker = mapMarker -- so it can be removed later newMission.isHot = false -- creating adversaries will make it hot, or when units are near. maybe implement a search later? @@ -388,7 +397,9 @@ function csarManager.successMission(who, where, theMission) if csarManager.csarDelivered then cfxZones.pollFlag(csarManager.csarDelivered, "inc", csarManager.configZone) - trigger.action.outText("+++csar: banging csarDelivered: <" .. csarManager.csarDelivered .. ">", 30) + if csarManager.verbose then + trigger.action.outText("+++csar: banging csarDelivered: <" .. csarManager.csarDelivered .. ">", 30) + end end end @@ -410,8 +421,19 @@ function csarManager.heloLanded(theUnit) -- points or airframes local allEvacuees = cargoSuper.getManifestFor(myName, "Evacuees") -- returns unlinked array + if csarManager.verbose then + trigger.action.outText("+++csar: helo <" .. myName .. "> landed with <" .. #allEvacuees .. "> evacuees on board.",30) + end + if #allEvacuees > 0 then -- wasif #conf.troopsOnBoard > 0 then + if csarManager.verbose then + trigger.action.outText("+++csar: checking bases:", 30) + end + for idx, base in pairs(csarManager.csarBases) do + if csarManager.verbose then + trigger.action.outText("+++csar: base <" .. base.zone.name .. ">", 30) + end -- check if the attached zone has changed hands -- this can happen if zone has its own owner -- attribute and is conquered by another side @@ -428,6 +450,10 @@ function csarManager.heloLanded(theUnit) currentBaseSide == 0 then -- can always land in neutral if cfxZones.pointInZone(thePoint, base.zone) then + if csarManager.verbose or base.zone.verbose then + trigger.action.outText("+++csar: <" .. myName .. "> touch down in CSAR drop-off zone <" .. base.zone.name .. ">", 30) + end + for idx, msn in pairs(conf.troopsOnBoard) do -- each troopsOnboard is actually the -- csar mission that I picked up @@ -454,9 +480,21 @@ function csarManager.heloLanded(theUnit) conf.troopsOnBoard = {} -- empty out troops on board -- we do *not* return so we can pick up troops on -- a CSARBASE if they were dropped there - + + else + if csarManager.verbose or base.zone.verbose then + trigger.action.outText("+++csar: touchdown of <" .. myName .. "> occured outside of csar zone <" .. base.zone.name .. ">", 30) + end end + + else -- not on my side + if csarManager.verbose or base.zone.verbose then + trigger.action.outText("+++csar: base <" .. base.zone.name .. "> is on side <" .. currentBaseSide .. ">, which is not on my side <" .. mySide .. ">.", 30) + end end -- my side? + end -- for all bases + if csarManager.verbose then + trigger.action.outText("+++csar: complete bases check", 30) end end -- check only if I'm carrying evacuees @@ -469,7 +507,7 @@ function csarManager.heloLanded(theUnit) -- see if we are inside the mission's rescue range local d = dcsCommon.distFlat(thePoint, mission.zone.point) if d < csarManager.rescueRadius then - -- pick up this mission an remove it from the + -- pick up this mission and remove it from the table.insert(pickups, mission) end end @@ -488,7 +526,7 @@ function csarManager.heloLanded(theUnit) theMission.group:destroy() -- will shut up radio as well theMission.group = nil -- now adapt for cargoSuper - theMassObject = cargoSuper.createMassObject( + local theMassObject = cargoSuper.createMassObject( csarManager.pilotWeight, theMission.name, theMission) @@ -788,6 +826,8 @@ function csarManager.unloadOne(args) -- create a new missions in 50m radius csarManager.createCSARforUnit(theUnit, theRescuedPilot, 50, true) conf.troopsOnBoard[i] = nil -- remove this mission + --TODO: remove weight for this pilot! + trigger.action.outTextForCoalition(theSide, myName .. " has aborted evacuating " .. msn.name .. ". New CSAR available.", 30) trigger.action.outSoundForCoalition(theSide, "Quest Snare 3.wav") @@ -944,8 +984,8 @@ function csarManager.update() -- every second trigger.action.outSoundForGroup(uID, "Quest Snare 3.wav") table.insert(csarMission.messagedUnits, uName) -- remember that we messaged them so we don't do again end - -- also pop smoke if not popped already, or more than 3 minutes ago - if csarManager.useSmoke and timer.getTime() - csarMission.lastSmokeTime > 179 then + -- also pop smoke if not popped already, or more than 5 minutes ago + if csarManager.useSmoke and (timer.getTime() - csarMission.lastSmokeTime) >= 5 * 60 then local smokePoint = dcsCommon.randomPointOnPerimeter( 50, csarMission.zone.point.x, csarMission.zone.point.z) --cfxZones.createHeightCorrectedPoint(csarMission.zone.point) -- trigger.action.smoke(smokePoint, 4 ) @@ -958,7 +998,7 @@ function csarManager.update() -- every second -- WARNING: WE ALWAYS ONLY CHECK A SINGLE UNIT - the first alive local evacuee = csarMission.group:getUnit(1) if evacuee then - ep = evacuee:getPoint() + local ep = evacuee:getPoint() d = dcsCommon.distFlat(uPoint, ep) d = math.floor(d * 10) / 10 if d < csarManager.hoverRadius * 2 then @@ -976,7 +1016,7 @@ function csarManager.update() -- every second csarMission.hoveringUnits[uName] = timer.getTime() end hoverTime = timer.getTime() - hoverTime -- calculate number of seconds - remainder = math.floor(csarManager.hoverDuration - hoverTime) + local remainder = math.floor(csarManager.hoverDuration - hoverTime) if remainder < 1 then remainder = 1 end hoverMsg = "Steady... " .. d * 3 .. "ft to your " .. oclock .. " o'clock, winching... (" .. remainder .. ")" if hoverTime > csarManager.hoverDuration then @@ -987,6 +1027,24 @@ function csarManager.update() -- every second table.insert(conf.troopsOnBoard, csarMission) csarMission.group:destroy() -- will shut up radio as well csarMission.group = nil + + -- now handle weight using cargoSuper + local theMassObject = cargoSuper.createMassObject( + csarManager.pilotWeight, + csarMission.name, + csarMission) + cargoSuper.addMassObjectTo( + uName, + "Evacuees", + theMassObject) + local totalMass = cargoSuper.calculateTotalMassFor(uName) + trigger.action.setUnitInternalCargo(uName, totalMass) + + if csarManager.verbose then + local allEvacuees = cargoSuper.getManifestFor(myName, "Evacuees") -- returns unlinked array + trigger.action.outText("+++csar: <" .. uName .. "> now has <" .. #allEvacuees .. "> groups of evacuees on board, totalling " .. totalMass .. "kg", 30) + end + trigger.action.outTextForGroup(uID, hoverMsg, 30, true) trigger.action.outSoundForGroup(uID, "Quest Snare 3.wav") @@ -1310,5 +1368,9 @@ end - compatibility: side/owner - make sure it is compatible with FARP, and landing on a FARP with opposition ownership will not disembark + + - suppress multi smoke + + - when unloading one by menu, update weight!!! --]]-- \ No newline at end of file diff --git a/modules/dcsCommon.lua b/modules/dcsCommon.lua index d18d432..32e966e 100644 --- a/modules/dcsCommon.lua +++ b/modules/dcsCommon.lua @@ -1,5 +1,5 @@ dcsCommon = {} -dcsCommon.version = "2.6.2" +dcsCommon.version = "2.6.3" --[[-- VERSION HISTORY 2.2.6 - compassPositionOfARelativeToB - clockPositionOfARelativeToB @@ -72,6 +72,7 @@ dcsCommon.version = "2.6.2" 2.6.0 - unified uuid, removed uuIdent 2.6.1 - removed bug in rotateUnitData: cy --> cz param passing 2.6.2 - new combineTables() + 2.6.3 - new tacan2freq() --]]-- @@ -1972,6 +1973,25 @@ dcsCommon.version = "2.6.2" trigger.action.smoke(newPoint, smokeColor) end +-- based on buzzer1977's idea, channel is number, eg in 74X, channel is 74, mode is "X" + function tacan2freq(channel, mode) + if not mode then mode = "X" end + if not channel then channel = 1 end + if type(mode) ~= "string" then mode = "X" end + mode = mode:upper() + local offset = 1000000 * channel + if channel < 64 then + if mode == "Y" then + return 1087000000 + offset + end + return 961000000 + offset -- mode x + end + + if mode == "Y" then + return 961000000 + offset + end + return 1087000000 + offset -- mode x + end -- -- -- V E C T O R M A T H diff --git a/modules/groupTrackers.lua b/modules/groupTrackers.lua index 5a11a17..12f87b7 100644 --- a/modules/groupTrackers.lua +++ b/modules/groupTrackers.lua @@ -1,5 +1,5 @@ groupTracker = {} -groupTracker.version = "1.1.1" +groupTracker.version = "1.1.2" groupTracker.verbose = false groupTracker.ups = 1 groupTracker.requiredLibs = { @@ -15,6 +15,8 @@ groupTracker.trackers = {} - array support for trackers - array support for trackers 1.1.1 - corrected clone zone reference bug + 1.1.2 - corrected naming (removed bang from flags), deprecated old + - more zone-local verbosity --]]-- @@ -97,20 +99,32 @@ function groupTracker.createTrackerWithZone(theZone) -- init group tracking set theZone.trackedGroups = {} - if cfxZones.hasProperty(theZone, "numGroups!") then - theZone.tNumGroups = cfxZones.getStringFromZoneProperty(theZone, "numGroups!", "") + + if cfxZones.hasProperty(theZone, "numGroups") then + theZone.tNumGroups = cfxZones.getStringFromZoneProperty(theZone, "numGroups", "*") + -- we may need to zero this flag + elseif cfxZones.hasProperty(theZone, "numGroups!") then -- DEPRECATED! + theZone.tNumGroups = cfxZones.getStringFromZoneProperty(theZone, "numGroups!", "*") -- we may need to zero this flag end - - if cfxZones.hasProperty(theZone, "addGroup!") then - theZone.tAddGroup = cfxZones.getStringFromZoneProperty(theZone, "addGroup!", "") + + if cfxZones.hasProperty(theZone, "addGroup") then + theZone.tAddGroup = cfxZones.getStringFromZoneProperty(theZone, "addGroup", "*") + -- we may need to zero this flag + elseif cfxZones.hasProperty(theZone, "addGroup!") then -- DEPRECATED + theZone.tAddGroup = cfxZones.getStringFromZoneProperty(theZone, "addGroup!", "*") + -- we may need to zero this flag + end + + if cfxZones.hasProperty(theZone, "removeGroup") then + theZone.tRemoveGroup = cfxZones.getStringFromZoneProperty(theZone, "removeGroup", "*") + -- we may need to zero this flag + elseif cfxZones.hasProperty(theZone, "removeGroup!") then -- DEPRECATED! + theZone.tRemoveGroup = cfxZones.getStringFromZoneProperty(theZone, "removeGroup!", "*") -- we may need to zero this flag end - if cfxZones.hasProperty(theZone, "removeGroup!") then - theZone.tRemoveGroup = cfxZones.getStringFromZoneProperty(theZone, "removeGroup!", "") - -- we may need to zero this flag - end + if cfxZones.hasProperty(theZone, "groupFilter") then local filterString = cfxZones.getStringFromZoneProperty(theZone, "groupFilter", "2") -- ground @@ -119,6 +133,10 @@ function groupTracker.createTrackerWithZone(theZone) trigger.action.outText("+++gTrck: filtering " .. theZone.groupFilter .. " in " .. theZone.name, 30) end end + + if theZone.verbose or groupTracker.verbose then + trigger.action.outText("gTrck: processed <" .. theZone.name .. ">", 30) + end end -- @@ -145,10 +163,13 @@ function groupTracker.checkGroups(theZone) if isDead then -- bang deceased if groupTracker.verbose or theZone.verbose then - trigger.action.outText("+++gTrk: dead group detected in " .. theZone.name .. ", discarding.", 30) + trigger.action.outText("+++gTrk: dead group detected in " .. theZone.name .. ", removing.", 30) end if theZone.tRemoveGroup then cfxZones.pollFlag(theZone.tRemoveGroup, "inc", theZone) + if theZone.verbose then + trigger.action.outText("+++gTrk: <" .. theZone.name .. "> incrementing remove flag <" .. theZone.tRemoveGroup .. ">", 30) + end end else -- transfer alive group @@ -207,24 +228,6 @@ function groupTracker.trackGroupsInZone(theZone) end end - -- old code, non-array capable - --[[-- - if trackerName == "*" then trackerName = theZone.name end - - local theTracker = groupTracker.getTrackerByName(trackerName) - if not theTracker then - trigger.action.outText("+++gTrk: trackGroupsInZone - no zone named <" .. trackerName .. ">", 30 ) - return - end - - local theGroups = cfxZones.allGroupsInZone(theZone, nil) - for idx, aGroup in pairs(theGroups) do - if groupTracker.verbose then - trigger.action.outText("+++gTrk: <" .. theZone.name .. "> passed off group <" .. aGroup:getName() .. "> to <" .. trackerName .. ">", 30) - end - groupTracker.addGroupToTracker(aGroup, theTracker) - end - --]]-- end diff --git a/modules/unGrief.lua b/modules/unGrief.lua index 38b8a08..d582162 100644 --- a/modules/unGrief.lua +++ b/modules/unGrief.lua @@ -1,6 +1,7 @@ unGrief = {} -unGrief.version = "1.1.0" +unGrief.version = "1.2.0" unGrief.verbose = false +unGrief.ups = 1 unGrief.requiredLibs = { "dcsCommon", -- always "cfxZones", -- Zones, of course @@ -16,11 +17,48 @@ unGrief.disabledFlagValue = unGrief.enabledFlagValue + 100 -- DO NOT CHANGE 1.1.0 - wrathful option - pve option - ignoreAI option - + 1.2.0 - allow PVP zones + - strict rules + - warnings on enter/exit + - warnings optional + --]]-- unGrief.griefers = {} -- offenders are stored here +-- PVP stuff here +unGrief.pvpZones = {} +unGrief.playerPilotZone = {} -- for messaging when leaving/entering pvp zones + + +function unGrief.addPvpZone(theZone) + table.insert(unGrief.pvpZones, theZone) +end + +function unGrief.getPvpZoneByName(aName) + for idx, aZone in pairs(unGrief.pvpZones) do + if aName == aZone.name then return aZone end + end + if unGrief.verbose then + trigger.action.outText("+++unGrief: no pvpZone with name <" .. aName ..">", 30) + end + + return nil +end + +-- +-- read pvp zone +-- +function unGrief.createPvpWithZone(theZone) + -- read pvp data - there's currently really nothing to do + if theZone.verbose or unGrief.verbose then + trigger.action.outText("+++uGrf: <" .. theZone.name .. "> is designated as PVP legal", 30) + end + + theZone.strictPVP = cfxZones.getBoolFromZoneProperty(theZone, "strict", false) + +end + -- vengeance: if player killed before, they are no longer welcome function unGrief.exactVengance(theEvent) if theEvent.id == 20 then -- S_EVENT_PLAYER_ENTER_UNIT @@ -90,6 +128,31 @@ function unGrief:onEvent(theEvent) local pvpTransgression = false if unGrief.pve and stiff.getPlayerName and stiff:getPlayerName() then pvpTransgression = true + if pvpTransgression then + -- check if this happened in a pvp zone. + local crimeScene = stiff:getPoint() + for idx, theZone in pairs (unGrief.pvpZones) do + -- if the VIC is in a pvp zone, that was legal + if cfxZones.isPointInsideZone(crimeScene, theZone) then + -- see if strict rules apply + if theZone.strictPVP then + -- also check killer + crimeScene = killer:getPoint() + if cfxZones.isPointInsideZone(crimeScene, theZone) then + pvpTransgression = false + end + else + -- relaxed pvp + pvpTransgression = false + end + + if (not pvpTransgression) and + (unGrief.verbose or theZone.verbose) then + trigger.action.outText("+++uGrf: legal PVP kill of <" .. stiff:getName() .. "> in <" .. theZone.name .. ">", 30) + end + end + end + end end if unGrief.ignoreAI then @@ -115,7 +178,7 @@ function unGrief:onEvent(theEvent) if not pvpTransgression then trigger.action.outText(playerName .. " has killed one of their own. YOU ARE ON NOTICE!", 30) else - trigger.action.outText(playerName .. " has killed a fellow Player. YOU ARE ON NOTICE!", 30) + trigger.action.outText(playerName .. " has illegally killed a fellow Player. YOU ARE ON NOTICE!", 30) end return end @@ -145,6 +208,45 @@ function unGrief:onEvent(theEvent) -- (or kick via SSB or do some other stuff. be creative to boot this idiot) end +function unGrief.update() + timer.scheduleFunction(unGrief.update, {}, timer.getTime() + 1/unGrief.ups) + -- iterate all players + for side = 1, 2 do + local playersOnThisSide = coalition.getPlayers(side) + for idx, p in pairs (playersOnThisSide) do + local pName = p:getPlayerName() + if pName then + local pLoc = p:getPoint() + local lastZone = unGrief.playerPilotZone[pName] + local currZone = nil + local isStrict = false + for idy, theZone in pairs(unGrief.pvpZones) do + if cfxZones.isPointInsideZone(pLoc, theZone) then + currZone = theZone + isStrict = theZone.strictPVP + end + end + if currZone ~= lastZone then + local pG = p:getGroup() + local gID = pG:getID() + if currZone then + local strictness = "" + if isStrict then + strictness = " STRICT PvP rules apply!" + end + + trigger.action.outTextForGroup(gID, "WARNING: you are entering a PVP zone!" .. strictness, 30) + else + -- left a pvp zone + trigger.action.outTextForGroup(gID, "NOTE: you are leaving a PVP area!", 30) + end + unGrief.playerPilotZone[pName] = currZone + end + end + end + end +end + function unGrief.readConfigZone() local theZone = cfxZones.getZoneByName("unGriefConfig") if not theZone then @@ -170,6 +272,8 @@ function unGrief.readConfigZone() unGrief.ignoreAI = cfxZones.getBoolFromZoneProperty(theZone, "ignoreAI", false) + unGrief.PVPwarnings = cfxZones.getBoolFromZoneProperty(theZone, "warnings", true) + if unGrief.verbose then trigger.action.outText("+++uGrf: read config", 30) end @@ -188,6 +292,22 @@ function unGrief.start() -- read config unGrief.readConfigZone() + -- read pvp zones if pve is enabled + if unGrief.pve then + if unGrief.verbose then + trigger.action.outText("PVE mode - scanning for PVP zones", 30) + end + local attrZones = cfxZones.getZonesWithAttributeNamed("pvp") + for k, aZone in pairs(attrZones) do + unGrief.createPvpWithZone(aZone) -- process attributes + unGrief.addPvpZone(aZone) -- add to list + end + + if unGrief.PVPwarnings then + unGrief.update() -- start update tracking for player warnings + end + end + -- connect event proccer world.addEventHandler(unGrief) @@ -201,6 +321,3 @@ if not unGrief.start() then unGrief = nil end --- to be developed: --- ungrief on and off flags --- pvp and pve zones in addition to global attributes \ No newline at end of file diff --git a/tutorial & demo missions/demo - The Danger Zone.miz b/tutorial & demo missions/demo - The Danger Zone.miz new file mode 100644 index 0000000..3835d7e Binary files /dev/null and b/tutorial & demo missions/demo - The Danger Zone.miz differ