mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
2.3.6
Yeller Model, The Debugger -x !, heloTroops' dropZones
This commit is contained in:
parent
0c1eb53a89
commit
b498a4e803
Binary file not shown.
Binary file not shown.
@ -1,5 +1,5 @@
|
||||
cfxCargoReceiver = {}
|
||||
cfxCargoReceiver.version = "2.0.0"
|
||||
cfxCargoReceiver.version = "2.1.0"
|
||||
cfxCargoReceiver.ups = 1 -- once a second
|
||||
cfxCargoReceiver.maxDirectionRange = 500 -- in m. distance when cargo manager starts talking to pilots who are carrying that cargo
|
||||
cfxCargoReceiver.requiredLibs = {
|
||||
@ -12,7 +12,10 @@ cfxCargoReceiver.requiredLibs = {
|
||||
- 2.0.0 no more cfxPlayer Dependency
|
||||
dmlZones, OOP
|
||||
clean-up
|
||||
|
||||
- 2.1.0 code maintenance
|
||||
cargo gets removed from mgr when touching ground
|
||||
switch to cargoReceiver!
|
||||
noBounce attribute
|
||||
|
||||
CargoReceiver is a zone enhancement you use to be automatically
|
||||
notified if a cargo was delivered inside the zone.
|
||||
@ -25,26 +28,30 @@ cfxCargoReceiver.receiverZones = {}
|
||||
function cfxCargoReceiver.processReceiverZone(aZone) -- process attribute and add to zone
|
||||
-- since the attribute is there, simply set the zones
|
||||
-- isCargoReceiver flag and we are good
|
||||
aZone.isCargoReceiver = true
|
||||
-- we can add additional processing here
|
||||
aZone.autoRemove = aZone:getBoolFromZoneProperty("autoRemove", false) -- maybe add a removeDelay
|
||||
aZone.isCargoReceiver = true -- so all zones can detect this. Necessary?
|
||||
aZone.autoRemove = aZone:getBoolFromZoneProperty("autoRemove", false)
|
||||
aZone.removeDelay = aZone:getNumberFromZoneProperty("removeDelay", 1)
|
||||
if aZone.removeDelay < 1 then aZone.removeDelay = 1 end
|
||||
aZone.silent = aZone:getBoolFromZoneProperty("silent", false)
|
||||
|
||||
|
||||
-- new method support
|
||||
aZone.cargoMethod = aZone:getStringFromZoneProperty("method", "inc")
|
||||
if aZone:hasProperty("cargoMethod") then
|
||||
aZone.cargoMethod = aZone:getStringFromZoneProperty("cargoMethod", "inc")
|
||||
end
|
||||
|
||||
if aZone:hasProperty("f!") then
|
||||
-- save the names of cargos delivered to prevent 'bounce'
|
||||
aZone.cargosDelivered = {} -- by cargo name
|
||||
aZone.noBounce = aZone:getBoolFromZoneProperty("noBounce", true)
|
||||
if aZone:hasProperty("cargoReceiver!") then
|
||||
aZone.outReceiveFlag = aZone:getStringFromZoneProperty("cargoReceiver!", "*<none>")
|
||||
elseif aZone:hasProperty("f!") then
|
||||
aZone.outReceiveFlag = aZone:getStringFromZoneProperty("f!", "*<none>")
|
||||
elseif aZone:hasProperty("cargoReceived!") then
|
||||
aZone.outReceiveFlag = aZone:getStringFromZoneProperty( "cargoReceived!", "*<none>")
|
||||
end
|
||||
|
||||
if not aZone.outReceiveFlag then
|
||||
trigger.action.outText("+++crgR: receiver <" .. aZone.name .. "> has no output!", 30)
|
||||
end
|
||||
end
|
||||
|
||||
function cfxCargoReceiver.addReceiverZone(aZone)
|
||||
@ -94,7 +101,7 @@ function cfxCargoReceiver.cargoEvent(event, object, name)
|
||||
|
||||
if not event then return end
|
||||
if event == "grounded" then
|
||||
-- this is actually the only one that interests us
|
||||
-- this is the only one that interests us
|
||||
if not object then
|
||||
return
|
||||
end
|
||||
@ -106,21 +113,28 @@ function cfxCargoReceiver.cargoEvent(event, object, name)
|
||||
-- now invoke callbacks for all zones
|
||||
-- this is in
|
||||
for name, aZone in pairs(cfxCargoReceiver.receiverZones) do
|
||||
if cfxZones.pointInZone(loc, aZone) then
|
||||
if aZone:pointInZone(loc) then
|
||||
cfxCargoReceiver.invokeCallback("deliver", object, name, aZone)
|
||||
|
||||
-- set flags as indicated
|
||||
if aZone.outReceiveFlag then
|
||||
cfxZones.pollFlag(aZone.outReceiveFlag, aZone.cargoMethod, aZone)
|
||||
if aZone.noBounce then
|
||||
-- we only do this once for every named object
|
||||
if not aZone.cargosDelivered[name] then
|
||||
aZone.cargosDelivered[name] = true
|
||||
aZone:pollFlag(aZone.outReceiveFlag, aZone.cargoMethod)
|
||||
end
|
||||
else
|
||||
aZone:pollFlag(aZone.outReceiveFlag, aZone.cargoMethod)
|
||||
end
|
||||
end
|
||||
|
||||
if aZone.autoRemove then
|
||||
-- schedule this for in a few seconds?
|
||||
-- schedule this for in a few seconds
|
||||
local args = {}
|
||||
args.theObject = object
|
||||
args.theZone = aZone
|
||||
timer.scheduleFunction(cfxCargoReceiver.removeCargo, args, timer.getTime() + aZone.removeDelay)
|
||||
--object:destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -139,17 +153,13 @@ function cfxCargoReceiver.update()
|
||||
-- new we see if any of these are close to a delivery zone
|
||||
for idx, aCargo in pairs(liftedCargos) do
|
||||
local thePoint = aCargo:getPoint()
|
||||
local receiver = cfxZones.getClosestZone(
|
||||
thePoint,
|
||||
cfxCargoReceiver.receiverZones -- must be indexed by name
|
||||
)
|
||||
local receiver = cfxZones.getClosestZone(thePoint, cfxCargoReceiver.receiverZones) -- must be indexed by name
|
||||
-- we now check if we are in 'speaking range' and receiver can talk
|
||||
-- modify delta by distance to boundary, not
|
||||
-- center
|
||||
-- modify delta by distance to boundary, not center
|
||||
local delta = dcsCommon.distFlat(thePoint, cfxZones.getPoint(receiver))
|
||||
delta = delta - receiver.radius
|
||||
|
||||
if (receiver.silent == false) and
|
||||
if (not receiver.silent) and
|
||||
(delta < cfxCargoReceiver.maxDirectionRange) then
|
||||
-- this cargo can be talked down.
|
||||
-- find the player unit that is closest to in in hopes
|
||||
@ -214,10 +224,14 @@ function cfxCargoReceiver.start()
|
||||
end
|
||||
|
||||
-- scan all zones for cargoReceiver flag
|
||||
local attrZones = cfxZones.getZonesWithAttributeNamed("cargoReceiver!")
|
||||
for k, aZone in pairs(attrZones) do
|
||||
cfxCargoReceiver.processReceiverZone(aZone)
|
||||
cfxCargoReceiver.addReceiverZone(aZone)
|
||||
end
|
||||
|
||||
-- old version, LEGACY
|
||||
local attrZones = cfxZones.getZonesWithAttributeNamed("cargoReceiver")
|
||||
|
||||
-- now create a spawner for all, add them to the spawner updater, and spawn for all zones that are not
|
||||
-- paused
|
||||
for k, aZone in pairs(attrZones) do
|
||||
cfxCargoReceiver.processReceiverZone(aZone) -- process attribute and add to zone
|
||||
cfxCargoReceiver.addReceiverZone(aZone) -- remember it so we can smoke it
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxZones = {}
|
||||
cfxZones.version = "4.4.2"
|
||||
cfxZones.version = "4.4.3"
|
||||
|
||||
-- cf/x zone management module
|
||||
-- reads dcs zones and makes them accessible and mutable
|
||||
@ -32,6 +32,7 @@ cfxZones.version = "4.4.2"
|
||||
- dmlZone:getCoalition() dereferences masterOwner once
|
||||
-4.4.1 - better verbosity for error in doPollFlag()
|
||||
-4.4.2 - twn support for wildcards <twn: > and <loc:>
|
||||
-4.4.3 - property name is trimmed (double check)
|
||||
--]]--
|
||||
|
||||
--
|
||||
@ -123,7 +124,14 @@ function cfxZones.readFromDCS(clearfirst)
|
||||
else
|
||||
newZone.properties = {}
|
||||
end -- WARNING: REF COPY. May need to clone
|
||||
|
||||
--[[--
|
||||
trigger.action.outText("zone <> properties:trimmed", 30)
|
||||
local msg = "["
|
||||
for idx, val in pairs(newZone.properties) do
|
||||
msg = msg .. "<" .. val.key .. ">:<" .. dcsCommon.trim(val.key) .. ">, "
|
||||
end
|
||||
trigger.action.outText(msg, 30)
|
||||
--]]--
|
||||
local upperName = newZone.name:upper()
|
||||
|
||||
-- location as 'point'
|
||||
@ -2158,7 +2166,14 @@ function cfxZones.extractPropertyFromDCS(theKey, theProperties)
|
||||
for i=1, #theProperties do
|
||||
local theP = theProperties[i]
|
||||
|
||||
local existingKey = dcsCommon.trim(theP.key)
|
||||
local existingKey = dcsCommon.trim(theP.key) -- does not work if ends on "#!?" - why?
|
||||
--while len(existingKey) > 1 and string.sub(existingKey, -1) == " " do
|
||||
-- existingKey = existingKey:sub(1, -2) -- trim manually
|
||||
--end
|
||||
if string.sub(existingKey, -1) == " " then
|
||||
trigger.action.outText("+++ZONES: warning: unable to trim blanks from attribute name <" .. existingKey .. ">", 30)
|
||||
end
|
||||
-- trigger.action.outText("procced attribute name <" .. existingKey .. ">", 30)
|
||||
if not cfxZones.caseSensitiveProperties then
|
||||
existingKey = string.lower(existingKey)
|
||||
end
|
||||
@ -2388,6 +2403,7 @@ function dmlZone:hasProperty(theProperty)
|
||||
trigger.action.outText("+++zne: WARNING - hasProperty called with nil theProperty for zone <" .. self.name .. ">", 30)
|
||||
return false
|
||||
end
|
||||
theProperty = dcsCommon.trim(theProperty) -- strip leading and training blanks
|
||||
local foundIt = self:getZoneProperty(theProperty)
|
||||
if not foundIt then
|
||||
-- check for possible forgotten or exchanged IO flags
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
civAir = {}
|
||||
civAir.version = "3.0.2"
|
||||
civAir.version = "3.1.0"
|
||||
--[[--
|
||||
3.0.0 liveries support
|
||||
default liveries for Yak-50 (main test case)
|
||||
@ -15,7 +15,12 @@ civAir.version = "3.0.2"
|
||||
protest action
|
||||
spawning now works correctly for groupType
|
||||
3.0.2 clean-up
|
||||
|
||||
3.1.0 better verbosity for startup info
|
||||
dicts for departOnly and landingOnly
|
||||
correctly filter depart only, land only, closed at start
|
||||
Syria multiple "H" airfields DCS bug
|
||||
filter airfields with no runways
|
||||
getAirfieldNamed
|
||||
--]]--
|
||||
|
||||
civAir.ups = 0.05 -- updates per second. 0.05 = once every 20 seconds
|
||||
@ -60,8 +65,11 @@ civAir.maxIdle = 8 * 60 -- seconds of ide time before it is removed after landin
|
||||
|
||||
civAir.trafficCenters = {}
|
||||
civAir.excludeAirfields = {}
|
||||
civAir.excludeAirfieldsDict = {}
|
||||
civAir.departOnly = {} -- use only to start from
|
||||
civAir.departOnlyDict = {} -- as above, by af name
|
||||
civAir.landingOnly = {} -- use only to land at
|
||||
civAir.landingOnlyDict = {} -- as above, by af name
|
||||
civAir.inoutZones = {} -- off-map connector zones
|
||||
|
||||
civAir.requiredLibs = {
|
||||
@ -180,7 +188,7 @@ end
|
||||
|
||||
function civAir.processZone(theZone)
|
||||
local value = theZone:getStringFromZoneProperty("civAir", "")
|
||||
local af = dcsCommon.getClosestAirbaseTo(theZone.point, 0) -- 0 = only airfields, not farp or ships
|
||||
local af = dcsCommon.getClosestAirbaseTo(theZone.point, 0) -- 0 = only airfields, not farp nor ships
|
||||
local inoutName = "***" .. theZone:getName()
|
||||
|
||||
if af then
|
||||
@ -188,10 +196,13 @@ function civAir.processZone(theZone)
|
||||
value = value:lower()
|
||||
if value == "exclude" or value == "closed" then
|
||||
table.insert(civAir.excludeAirfields, afName)
|
||||
civAir.excludeAirfieldsDict[afName] = afName
|
||||
elseif dcsCommon.stringStartsWith(value, "depart") or dcsCommon.stringStartsWith(value, "start") or dcsCommon.stringStartsWith(value, "take") then
|
||||
table.insert(civAir.departOnly, afName)
|
||||
civAir.departOnlyDict[afName] = afName -- can fold many in one
|
||||
elseif dcsCommon.stringStartsWith(value, "land") or dcsCommon.stringStartsWith(value, "arriv") then
|
||||
table.insert(civAir.landingOnly, afName)
|
||||
civAir.landingOnlyDict[afName] = afName -- can fold many on one
|
||||
elseif dcsCommon.stringStartsWith(value, "inb") then
|
||||
table.insert(civAir.departOnly, inoutName) -- start in inbound zone
|
||||
civAir.inoutZones[inoutName] = theZone
|
||||
@ -253,8 +264,8 @@ function civAir.filterAirfields(inAll, inFilter)
|
||||
end
|
||||
|
||||
function civAir.getTwoAirbases()
|
||||
local fAB -- first airbase to depart
|
||||
local sAB -- second airbase to fly to
|
||||
local fAB -- name of first airbase to depart from
|
||||
local sAB -- name second airbase to fly to
|
||||
|
||||
local departAB = dcsCommon.combineTables(civAir.trafficCenters, civAir.departOnly)
|
||||
-- remove all currently excluded air bases from departure
|
||||
@ -263,11 +274,14 @@ function civAir.getTwoAirbases()
|
||||
if #filteredAB < 1 then
|
||||
trigger.action.outText("+++civA: too few departure airfields", 30)
|
||||
return nil, nil
|
||||
else
|
||||
-- trigger.action.outText("+++civA: source (first) fields available: " .. #filteredAB, 30)
|
||||
end
|
||||
|
||||
-- now pick the departure airfield
|
||||
fAB = dcsCommon.pickRandom(filteredAB)
|
||||
|
||||
fAB = dcsCommon.pickRandom(filteredAB) -- returns an airfield name
|
||||
-- trigger.action.outText("+++civA: picked first: <" .. fAB .. ">", 30)
|
||||
|
||||
-- now generate list of landing airfields
|
||||
local arriveAB = dcsCommon.combineTables(civAir.trafficCenters, civAir.landingOnly)
|
||||
-- remove all currently excluded air bases from arrival
|
||||
@ -277,6 +291,8 @@ function civAir.getTwoAirbases()
|
||||
if #filteredAB < 1 then
|
||||
trigger.action.outText("+++civA: too few arrival airfields", 30)
|
||||
return nil, nil
|
||||
else
|
||||
-- trigger.action.outText("+++civA: second (ARV) fields available: " .. #filteredAB, 30)
|
||||
end
|
||||
|
||||
-- pick any second that are not the same
|
||||
@ -285,10 +301,13 @@ function civAir.getTwoAirbases()
|
||||
sAB = dcsCommon.pickRandom(filteredAB)
|
||||
tries = tries + 1 -- only try 10 times
|
||||
until fAB ~= sAB or tries > 10
|
||||
|
||||
|
||||
-- trigger.action.outText("+++civA: picked SECOND: <" .. sAB .. ">", 30)
|
||||
|
||||
|
||||
local civA = {}
|
||||
if not (dcsCommon.stringStartsWith(fAB, '***')) then
|
||||
civA.AB = dcsCommon.getFirstAirbaseWhoseNameContains(fAB, 0)
|
||||
civA.AB = civAir.getAirfieldNamed(fAB) -- dcsCommon.getFirstAirbaseWhoseNameContains(fAB, 0)
|
||||
civA.name = civA.AB:getName()
|
||||
else
|
||||
civA.zone = civAir.inoutZones[fAB]
|
||||
@ -296,16 +315,22 @@ function civAir.getTwoAirbases()
|
||||
end
|
||||
local civB = {}
|
||||
if not (dcsCommon.stringStartsWith(sAB, '***')) then
|
||||
civB.AB = dcsCommon.getFirstAirbaseWhoseNameContains(sAB, 0)
|
||||
civB.AB = civAir.getAirfieldNamed(sAB) -- dcsCommon.getFirstAirbaseWhoseNameContains(sAB, 0)
|
||||
civB.name = civB.AB:getName()
|
||||
else
|
||||
civB.zone = civAir.inoutZones[sAB]
|
||||
civB.name = civB.zone:getName()
|
||||
end
|
||||
|
||||
-- trigger.action.outText("+++civA: picked source AF <" .. civA.name .. "> and dest <" .. civB.name .. ">", 30)
|
||||
|
||||
return civA, civB -- fAB, sAB
|
||||
end
|
||||
|
||||
function civAir.getAirfieldNamed(name)
|
||||
return Airbase.getByName(name)
|
||||
end
|
||||
|
||||
function civAir.parkingIsFree(fromWP)
|
||||
-- iterate over all currently registred flights and make
|
||||
-- sure that their location isn't closer than 10m to my new parking
|
||||
@ -684,24 +709,48 @@ function civAir.collectHubs()
|
||||
end
|
||||
|
||||
function civAir.listTrafficCenters()
|
||||
trigger.action.outText("Traffic Centers", 30)
|
||||
local msg = "Traffic Centers:\n"
|
||||
local other = false
|
||||
for idx, aName in pairs(civAir.trafficCenters) do
|
||||
trigger.action.outText(aName, 30)
|
||||
if other then msg = msg .. ", " end
|
||||
msg = msg .. aName
|
||||
other = true
|
||||
end
|
||||
trigger.action.outText(msg .. "\n", 30)
|
||||
|
||||
msg = "Departure-Only:\n"
|
||||
other = false
|
||||
if #civAir.departOnly > 0 then
|
||||
trigger.action.outText("Departure-Only:", 30)
|
||||
for idx, aName in pairs(civAir.departOnly) do
|
||||
trigger.action.outText(aName, 30)
|
||||
if other then msg = msg .. ", " end
|
||||
msg = msg .. aName
|
||||
other = true
|
||||
end
|
||||
end
|
||||
trigger.action.outText(msg .. "\n", 30)
|
||||
|
||||
msg = "Landing-Only:\n"
|
||||
other = false
|
||||
if #civAir.landingOnly > 0 then
|
||||
trigger.action.outText("Arrival/Landing-Only:", 30)
|
||||
for idx, aName in pairs(civAir.landingOnly) do
|
||||
trigger.action.outText(aName, 30)
|
||||
if other then msg = msg .. ", " end
|
||||
msg = msg .. aName
|
||||
other = true
|
||||
end
|
||||
end
|
||||
trigger.action.outText(msg .. "\n", 30)
|
||||
|
||||
|
||||
msg = "Closed:\n"
|
||||
other = false
|
||||
if #civAir.excludeAirfields > 0 then
|
||||
for idx, aName in pairs(civAir.excludeAirfields) do
|
||||
if other then msg = msg .. ", " end
|
||||
msg = msg .. aName
|
||||
other = true
|
||||
end
|
||||
end
|
||||
trigger.action.outText(msg .. "\n", 30)
|
||||
end
|
||||
|
||||
-- start
|
||||
@ -721,13 +770,27 @@ function civAir.start()
|
||||
if (#civAir.trafficCenters + #civAir.departOnly < 1) or
|
||||
(#civAir.trafficCenters + #civAir.landingOnly < 1)
|
||||
then
|
||||
trigger.action.outText("+++civA: marked traffic centers:" .. #civAir.trafficCenters .. "\n depart-only:" .. #civAir.departOnly .. "\n landing-only: " .. #civAir.landingOnly .. "\n", 30 )
|
||||
trigger.action.outText("+++civA: auto-populating", 30)
|
||||
-- simply add airfields on the map
|
||||
-- and filter those that are excluded, land-only or depart only
|
||||
local allBases = dcsCommon.getAirbasesWhoseNameContains("*", 0)
|
||||
for idx, aBase in pairs(allBases) do
|
||||
local afName = aBase:getName()
|
||||
|
||||
table.insert(civAir.trafficCenters, afName)
|
||||
if civAir.departOnlyDict[afName] or
|
||||
civAir.landingOnlyDict[afName] or
|
||||
civAir.excludeAirfieldsDict[afName]
|
||||
then
|
||||
trigger.action.outText("+++civA: filtering base " .. afName .. " for single-exception", 30)
|
||||
else
|
||||
-- syria special proccing
|
||||
local rw = aBase:getRunways()
|
||||
if #rw < 1 then
|
||||
-- trigger.action.outText(afName .. " has no runways, filtered", 30)
|
||||
else
|
||||
table.insert(civAir.trafficCenters, afName)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
convoy = {}
|
||||
convoy.version = "1.1.0"
|
||||
convoy.version = "1.2.0"
|
||||
convoy.requiredLibs = {
|
||||
"dcsCommon",
|
||||
"cfxZones",
|
||||
@ -32,7 +32,8 @@ VERSION HISTORY
|
||||
- warning when not onStart and no start?
|
||||
- say hi
|
||||
- removed destination attribute
|
||||
|
||||
1.2.0 - convoyMethod
|
||||
- convoyTriggerMethod
|
||||
--]]--
|
||||
|
||||
--[[-- CONVOY Structure
|
||||
@ -174,6 +175,9 @@ function convoy.readConvoyZone(theZone)
|
||||
trigger.action.outText("+++CVY: Warning: Convoy zone <" .. theZone.name .. "> has disabled 'onStart' and has no 'spawn?' input. This convoy zone can't send out any convoys,", 30)
|
||||
end
|
||||
end
|
||||
theZone.convoyMethod = theZone:getStringFromZoneProperty("convoyMethod", "inc")
|
||||
theZone.convoyTriggerMethod = theZone:getStringFromZoneProperty("convoyTriggerMethod", "change")
|
||||
|
||||
--[[--
|
||||
if theZone:hasProperty("destination") then -- remove me
|
||||
theZone.destination = theZone:getStringFromZoneProperty("destination", "none")
|
||||
@ -560,7 +564,7 @@ function convoy.wpReached(gName, convName, idx, wpNum)
|
||||
convoy.invokeArrivedCallbacks(theConvoy)
|
||||
-- hit the output flag if defined
|
||||
if theZone.arrivedOut then
|
||||
theZone:pollFlag(theZone.arrivedOut, "inc")
|
||||
theZone:pollFlag(theZone.arrivedOut, theZone.convoyMethod) -- "inc")
|
||||
end
|
||||
-- remove convoy from watchlist
|
||||
convoy.convoys[convName] = nil
|
||||
@ -845,7 +849,7 @@ function convoy.update()
|
||||
-- check for flags
|
||||
for idx, theZone in pairs (convoy.zones) do
|
||||
if theZone.spawnFlag and
|
||||
theZone:testZoneFlag(theZone.spawnFlag, "change", "lastSpawnFlag") then
|
||||
theZone:testZoneFlag(theZone.spawnFlag, theZone.convoyTriggerMethod, "lastSpawnFlag") then
|
||||
convoy.startConvoy(theZone)
|
||||
end
|
||||
end
|
||||
@ -900,7 +904,7 @@ function convoy.statusUpdate() -- every 10 seconds
|
||||
convoy.invokeAttackedCallbacks(theConvoy)
|
||||
theZone = theConvoy.origin
|
||||
if theZone.attackedOut then
|
||||
theZone:pollFlag(theZone.attackedOut, "inc")
|
||||
theZone:pollFlag(theZone.attackedOut, theZone.convoyMethod) -- "inc")
|
||||
end
|
||||
end
|
||||
|
||||
@ -909,7 +913,7 @@ function convoy.statusUpdate() -- every 10 seconds
|
||||
convoy.invokeDestroyedCallbacks(theConvoy)
|
||||
theZone = theConvoy.origin
|
||||
if theZone.deadOut then
|
||||
theZone:pollFlag(theZone.deadOut, "inc")
|
||||
theZone:pollFlag(theZone.deadOut, theZone.convoyMethod) -- "inc")
|
||||
end
|
||||
trigger.action.outTextForCoalition(theConvoy.coa, "Convoy " .. convName .. " enroute to " .. theConvoy.dest .. " was destroyed.", 30)
|
||||
trigger.action.outSoundForCoalition(theConvoy.coa, convoy.actionSound)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxHeloTroops = {}
|
||||
cfxHeloTroops.version = "3.1.5"
|
||||
cfxHeloTroops.version = "4.0.0"
|
||||
cfxHeloTroops.verbose = false
|
||||
cfxHeloTroops.autoDrop = true
|
||||
cfxHeloTroops.autoPickup = false
|
||||
@ -25,6 +25,9 @@ cfxHeloTroops.requestRange = 500 -- meters
|
||||
- loadSound and disembarkSound
|
||||
3.1.4 - guarding destination access in save
|
||||
3.1.5 - more guarding of destination access
|
||||
4.0.0 - added dropZones
|
||||
- enforceDropZones
|
||||
- coalition for drop zones
|
||||
--]]--
|
||||
|
||||
|
||||
@ -37,10 +40,24 @@ cfxHeloTroops.requiredLibs = {
|
||||
|
||||
cfxHeloTroops.unitConfigs = {} -- all configs are stored by unit's name
|
||||
cfxHeloTroops.troopWeight = 100 -- kg average weight per trooper
|
||||
cfxHeloTroops.dropZones = {}
|
||||
|
||||
-- persistence support
|
||||
cfxHeloTroops.deployedTroops = {}
|
||||
|
||||
--
|
||||
-- drop zones
|
||||
--
|
||||
function cfxHeloTroops.processDropZone(theZone)
|
||||
theZone.droppedFlag = theZone:getStringFromZoneProperty("dropZone!", "cfxNone")
|
||||
theZone.dropMethod = theZone:getStringFromZoneProperty("dropMethod", "inc")
|
||||
theZone.dropCoa = theZone:getCoalitionFromZoneProperty("coalition", 0)
|
||||
theZone.autoDespawn = theZone:getNumberFromZoneProperty("autoDespawn", -1)
|
||||
end
|
||||
|
||||
--
|
||||
-- comms
|
||||
--
|
||||
function cfxHeloTroops.resetConfig(conf)
|
||||
conf.autoDrop = cfxHeloTroops.autoDrop --if true, will drop troops on-board upon touchdown
|
||||
conf.autoPickup = cfxHeloTroops.autoPickup -- if true will load nearest troops upon touchdown
|
||||
@ -576,16 +593,33 @@ function cfxHeloTroops.scoreWhenCapturing(theUnit)
|
||||
end
|
||||
end
|
||||
|
||||
function cfxHeloTroops.isInsideDropZone(theUnit)
|
||||
local p = theUnit:getPoint()
|
||||
for idx, theZone in pairs (cfxHeloTroops.dropZones) do
|
||||
if theZone:isPointInsideZone(p) then return true end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function cfxHeloTroops.doDeployTroops(args)
|
||||
local conf = args[1]
|
||||
local what = args[2]
|
||||
-- deploy the troops I have on board in formation
|
||||
local theUnit = conf.unit
|
||||
local theGroup = theUnit:getGroup()
|
||||
local gid = theGroup:getID()
|
||||
local inside = cfxHeloTroops.isInsideDropZone(theUnit)
|
||||
if (not inside) and cfxHeloTroops.enforceDropZones then
|
||||
trigger.action.outTextForGroup(gid, "You are outside an disembark/drop zone.", 30)
|
||||
return
|
||||
end
|
||||
|
||||
-- deploy the troops I have on board
|
||||
cfxHeloTroops.deployTroopsFromHelicopter(conf)
|
||||
|
||||
-- interface with playerscore if we dropped
|
||||
-- inside an enemy-owned zone
|
||||
if cfxPlayerScore and cfxOwnedZones then
|
||||
local theUnit = conf.unit
|
||||
--local theUnit = conf.unit
|
||||
cfxHeloTroops.scoreWhenCapturing(theUnit)
|
||||
end
|
||||
|
||||
@ -630,7 +664,7 @@ function cfxHeloTroops.deployTroopsFromHelicopter(conf)
|
||||
end
|
||||
|
||||
local chopperZone = cfxZones.createSimpleZone("choppa", p, 12) -- 12 m radius around choppa
|
||||
local theCoalition = theUnit:getGroup():getCoalition() -- make it choppers COALITION
|
||||
local theCoalition = theUnit:getGroup():getCoalition() -- make it chopper's COALITION
|
||||
local theGroup, theData = cfxZones.createGroundUnitsInZoneForCoalition (
|
||||
theCoalition,
|
||||
theName, -- group name, may be tracked
|
||||
@ -677,8 +711,39 @@ function cfxHeloTroops.deployTroopsFromHelicopter(conf)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- bang on all dropZones that we can find
|
||||
for name, theZone in pairs(cfxHeloTroops.dropZones) do
|
||||
-- can employ coalition test here as well, maybe later?
|
||||
if theZone:isPointInsideZone(p) then
|
||||
if theZone.dropCoa == 0 or theCoalition == theZone.dropCoa then
|
||||
if cfxHeloTroops.verbose or theZone.verbose then
|
||||
trigger.action.outText("+++Helo: will bang! on dropZone <" .. theZone.name .. "> output dropZone! <" .. theZone.droppedFlag .. "> with method <" .. theZone.dropMethod .. ">", 30)
|
||||
end
|
||||
theZone:pollFlag(theZone.droppedFlag, theZone.dropMethod)
|
||||
end
|
||||
if theZone.autoDespawn and theZone.autoDespawn > 0 then
|
||||
args = {}
|
||||
args.theZone = theZone
|
||||
args.theGroup = theGroup
|
||||
timer.scheduleFunction(cfxHeloTroops.autoDespawn, args, timer.getTime() + theZone.autoDespawn)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function cfxHeloTroops.autoDespawn(args)
|
||||
if not args then return end
|
||||
local theZone = args.theZone
|
||||
local theGroup = args.theGroup
|
||||
if theZone.verbose then
|
||||
trigger.action.outText("+++Helo: auto-despawning drop in drop zone <" .. theZone.name .. ">", 30)
|
||||
end
|
||||
if not theGroup then return end
|
||||
if Group.isExist(theGroup) then
|
||||
Group.destroy(theGroup)
|
||||
end
|
||||
end
|
||||
--
|
||||
-- Loading Troops
|
||||
--
|
||||
@ -882,7 +947,7 @@ function cfxHeloTroops.readConfigZone()
|
||||
theZone = cfxZones.createSimpleZone("heloTroopsConfig")
|
||||
end
|
||||
|
||||
cfxHeloTroops.verbose = theZone:getBoolFromZoneProperty("verbose", false)
|
||||
cfxHeloTroops.verbose = theZone.verbose
|
||||
|
||||
if theZone:hasProperty("legalTroops") then
|
||||
local theTypesString = theZone:getStringFromZoneProperty("legalTroops", "")
|
||||
@ -907,6 +972,7 @@ function cfxHeloTroops.readConfigZone()
|
||||
cfxHeloTroops.disembarkSound = theZone:getStringFromZoneProperty("disembarkSound", cfxHeloTroops.actionSound)
|
||||
|
||||
cfxHeloTroops.requestRange = theZone:getNumberFromZoneProperty("requestRange", 500)
|
||||
cfxHeloTroops.enforceDropZones = theZone:getBoolFromZoneProperty("enforceDropZones", false)
|
||||
-- add own troop carriers
|
||||
if theZone:hasProperty("troopCarriers") then
|
||||
local tc = theZone:getStringFromZoneProperty("troopCarriers", "UH-1D")
|
||||
@ -999,6 +1065,13 @@ function cfxHeloTroops.start()
|
||||
-- read config zone
|
||||
cfxHeloTroops.readConfigZone()
|
||||
|
||||
-- read drop zones
|
||||
local attrZones = cfxZones.getZonesWithAttributeNamed("dropZone!")
|
||||
for k, aZone in pairs(attrZones) do
|
||||
cfxHeloTroops.processDropZone(aZone)
|
||||
cfxHeloTroops.dropZones[aZone.name] = aZone
|
||||
end
|
||||
|
||||
-- start housekeeping
|
||||
cfxHeloTroops.houseKeeping()
|
||||
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
cfxPlayerScore = {}
|
||||
cfxPlayerScore.version = "3.3.1"
|
||||
cfxPlayerScore.version = "4.0.0"
|
||||
cfxPlayerScore.name = "cfxPlayerScore" -- compatibility with flag bangers
|
||||
cfxPlayerScore.badSound = "Death BRASS.wav"
|
||||
cfxPlayerScore.scoreSound = "Quest Snare 3.wav"
|
||||
@ -18,7 +18,9 @@ cfxPlayerScore.firstSave = true -- to force overwrite
|
||||
3.3.0 - case INsensitivity for all typeScore objects
|
||||
3.3.1 - fixes for DCS oddity in events after update
|
||||
- cleanup
|
||||
|
||||
4.0.0 - own event handling, disco from dcsCommon
|
||||
- early landing detection (unitSpawnTime)
|
||||
|
||||
TODO: Kill event no longer invoked for map objetcs, attribute
|
||||
to faction now, reverse invocation direction with PlayerScore
|
||||
--]]--
|
||||
@ -51,7 +53,7 @@ cfxPlayerScore.train = 5
|
||||
cfxPlayerScore.landing = 0 -- if > 0 it scores as feat
|
||||
|
||||
cfxPlayerScore.unit2player = {} -- lookup and reverse look-up
|
||||
|
||||
cfxPlayerScore.unitSpawnTime = {} -- lookup by unit name to prevent early landing
|
||||
function cfxPlayerScore.addSafeZone(theZone)
|
||||
theZone.scoreSafe = theZone:getCoalitionFromZoneProperty("scoreSafe", 0)
|
||||
table.insert(cfxPlayerScore.safeZones, theZone)
|
||||
@ -570,7 +572,7 @@ function cfxPlayerScore.awardScoreTo(killSide, theScore, killerName)
|
||||
end
|
||||
|
||||
--
|
||||
-- EVENT HANDLING
|
||||
-- EVENT PROCESSING / HANDLING
|
||||
--
|
||||
function cfxPlayerScore.linkUnitWithPlayer(theUnit)
|
||||
-- create the entries for lookup and reverseLooup tables
|
||||
@ -583,7 +585,7 @@ function cfxPlayerScore.unlinkUnit(theUnit)
|
||||
local uName = theUnit:getName()
|
||||
cfxPlayerScore.unit2player[uName] = nil
|
||||
end
|
||||
|
||||
--[[--
|
||||
function cfxPlayerScore.preProcessor(theEvent)
|
||||
-- return true if the event should be processed
|
||||
-- by us
|
||||
@ -721,10 +723,13 @@ function cfxPlayerScore.preProcessor(theEvent)
|
||||
|
||||
return false
|
||||
end
|
||||
--]]--
|
||||
|
||||
--[[--
|
||||
function cfxPlayerScore.postProcessor(theEvent)
|
||||
-- don't do anything
|
||||
end
|
||||
--]]--
|
||||
|
||||
function cfxPlayerScore.isStaticObject(theUnit)
|
||||
if not theUnit.getGroup then return true end
|
||||
@ -1091,7 +1096,165 @@ function cfxPlayerScore.handlePlayerDeath(theEvent)
|
||||
end
|
||||
end
|
||||
|
||||
function cfxPlayerScore.handlePlayerEvent(theEvent)
|
||||
--
|
||||
-- event detection
|
||||
--
|
||||
function cfxPlayerScore.isScoreEvent(theEvent)
|
||||
-- return true if the event results in a score event
|
||||
if theEvent.initiator == nil then
|
||||
return false
|
||||
end
|
||||
if cfxPlayerScore.verbose then
|
||||
trigger.action.outText("Event preproc: " .. theEvent.id .. " (" .. dcsCommon.event2text(theEvent.id) .. ")", 30)
|
||||
if theEvent.id == 8 or theEvent.id == 30 then -- dead or lost event
|
||||
local who = theEvent.initiator
|
||||
local name = "(nil ini)"
|
||||
if who then
|
||||
name = "(inval object)"
|
||||
if who.getName then name = who:getName() end
|
||||
end
|
||||
trigger.action.outText("Dead/Lost subject: <" .. name .. ">", 30)
|
||||
end
|
||||
if theEvent.id == 2 then -- hit
|
||||
local who = theEvent.initiator
|
||||
local name = "(nil ini)"
|
||||
if who then
|
||||
name = "(inval initi)"
|
||||
if who.getName then name = who:getName() end
|
||||
if not name then -- WTF??? could be a weapon
|
||||
name = "!nil getName!"
|
||||
if who.getTypeName then name = who:getTypeName() end
|
||||
if not name then
|
||||
name = "WTFer"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local hit = theEvent.object
|
||||
local hname = "(nil ini)"
|
||||
if hit then
|
||||
hname = "(inval object)"
|
||||
if hit.getName then hname = hit:getName() end
|
||||
end
|
||||
trigger.action.outText("o:<" .. name .. "> hit <" .. hname .. ">", 30)
|
||||
end
|
||||
end
|
||||
|
||||
-- check if this was FORMERLY a player plane
|
||||
local theUnit = theEvent.initiator
|
||||
if not theUnit.getName then return end -- fix for DCS update bug
|
||||
local uName = theUnit:getName()
|
||||
if cfxPlayerScore.unit2player[uName] then
|
||||
-- this requires special IMMEDIATE handling when event is
|
||||
-- one of the below
|
||||
if theEvent.id == 5 or -- crash
|
||||
theEvent.id == 8 or -- dead
|
||||
theEvent.id == 9 or -- pilot_dead
|
||||
theEvent.id == 30 or -- unit loss
|
||||
theEvent.id == 6 then -- eject
|
||||
-- these can lead to a pilot demerit
|
||||
-- event does NOT have a player
|
||||
cfxPlayerScore.handlePlayerDeath(theEvent)
|
||||
return false -- false = no score event (any more)
|
||||
end
|
||||
end
|
||||
|
||||
-- from here on, initiator must be player
|
||||
if not theUnit.getPlayerName or
|
||||
not theUnit:getPlayerName() then
|
||||
return false
|
||||
end
|
||||
if theEvent.id == 28 then -- kill, but only with target
|
||||
local killer = theEvent.initiator
|
||||
if not theEvent.target then
|
||||
if cfxPlayerScore.verbose then
|
||||
trigger.action.outText("+++scr kill nil TARGET", 30)
|
||||
end
|
||||
return false
|
||||
end
|
||||
-- if there are kill zones, we filter all kills that happen outside of kill zones
|
||||
if #cfxPlayerScore.killZones > 0 then
|
||||
local pLoc = theUnit:getPoint()
|
||||
local tLoc = theEvent.target:getPoint()
|
||||
local isIn, percent, dist, theZone = cfxZones.pointInOneOfZones(tLoc, cfxPlayerScore.killZones)
|
||||
if not isIn then
|
||||
if cfxPlayerScore.verbose then
|
||||
trigger.action.outText("+++pScr: kill detected, but target <" .. theEvent.target:getName() .. "> was outside of any kill zones", 30)
|
||||
end
|
||||
return false
|
||||
end
|
||||
if theZone.duet and not cfxZones.pointInZone(pLoc, theZone) then
|
||||
-- player must be in same zone but was not
|
||||
if cfxPlayerScore.verbose then
|
||||
trigger.action.outText("+++pScr: kill detected, but player <" .. theUnit:getPlayerName() .. "> was outside of kill zone <" .. theZone.name .. ">", 30)
|
||||
end
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- birth event for players initializes score if
|
||||
-- not existed, and nils the queue
|
||||
if theEvent.id == 15 then -- player birth
|
||||
-- link player and unit
|
||||
cfxPlayerScore.linkUnitWithPlayer(theUnit)
|
||||
cfxPlayerScore.unitSpawnTime[uName] = timer.getTime() -- to detect 'early landing'
|
||||
-- trigger.action.outText("Birth event", 30)
|
||||
return true
|
||||
end
|
||||
|
||||
-- take off. overwrites timestamp for last landing
|
||||
-- so a blipping t/o does nor count. Pre-proc only
|
||||
if theEvent.id == 3 or theEvent.id == 54 then
|
||||
local now = timer.getTime()
|
||||
local playerName = theUnit:getPlayerName()
|
||||
cfxPlayerScore.lastPlayerLanding[playerName] = now -- overwrite
|
||||
return false
|
||||
end
|
||||
|
||||
-- landing can score. but only the first landing in x seconds
|
||||
-- and has spawned more than 10 seconds before
|
||||
-- landing in safe zone promotes any queued scores to
|
||||
-- permanent if enabled, then nils queue
|
||||
if theEvent.id == 4 or theEvent.id == 55 then
|
||||
-- trigger.action.outText("LANDING event", 30)
|
||||
-- player landed. filter multiple landed events
|
||||
local now = timer.getTime()
|
||||
local playerName = theUnit:getPlayerName()
|
||||
-- if player spawns on ground, DCS now can post a
|
||||
-- "landing" event. filter
|
||||
if cfxPlayerScore.unitSpawnTime[uName] and
|
||||
now - cfxPlayerScore.unitSpawnTime[uName] < 10
|
||||
then
|
||||
cfxPlayerScore.lastPlayerLanding[playerName] = now -- just for the sake of it
|
||||
-- trigger.action.outText("(DCS early landing bug ignored)", 30)
|
||||
return false
|
||||
end
|
||||
-- trigger.action.outText("Time since spawn: " .. now - cfxPlayerScore.unitSpawnTime[uName], 30)
|
||||
local lastLanding = cfxPlayerScore.lastPlayerLanding[playerName]
|
||||
cfxPlayerScore.lastPlayerLanding[playerName] = now -- overwrite
|
||||
if lastLanding and lastLanding + cfxPlayerScore.delayBetweenLandings > now then
|
||||
if cfxPlayerScore.verbose then
|
||||
trigger.action.outText("+++pScr: Player <" .. playerName .. "> touch-down ignored: too soon after last.", 30)
|
||||
trigger.action.outText("now is <" .. now .. ">, between is <" .. cfxPlayerScore.delayBetweenLandings .. ">, last + between is <" .. lastLanding + cfxPlayerScore.delayBetweenLandings .. ">", 30)
|
||||
end
|
||||
-- filter this event, too soon
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
function cfxPlayerScore:onEvent(theEvent)
|
||||
if cfxPlayerScore.isScoreEvent(theEvent) then
|
||||
cfxPlayerScore.handleScoreEvent(theEvent)
|
||||
end
|
||||
end
|
||||
|
||||
function cfxPlayerScore.handleScoreEvent(theEvent)
|
||||
if theEvent.id == 28 then
|
||||
-- kill from player detected.
|
||||
cfxPlayerScore.killDetected(theEvent)
|
||||
@ -1134,7 +1297,9 @@ function cfxPlayerScore.handlePlayerEvent(theEvent)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Config handling
|
||||
--
|
||||
function cfxPlayerScore.readConfigZone(theZone)
|
||||
cfxPlayerScore.verbose = theZone.verbose
|
||||
-- default scores
|
||||
@ -1450,9 +1615,10 @@ function cfxPlayerScore.start()
|
||||
end
|
||||
|
||||
-- subscribe to events and use dcsCommon's handler structure
|
||||
dcsCommon.addEventHandler(cfxPlayerScore.handlePlayerEvent,
|
||||
cfxPlayerScore.preProcessor,
|
||||
cfxPlayerScore.postProcessor)
|
||||
-- dcsCommon.addEventHandler(cfxPlayerScore.handlePlayerEvent,
|
||||
-- cfxPlayerScore.preProcessor,
|
||||
-- cfxPlayerScore.postProcessor)
|
||||
world.addEventHandler(cfxPlayerScore)
|
||||
-- now load all save data and populate map with troops that
|
||||
-- we deployed last save.
|
||||
if persistence then
|
||||
|
||||
@ -21,6 +21,7 @@ radioMenu.lateGroups = {} -- dict by ID
|
||||
- added dynamic player support
|
||||
4.0.1 - MX no longer optional, so ask for it
|
||||
4.0.2 - ackSnd now also broadcasts to all if no group
|
||||
4.1.0 - outX --> valX verification. putting back in optional outX
|
||||
--]]--
|
||||
|
||||
function radioMenu.addRadioMenu(theZone)
|
||||
@ -437,6 +438,11 @@ function radioMenu.createRadioMenuWithZone(theZone)
|
||||
if theZone:hasProperty("radioMethod") then
|
||||
theZone.radioMethod = theZone:getStringFromZoneProperty( "radioMethod", "inc")
|
||||
end
|
||||
-- note: outX currently overridden with valX
|
||||
theZone.outMethA = theZone:getStringFromZoneProperty("outA", theZone.radioMethod)
|
||||
theZone.outMethB = theZone:getStringFromZoneProperty("outB", theZone.radioMethod)
|
||||
theZone.outMethC = theZone:getStringFromZoneProperty("outC", theZone.radioMethod)
|
||||
theZone.outMethD = theZone:getStringFromZoneProperty("outD", theZone.radioMethod)
|
||||
|
||||
theZone.radioTriggerMethod = theZone:getStringFromZoneProperty("radioTriggerMethod", "change")
|
||||
|
||||
@ -731,6 +737,7 @@ function radioMenu.doMenuX(args)
|
||||
local outVal = theZone.outValA
|
||||
local ack = theZone.ackA
|
||||
local ackSnd = theZone.ackASnd
|
||||
local meth = theZone.outMethA -- currently not used
|
||||
|
||||
-- decode A..X
|
||||
if theItemIndex == "B"then
|
||||
@ -740,6 +747,7 @@ function radioMenu.doMenuX(args)
|
||||
outVal = theZone.outValB
|
||||
ack = theZone.ackB
|
||||
ackSnd = theZone.ackBSnd
|
||||
meth = theZone.outMethB
|
||||
elseif theItemIndex == "C" then
|
||||
cd = radioMenu.cdByGID(theZone.mcdC, theZone, theGroup) -- theZone.mcdC
|
||||
busy = theZone.busyC
|
||||
@ -747,6 +755,7 @@ function radioMenu.doMenuX(args)
|
||||
outVal = theZone.outValC
|
||||
ack = theZone.ackC
|
||||
ackSnd = theZone.ackCSnd
|
||||
meth = theZone.outMethC
|
||||
elseif theItemIndex == "D" then
|
||||
cd = radioMenu.cdByGID(theZone.mcdD, theZone, theGroup) -- theZone.mcdD
|
||||
busy = theZone.busyD
|
||||
@ -754,6 +763,7 @@ function radioMenu.doMenuX(args)
|
||||
outVal = theZone.outValD
|
||||
ack = theZone.ackD
|
||||
ackSnd = theZone.ackDSnd
|
||||
meth = theZone.outMethD
|
||||
end
|
||||
|
||||
-- see if we are on cooldown
|
||||
@ -793,6 +803,7 @@ function radioMenu.doMenuX(args)
|
||||
-- poll flag, override with outVal if set
|
||||
if outVal then
|
||||
--outVal = "#"..outVal -- we force immediate mode
|
||||
-- now replaced by 'valX' attribute
|
||||
theZone:pollFlag(theFlag, outVal)
|
||||
if theZone.verbose or radioMenu.verbose then
|
||||
trigger.action.outText("+++menu: overriding index " .. theItemIndex .. " output method <" .. theZone.radioMethod .. "> with immediate value <" .. outVal .. ">", 30)
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
debugger = {}
|
||||
debugger.version = "3.0.0"
|
||||
debugger.version = "3.1.0"
|
||||
debugDemon = {}
|
||||
debugDemon.version = "2.1.0"
|
||||
|
||||
@ -45,7 +45,8 @@ debugger.log = ""
|
||||
- x *f
|
||||
- x *z
|
||||
- x ?
|
||||
|
||||
3.1.0 - new DCS world events 57-61
|
||||
- x ! xref hanging/unconnected
|
||||
|
||||
--]]--
|
||||
|
||||
@ -122,7 +123,11 @@ debugDemon.eventList = {
|
||||
["54"] = "S_EVENT_MISSION_WINNER = 54",
|
||||
["55"] = "S_EVENT_POSTPONED_TAKEOFF = 55",
|
||||
["56"] = "S_EVENT_POSTPONED_LAND = 56",
|
||||
["57"] = "S_EVENT_MAX = 57",
|
||||
["57"] = "S_EVENT_SIMULATION_FREEZE = 57",
|
||||
["58"] = "S_EVENT_SIMULATION_UNFREEZE = 58",
|
||||
["59"] = "S_EVENT_HUMAN_AIRCRAFT_REPAIR_START = 59",
|
||||
["60"] = "S_EVENT_HUMAN_AIRCRAFT_REPAIR_FINISH = 60",
|
||||
["61"] = "S_EVENT_MAX = 61",
|
||||
}
|
||||
|
||||
debugger.spawnTypes = {
|
||||
@ -150,7 +155,7 @@ debugger.spawnTypes = {
|
||||
-- XREF MODULE
|
||||
--
|
||||
xref = {}
|
||||
xref.version = "1.0.0"
|
||||
xref.version = "1.1.0"
|
||||
xref.dmlObjects = {} -- dict by zone name:upper()
|
||||
-- has inputs: dict of string for each '?' input, contains input flag name
|
||||
-- has output: dict of array for each output '!', contains output flag names as array
|
||||
@ -158,7 +163,7 @@ xref.flags = {} -- dict by flag name
|
||||
-- has froms: dict of zone of attributes that can write to this flags
|
||||
-- has tos: dict of zones of attributes that read from flag
|
||||
|
||||
function xref.getDmlObject(name)
|
||||
function xref.getDmlObject(name) -- lazy alloc
|
||||
name = name:upper()
|
||||
local theObject = xref.dmlObjects[name]
|
||||
if not theObject then
|
||||
@ -170,7 +175,7 @@ function xref.getDmlObject(name)
|
||||
return theObject
|
||||
end
|
||||
|
||||
function xref.getFlag(name, theZone)
|
||||
function xref.getFlag(name, theZone) -- lazy alloc
|
||||
if theZone and dcsCommon.stringStartsWith(name, "*") then
|
||||
-- local name conversion
|
||||
name = theZone.name .. name
|
||||
@ -178,8 +183,8 @@ function xref.getFlag(name, theZone)
|
||||
local theFlag = xref.flags[name]
|
||||
if not theFlag then
|
||||
theFlag = {}
|
||||
theFlag.froms = {} -- dict by zone name/output that write to this flag
|
||||
theFlag.tos = {} -- dict by zone name / inputs that reads from this flag
|
||||
theFlag.froms = {} -- dict by zone name: OUTPUTS that write to this flag
|
||||
theFlag.tos = {} -- dict by zone name: INPUTS that read from this flag
|
||||
xref.flags[name] = theFlag
|
||||
end
|
||||
return theFlag
|
||||
@ -236,20 +241,21 @@ function xref.scanMissionZones()
|
||||
-- iterate all properties
|
||||
local attributes = theZone:getAllZoneProperties()
|
||||
for name, value in pairs(attributes) do
|
||||
local n2 = dcsCommon.trim(name)
|
||||
-- find inputs
|
||||
if dcsCommon.stringEndsWith(name, "?") then
|
||||
xref.addInput(theZone, name, value)
|
||||
if dcsCommon.stringEndsWith(n2, "?") then
|
||||
xref.addInput(theZone, n2, value)
|
||||
end
|
||||
|
||||
-- find outputs
|
||||
if dcsCommon.stringEndsWith(name, "!") then
|
||||
xref.addOutput(theZone, name, value)
|
||||
if dcsCommon.stringEndsWith(n2, "!") then
|
||||
xref.addOutput(theZone, n2, value)
|
||||
end
|
||||
|
||||
-- other stuff, e.g. "#"
|
||||
-- find outputs
|
||||
if dcsCommon.stringEndsWith(name, "#") then
|
||||
xref.addOutput(theZone, name, value)
|
||||
if dcsCommon.stringEndsWith(n2, "#") then
|
||||
xref.addOutput(theZone, n2, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -289,8 +295,6 @@ function xref.xrefFlag(name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- trigger.action.outText(msg, 30)
|
||||
return msg
|
||||
|
||||
end
|
||||
@ -323,9 +327,7 @@ function xref.xrefZone(name, theObject)
|
||||
end
|
||||
end
|
||||
|
||||
-- trigger.action.outText(msg, 30)
|
||||
return msg
|
||||
|
||||
return msg
|
||||
end
|
||||
|
||||
function xref.xrefName(name)
|
||||
@ -362,41 +364,93 @@ function xref.allZones()
|
||||
end
|
||||
|
||||
function xref.xall()
|
||||
msg = ""
|
||||
local msg = ""
|
||||
-- now dump all flags
|
||||
for flagName, data in pairs (xref.flags) do
|
||||
-- msg = msg .. xref.xrefFlag(flagName)
|
||||
msg = msg .. xref.xrefName(flagName)
|
||||
end
|
||||
|
||||
-- dump all zones
|
||||
for zoneName, data in pairs(xref.dmlObjects) do
|
||||
-- msg = msg .. xref.xrefZone(zoneName, data)
|
||||
msg = msg .. xref.xrefName(zoneName)
|
||||
end
|
||||
return msg
|
||||
-- trigger.action.outText(msg, 30)
|
||||
end
|
||||
|
||||
function xref.unconnected()
|
||||
local msg = "xref: unconnected flags/commands:\n"
|
||||
local badFroms = {}
|
||||
local badTos = {}
|
||||
for name, theFlag in pairs(xref.flags) do
|
||||
-- look for single-direction flags, i.e those that have
|
||||
-- no froms or no tos.
|
||||
if dcsCommon.getSizeOfTable(theFlag.froms) < 1 then
|
||||
-- this flag has output referencing it, so the input hangs
|
||||
badFroms[name] = theFlag
|
||||
end
|
||||
if dcsCommon.getSizeOfTable(theFlag.tos) < 1 then
|
||||
-- this flag has output referencing it, so the input hangs
|
||||
badTos[name] = theFlag
|
||||
end
|
||||
end
|
||||
local hasUnconnected = false
|
||||
if dcsCommon.getSizeOfTable(badFroms) > 0 then
|
||||
msg = msg .. "<Flag/Command> used at [zone]:INPUT that listens for/to nothing:\n"
|
||||
for name, theFlag in pairs(badFroms) do
|
||||
msg = msg .. " <" .. name .. ">: "
|
||||
local froms = theFlag.tos -- crossing from and to here!
|
||||
for zName, outList in pairs(froms) do
|
||||
msg = msg .. "[" .. zName .. "]:"
|
||||
local c = 0
|
||||
for idx, outName in pairs(outList) do
|
||||
if c > 0 then msg = msg .. ", " end
|
||||
c = 1
|
||||
msg = msg .. outName
|
||||
end
|
||||
msg = msg .. "\n"
|
||||
end
|
||||
end
|
||||
msg = msg .. " -- END OF LIST --\n\n"
|
||||
hasUnconnected = true
|
||||
end
|
||||
|
||||
if dcsCommon.getSizeOfTable(badTos) > 0 then
|
||||
msg = msg .. "<Flag/Command> used at [zone]:OUTPUT that sends to nobody:\n"
|
||||
for name, theFlag in pairs(badTos) do
|
||||
msg = msg .. " <" .. name .. ">: "
|
||||
local tos = theFlag.froms -- crossing!
|
||||
for zName, inList in pairs(tos) do
|
||||
msg = msg .. "[" .. zName .. "]:"
|
||||
local c = 0
|
||||
for idx, inName in pairs(inList) do
|
||||
if c > 0 then msg = msg .. ", " end
|
||||
c = 1
|
||||
msg = msg .. inName
|
||||
end
|
||||
end
|
||||
msg = msg .. "\n"
|
||||
end
|
||||
hasUnconnected = true
|
||||
msg = msg .. " -- END OF LIST --\n\n"
|
||||
end
|
||||
|
||||
if not hasUnconnected then
|
||||
msg = msg .. "\n -- NONE --\n"
|
||||
end
|
||||
|
||||
return msg
|
||||
end
|
||||
|
||||
function xref.start()
|
||||
xref.scanMissionZones()
|
||||
local flagNum = dcsCommon.getSizeOfTable(xref.flags)
|
||||
local dmlObNum = dcsCommon.getSizeOfTable(xref.dmlObjects)
|
||||
trigger.action.outText("XRef v" .. xref.version .. " full DML object scan on mission complete:\n<" .. flagNum .. "> flags are referenced in <" .. dmlObNum .. "> DML zones", 30)
|
||||
|
||||
-- trigger.action.outText(xref.xall(), 30)
|
||||
trigger.action.outText("XRef v" .. xref.version .. " full DML object scan on mission complete:\n<" .. flagNum .. "> flags are referenced in <" .. dmlObNum .. "> DML zones", 30)
|
||||
end
|
||||
|
||||
-- run the xref
|
||||
xref.start()
|
||||
|
||||
--[[--
|
||||
to do
|
||||
scan messenger and wildcards for flag access
|
||||
|
||||
--]]--
|
||||
|
||||
|
||||
--
|
||||
-- DEBUGGER MAIn
|
||||
--
|
||||
@ -436,7 +490,6 @@ function debugger.saveLog(name)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- tracking flags
|
||||
--
|
||||
@ -764,7 +817,6 @@ function debugger.update()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Config & Start
|
||||
--
|
||||
@ -950,7 +1002,6 @@ function debugDemon:onEvent(theEvent)
|
||||
end
|
||||
|
||||
if theEvent.id == world.event.S_EVENT_MARK_CHANGE then
|
||||
-- trigger.action.outText("debugger: Mark Change event received", 30)
|
||||
-- when changed, the mark's text is examined for a command
|
||||
-- if it starts with the 'mark' string ("-" by default) it is processed
|
||||
-- by the command processor
|
||||
@ -958,42 +1009,26 @@ function debugDemon:onEvent(theEvent)
|
||||
-- else an error is displayed and the mark remains.
|
||||
if debugDemon.hasMark(theEvent.text) then
|
||||
-- strip the mark
|
||||
local cCommand = dcsCommon.clone(theEvent.text, true)
|
||||
local cCommand = dcsCommon.clone(theEvent.text)
|
||||
local commandString = cCommand:sub(1+debugDemon.markOfDemon:len())
|
||||
-- break remainder apart into <command> <arg1> ... <argn>
|
||||
local commands = dcsCommon.splitString(commandString, debugDemon.splitDelimiter)
|
||||
|
||||
-- this is a command. process it and then remove it if it was executed successfully
|
||||
local cTheEvent = dcsCommon.clone(theEvent, true) -- strip meta tables
|
||||
local cTheEvent = dcsCommon.clone(theEvent) -- strip meta tables
|
||||
local args = {commands, cTheEvent}
|
||||
-- defer execution for 0.1s to get out of trx bracked
|
||||
timer.scheduleFunction(debugDemon.deferredDebug, args, timer.getTime() + 0.1)
|
||||
debugDemon.activeIdx = cTheEvent.idx
|
||||
--[[--
|
||||
local success = debugDemon.executeCommand(commands, cTheEvent) -- execute on a clone, not original
|
||||
|
||||
-- remove this mark after successful execution
|
||||
if success then
|
||||
trigger.action.removeMark(theEvent.idx)
|
||||
else
|
||||
-- we could play some error sound
|
||||
end
|
||||
--]]--
|
||||
end
|
||||
end
|
||||
|
||||
if theEvent.id == world.event.S_EVENT_MARK_REMOVED then
|
||||
-- trigger.action.outText("Mark Remove received, removing idx <" .. theEvent.idx .. ">.", 30)
|
||||
debugDemon.activeIdx = nil
|
||||
end
|
||||
end
|
||||
|
||||
function debugDemon.deferredDebug(args)
|
||||
-- trigger.action.outText("enter deferred debug command", 30)
|
||||
-- if not debugDemon.activeIdx then
|
||||
-- trigger.action.outText("Debugger: window was closed, debug command ignored.", 30)
|
||||
-- return
|
||||
-- end
|
||||
local commands = args[1]
|
||||
local cTheEvent = args[2]
|
||||
local success = debugDemon.executeCommand(commands, cTheEvent) -- execute on a clone, not original
|
||||
@ -1884,8 +1919,11 @@ function debugDemon.processXrefCommand(args, event)
|
||||
if not larg or larg == "" then larg = "?" end
|
||||
larg = larg:lower()
|
||||
if larg == "?" then
|
||||
debugger.outText("*** xRef: ? = help (this), * = xref all, *f = list all DML flags, *z = list all DML zones, <name> xref flag or zone", 30)
|
||||
debugger.outText("*** xRef: ? = help (this), ! = xref all 'hanging' or unconnected flags/commands, * = xref all, *f = list all DML flags, *z = list all DML zones, <name> xref flag or zone", 30)
|
||||
return true -- leave up
|
||||
elseif larg == "!" then
|
||||
debugger.outText(xref.unconnected(), 30)
|
||||
return true
|
||||
elseif larg == "*" then
|
||||
debugger.outText(xref.xall(), 30)
|
||||
return true
|
||||
|
||||
BIN
tutorial & demo missions/demo - Inferno at Sea.miz
Normal file
BIN
tutorial & demo missions/demo - Inferno at Sea.miz
Normal file
Binary file not shown.
BIN
tutorial & demo missions/demo - The Yeller Model.miz
Normal file
BIN
tutorial & demo missions/demo - The Yeller Model.miz
Normal file
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user