mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 2.0.1
Updates to Debugger, csarManager, PlayerScore/objectDestructDetector
This commit is contained in:
parent
c9694c3176
commit
38d6487de7
Binary file not shown.
Binary file not shown.
@ -12,27 +12,7 @@ rndFlags.requiredLibs = {
|
|||||||
Copyright 2022 by Christian Franz and cf/x
|
Copyright 2022 by Christian Franz and cf/x
|
||||||
|
|
||||||
Version History
|
Version History
|
||||||
1.0.0 - Initial Version
|
|
||||||
1.1.0 - DML flag conversion:
|
|
||||||
flagArrayFromString: strings OK, trim
|
|
||||||
remove pollFlag
|
|
||||||
pollFlag from cfxZones, include zone
|
|
||||||
randomBetween for pollSize
|
|
||||||
pollFlag to bang done with inc
|
|
||||||
getFlagValue in update
|
|
||||||
some code clean-up
|
|
||||||
rndMethod synonym
|
|
||||||
1.2.0 - Watchflag integration
|
|
||||||
1.3.0 - DML simplification: RND!
|
|
||||||
zone-local verbosity
|
|
||||||
1.3.1 - 'done+1' --> 'done!', using rndMethod instead of 'inc'
|
|
||||||
- added zonal verbosity
|
|
||||||
- added 'rndDone!' flag
|
|
||||||
- rndMethod defaults to "inc"
|
|
||||||
1.3.2 - moved flagArrayFromString to dcsCommon
|
|
||||||
- minor clean-up
|
|
||||||
1.4.0 - persistence
|
|
||||||
1.4.1 - a little less verbosity
|
|
||||||
2.0.0 - dmlZones, OOP
|
2.0.0 - dmlZones, OOP
|
||||||
|
|
||||||
--]]
|
--]]
|
||||||
|
|||||||
@ -158,3 +158,13 @@ if not cfxSSBSingleUse.start()then
|
|||||||
trigger.action.outText("SSB Single Use failed to start up.", 30)
|
trigger.action.outText("SSB Single Use failed to start up.", 30)
|
||||||
cfxSSBSingleUse = nil
|
cfxSSBSingleUse = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--[[--
|
||||||
|
limited use rebuild
|
||||||
|
have planes inside a zone to regulate:
|
||||||
|
numUp attribute for number of lives. defaults to one
|
||||||
|
reinforce? to make availabe again, resets numLeft to numUp - warning: check with other inhibitors
|
||||||
|
onStart = no will inhibit at start
|
||||||
|
exempt - limits to not apply to planes in this zone. same as -1 for numUp
|
||||||
|
--]]--
|
||||||
@ -1,5 +1,5 @@
|
|||||||
tdz = {}
|
tdz = {}
|
||||||
tdz.version = "1.0.2"
|
tdz.version = "1.0.3"
|
||||||
tdz.requiredLibs = {
|
tdz.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
"cfxZones", -- Zones, of course
|
"cfxZones", -- Zones, of course
|
||||||
@ -17,6 +17,7 @@ VERSION HISTORY
|
|||||||
helo attribute
|
helo attribute
|
||||||
1.0.2 - manual placement option
|
1.0.2 - manual placement option
|
||||||
filters FARPs
|
filters FARPs
|
||||||
|
1.0.3 - "manual" now defaults to false
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
@ -89,7 +90,7 @@ function tdz.createTDZ(theZone)
|
|||||||
|
|
||||||
local nearestRwy = nil
|
local nearestRwy = nil
|
||||||
-- see if this is a manually placed runway
|
-- see if this is a manually placed runway
|
||||||
if theZone:getBoolFromZoneProperty("manual", true) then
|
if theZone:getBoolFromZoneProperty("manual", false) then
|
||||||
-- construct runway from trigger zone attributes
|
-- construct runway from trigger zone attributes
|
||||||
if theZone.verbose or tdz.verbose then
|
if theZone.verbose or tdz.verbose then
|
||||||
trigger.action.outText("+++TDZ: runway for <" .. theZone.name .. "> is manually placed", 30)
|
trigger.action.outText("+++TDZ: runway for <" .. theZone.name .. "> is manually placed", 30)
|
||||||
|
|||||||
@ -1,34 +1,26 @@
|
|||||||
airfield = {}
|
airfield = {}
|
||||||
airfield.version = "2.0.0"
|
airfield.version = "2.1.1"
|
||||||
airfield.requiredLibs = {
|
airfield.requiredLibs = {
|
||||||
"dcsCommon",
|
"dcsCommon",
|
||||||
"cfxZones",
|
"cfxZones",
|
||||||
}
|
}
|
||||||
airfield.myAirfields = {} -- indexed by name
|
airfield.myAirfields = {} -- indexed by af name, zone that links to it
|
||||||
airfield.gracePeriod = 3
|
airfield.gracePeriod = 3
|
||||||
airfield.allAirfields = {} -- inexed by name
|
airfield.allAirfields = {} -- inexed by af name, db entries: base, cat
|
||||||
|
|
||||||
--[[--
|
--[[--
|
||||||
This module generates signals when the nearest airfield changes hands,
|
This module generates signals when the nearest airfield changes hands,
|
||||||
can force the coalition of an airfield, and always provides the
|
can force the coalition of an airfield, and always provides the
|
||||||
current owner as a value
|
current owner as a value
|
||||||
|
|
||||||
Version History
|
Version History^
|
||||||
1.0.0 - initial release
|
|
||||||
1.1.0 - added 'fixed' attribute
|
|
||||||
- added 'farps' attribute to individual zones
|
|
||||||
- allow zone.local farps designation
|
|
||||||
- always checks farp cap events
|
|
||||||
- added verbosity
|
|
||||||
1.1.1 - GC grace period correction of ownership
|
|
||||||
1.1.2 - 'show' attribute
|
|
||||||
line color attributes per zone
|
|
||||||
line color defaults in config
|
|
||||||
2.0.0 - show all airfields option
|
2.0.0 - show all airfields option
|
||||||
- fully reworked show options
|
- fully reworked show options
|
||||||
- unmanaged airfields are automatically updated
|
- unmanaged airfields are automatically updated
|
||||||
- full color support
|
- full color support
|
||||||
-- support for FARPS as well
|
-- support for FARPS as well
|
||||||
|
2.1.0 - added support for makeNeutral?
|
||||||
|
2.1.1 - bug fixing for DCS 2.9x airfield retrofit
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
@ -39,7 +31,9 @@ function airfield.collectAll()
|
|||||||
local dropped = 0
|
local dropped = 0
|
||||||
for idx, aBase in pairs(allBases) do
|
for idx, aBase in pairs(allBases) do
|
||||||
local entry = {}
|
local entry = {}
|
||||||
local cat = Airbase.getCategory(aBase) -- DCS 2.9 hardened
|
--local cat = Airbase.getCategory(aBase) -- DCS 2.9 hardened
|
||||||
|
-- ho! dcs 2.9.x retrofit screwed with Airfield.getCategory.
|
||||||
|
local cat = aBase:getDesc().category
|
||||||
-- cats: 0 = airfield, 1 = farp, 2 = ship
|
-- cats: 0 = airfield, 1 = farp, 2 = ship
|
||||||
if (cat == 0) or (cat == 1) then
|
if (cat == 0) or (cat == 1) then
|
||||||
local name = aBase:getName()
|
local name = aBase:getName()
|
||||||
@ -50,6 +44,7 @@ function airfield.collectAll()
|
|||||||
count = count + 1
|
count = count + 1
|
||||||
else
|
else
|
||||||
dropped = dropped + 1
|
dropped = dropped + 1
|
||||||
|
-- trigger.action.outText("***dropped airbase <" .. aBase:getName() .. ">, cat = <" .. cat .. ">", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if airfield.verbose then
|
if airfield.verbose then
|
||||||
@ -98,6 +93,11 @@ function airfield.createAirFieldFromZone(theZone)
|
|||||||
theZone.lastMakeBlue = trigger.misc.getUserFlag(theZone.makeBlue)
|
theZone.lastMakeBlue = trigger.misc.getUserFlag(theZone.makeBlue)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if theZone:hasProperty("makeNeutral?") then
|
||||||
|
theZone.makeNeutral = theZone:getStringFromZoneProperty("makeNeutral?", "<none>")
|
||||||
|
theZone.lastMakeNeutral = trigger.misc.getUserFlag(theZone.makeNeutral)
|
||||||
|
end
|
||||||
|
|
||||||
if theZone:hasProperty("autoCap?") then
|
if theZone:hasProperty("autoCap?") then
|
||||||
theZone.autoCap = theZone:getStringFromZoneProperty("autoCap?", "<none>")
|
theZone.autoCap = theZone:getStringFromZoneProperty("autoCap?", "<none>")
|
||||||
theZone.lastAutoCap = trigger.misc.getUserFlag(theZone.autoCap)
|
theZone.lastAutoCap = trigger.misc.getUserFlag(theZone.autoCap)
|
||||||
@ -146,8 +146,11 @@ function airfield.createAirFieldFromZone(theZone)
|
|||||||
|
|
||||||
-- now mark this zone as handled
|
-- now mark this zone as handled
|
||||||
local entry = airfield.allAirfields[theZone.afName]
|
local entry = airfield.allAirfields[theZone.afName]
|
||||||
entry.linkedTo = theZone -- only remember last, but that's enough.
|
if not entry then
|
||||||
|
trigger.action.outText("+++airF: WARNING - unlinked airfield <" .. theZone.afName .. "> for zone <" .. theZone.name .. ">", 30)
|
||||||
|
else
|
||||||
|
entry.linkedTo = theZone -- only remember last, but that's enough.
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function airfield.markAirfieldOnMap(theAirfield, lineColor, fillColor)
|
function airfield.markAirfieldOnMap(theAirfield, lineColor, fillColor)
|
||||||
@ -246,6 +249,10 @@ function airfield.airfieldCaptured(theBase)
|
|||||||
airfield.untendedCapture(bName, theBase)
|
airfield.untendedCapture(bName, theBase)
|
||||||
return
|
return
|
||||||
end -- not attached to a zone
|
end -- not attached to a zone
|
||||||
|
if theZone.verbose or airfield.verbose then
|
||||||
|
trigger.action.outText("+++airF: capturing <" .. bName .. "> for zone <" .. theZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
|
||||||
local newCoa = theBase:getCoalition()
|
local newCoa = theBase:getCoalition()
|
||||||
theZone.owner = newCoa
|
theZone.owner = newCoa
|
||||||
|
|
||||||
@ -324,6 +331,21 @@ function airfield.update()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if theZone.makeNeutral and theZone:testZoneFlag(theZone.makeNeutral, theZone.triggerMethod, "lastMakeNeutral") then
|
||||||
|
if theZone.verbose or airfield.verbose then
|
||||||
|
trigger.action.outText("+++airF: 'makeNeutral' triggered for airfield <" .. afName .. "> in zone <" .. theZone:getName() .. ">", 30)
|
||||||
|
end
|
||||||
|
if theAirfield:autoCaptureIsOn() then
|
||||||
|
-- turn off autoCap
|
||||||
|
airfield.assumeControl(theZone)
|
||||||
|
end
|
||||||
|
theAirfield:setCoalition(0) -- make it blue
|
||||||
|
if theZone.owner ~= 0 then -- only send cap event when capped
|
||||||
|
airfield.airfieldCaptured(theAirfield) -- 0 cap will not cause any signals, but we do this anyway
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
if theZone.autoCap and theZone:testZoneFlag(theZone.autoCap, theZone.triggerMethod, "lastAutoCap") then
|
if theZone.autoCap and theZone:testZoneFlag(theZone.autoCap, theZone.triggerMethod, "lastAutoCap") then
|
||||||
if theAirfield:autoCaptureIsOn() then
|
if theAirfield:autoCaptureIsOn() then
|
||||||
-- do nothing
|
-- do nothing
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxZones = {}
|
cfxZones = {}
|
||||||
cfxZones.version = "4.1.1"
|
cfxZones.version = "4.1.2"
|
||||||
|
|
||||||
-- cf/x zone management module
|
-- cf/x zone management module
|
||||||
-- reads dcs zones and makes them accessible and mutable
|
-- reads dcs zones and makes them accessible and mutable
|
||||||
@ -43,6 +43,7 @@ cfxZones.version = "4.1.1"
|
|||||||
- 4.0.10 - getBoolFromZoneProperty also supports "on" (=true) and "off" (=false)
|
- 4.0.10 - getBoolFromZoneProperty also supports "on" (=true) and "off" (=false)
|
||||||
- 4.1.0 - getBoolFromZoneProperty 'on/off' support for dml variant as well
|
- 4.1.0 - getBoolFromZoneProperty 'on/off' support for dml variant as well
|
||||||
- 4.1.1 - evalRemainder() updates
|
- 4.1.1 - evalRemainder() updates
|
||||||
|
- 4.1.2 - hash property missing warning
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
@ -2299,6 +2300,14 @@ function dmlZone:hasProperty(theProperty)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if string.sub(theProperty, -1) == "#" then
|
||||||
|
local lessOp = theProperty:sub(1,-2)
|
||||||
|
if self:getZoneProperty(lessOp) ~= nil then
|
||||||
|
trigger.action.outText("*** NOTE: " .. self.name .. "'s property <" .. lessOp .. "> may be missing a hash mark ('#') at end", 30)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
|
|||||||
@ -1,37 +1,6 @@
|
|||||||
civAir = {}
|
civAir = {}
|
||||||
civAir.version = "3.0.1"
|
civAir.version = "3.0.2"
|
||||||
--[[--
|
--[[--
|
||||||
1.0.0 initial version
|
|
||||||
1.1.0 exclude list for airfields
|
|
||||||
1.1.1 bug fixes with remove flight
|
|
||||||
and betweenHubs
|
|
||||||
check if slot is really free before spawning
|
|
||||||
add overhead waypoint
|
|
||||||
1.1.2 inAir start possible
|
|
||||||
1.2.0 civAir can use own config file
|
|
||||||
1.2.1 slight update to config file (moved active/idle)
|
|
||||||
1.3.0 add ability to use zones to add closest airfield to
|
|
||||||
trafficCenters or excludeAirfields
|
|
||||||
1.4.0 ability to load config from zone to override
|
|
||||||
all configs it finds
|
|
||||||
module check
|
|
||||||
removed obsolete civAirConfig module
|
|
||||||
1.5.0 process zones as in all other modules
|
|
||||||
verbose is part of config zone
|
|
||||||
reading type array from config corrected
|
|
||||||
massive simplifications: always between zoned airfieds
|
|
||||||
exclude list and include list
|
|
||||||
1.5.1 added depart only and arrive only options for airfields
|
|
||||||
1.5.2 fixed bugs inb verbosity
|
|
||||||
2.0.0 dmlZones
|
|
||||||
inbound zones
|
|
||||||
outbound zones
|
|
||||||
on start location is randomizes 30-70% of the way
|
|
||||||
guarded 'no longer exist' warning for verbosity
|
|
||||||
changed unit naming from -civA to -GA
|
|
||||||
strenghtened guard on testing against free slots for other units
|
|
||||||
flights are now of random neutral countries
|
|
||||||
maxFlights synonym for maxTraffic
|
|
||||||
3.0.0 liveries support
|
3.0.0 liveries support
|
||||||
default liveries for Yak-50 (main test case)
|
default liveries for Yak-50 (main test case)
|
||||||
default liveries for C-130, c-17A, IL-76MD, An-30M, An-26B
|
default liveries for C-130, c-17A, IL-76MD, An-30M, An-26B
|
||||||
@ -45,6 +14,7 @@ civAir.version = "3.0.1"
|
|||||||
3.0.1 protest option, on by default
|
3.0.1 protest option, on by default
|
||||||
protest action
|
protest action
|
||||||
spawning now works correctly for groupType
|
spawning now works correctly for groupType
|
||||||
|
3.0.2 clean-up
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
|
|||||||
@ -259,6 +259,14 @@ function cloneZones.createClonerWithZone(theZone) -- has "Cloner"
|
|||||||
trigger.action.outText("+++clnZ: masterOwner for <" .. theZone.name .. "> set successfully to to itself, currently owned by faction <" .. theZone.owner .. ">", 30)
|
trigger.action.outText("+++clnZ: masterOwner for <" .. theZone.name .. "> set successfully to to itself, currently owned by faction <" .. theZone.owner .. ">", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if theZone.verbose or cloneZones.verbose then
|
||||||
|
trigger.action.outText("+++clnZ: ownership of <" .. theZone.name .. "> tied to zone <" .. theZone.masterOwner .. ">", 30)
|
||||||
|
end
|
||||||
|
-- check that the zone exists in DCS
|
||||||
|
local theMaster = cfxZones.getZoneByName(theZone.masterOwner)
|
||||||
|
if not theMaster then
|
||||||
|
trigger.action.outText("clnZ: WARNING: cloner's <" .. theZone.name .. "> master owner named <" .. theZone.masterOwner .. "> does not exist!", 30)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
theZone.turn = theZone:getNumberFromZoneProperty("turn", 0)
|
theZone.turn = theZone:getNumberFromZoneProperty("turn", 0)
|
||||||
|
|||||||
@ -1,70 +1,9 @@
|
|||||||
csarManager = {}
|
csarManager = {}
|
||||||
csarManager.version = "2.3.2"
|
csarManager.version = "3.0.0"
|
||||||
csarManager.verbose = false
|
|
||||||
csarManager.ups = 1
|
csarManager.ups = 1
|
||||||
|
|
||||||
--[[-- VERSION HISTORY
|
--[[-- VERSION HISTORY
|
||||||
- 1.0.0 initial version
|
|
||||||
- 1.0.1 - smoke optional
|
|
||||||
- airframeCrashed method for airframe manager
|
|
||||||
- removed '(downed )' when re-picked up
|
|
||||||
- fixed oclock
|
|
||||||
- 1.0.2 - hover retrieval
|
|
||||||
- 1.0.3 - corrected a bug in oclock during hovering
|
|
||||||
- 1.0.4 - now correctly allocates pilot to coalition via dcscommon.coalition2county
|
|
||||||
- 1.1.0 - pilot adds weight to unit
|
|
||||||
- module check
|
|
||||||
- 2.0.0 - weight managed via cargoSuper
|
|
||||||
- 2.0.1 - getCSARBaseforZone()
|
|
||||||
- check if zone landed in has owner attribute
|
|
||||||
to provide compatibility with owned zones,
|
|
||||||
FARPZones etc that keep zone.owner up to date
|
|
||||||
- 2.0.2 - use parametric csarManager.hoverAlt
|
|
||||||
- use hoverDuration
|
|
||||||
- 2.0.3 - corrected bug in hoverDuration
|
|
||||||
- 2.0.4 - guard in createCSARMission for cfxCommander
|
|
||||||
- 2.1.0 - startCSAR?
|
|
||||||
- deferrable missions
|
|
||||||
- verbose
|
|
||||||
- ups
|
|
||||||
- useSmoke
|
|
||||||
- smokeColor
|
|
||||||
- reworked smoking the loc
|
|
||||||
- config zone
|
|
||||||
- csarRedDelivered
|
|
||||||
- csarBlueDelivered
|
|
||||||
- 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
|
|
||||||
- 2.2.0 - interface for autoCSAR
|
|
||||||
createDownedPilot() - added existingUnit option
|
|
||||||
createCSARMissionData() - added existinUnit option
|
|
||||||
- when no config zone, runs through empty zone
|
|
||||||
- actionSound
|
|
||||||
- integration with playerScore
|
|
||||||
- score global and per-mission
|
|
||||||
- isCSARTarget API
|
|
||||||
- 2.2.1 - added troopCarriers attribute to config
|
|
||||||
- passes own troop carriers to dcsCommon.isTroopCarrier()
|
|
||||||
- 2.2.2 - enable CSAR missions in water
|
|
||||||
- csar name defaults to zone name
|
|
||||||
- better randomization of pilot's point in csar mission,
|
|
||||||
supports quad zone
|
|
||||||
- 2.2.3 - better support for red/blue
|
|
||||||
- allow neutral pick-up
|
|
||||||
- directions to closest safe zone
|
|
||||||
- CSARBASE attribute now carries coalition
|
|
||||||
- deprecated coalition attribute
|
|
||||||
- 2.2.4 - CSAR attribute value defaults name
|
|
||||||
- start? attribute for CSAR as startCSAR? synonym
|
|
||||||
- 2.2.5 - manual freq for CSAR was off by a factor of 10 - Corrected
|
|
||||||
- 2.2.6 - useFlare, now also launches a flare in addition to smoke
|
|
||||||
- zone testing uses getPoint for zones, supports moving csar zones
|
|
||||||
- 2.3.0 - dmlZones
|
- 2.3.0 - dmlZones
|
||||||
- onRoad attribute for CSAR mission Zones
|
- onRoad attribute for CSAR mission Zones
|
||||||
- rndLoc support
|
- rndLoc support
|
||||||
@ -74,32 +13,27 @@ csarManager.ups = 1
|
|||||||
- offset zone on randomized soldier
|
- offset zone on randomized soldier
|
||||||
- smokeDist
|
- smokeDist
|
||||||
- 2.3.2 - DCS 2.9 getCategory() fix
|
- 2.3.2 - DCS 2.9 getCategory() fix
|
||||||
|
- 3.0.0 - moved mission creation out of update loop into own
|
||||||
|
- removed cfxPlayer dependency
|
||||||
|
- new event manager
|
||||||
|
- no longer single-proccing pilots
|
||||||
|
- can also handle aircraft - isTroopCarrier
|
||||||
|
|
||||||
INTEGRATES AUTOMATICALLY WITH playerScore IF INSTALLED
|
INTEGRATES AUTOMATICALLY WITH playerScore IF INSTALLED
|
||||||
|
INTEGRATES WITH LIMITE AIRFRAMES IF INSTALLED
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
-- modules that need to be loaded BEFORE I run
|
-- modules that need to be loaded BEFORE I run
|
||||||
csarManager.requiredLibs = {
|
csarManager.requiredLibs = {
|
||||||
"dcsCommon", -- common is of course needed for everything
|
"dcsCommon", -- common is of course needed for everything
|
||||||
"cfxZones", -- zones management for CSAR and CSAR Mission zones
|
"cfxZones", -- zones management for CSAR and CSAR Mission zones
|
||||||
"cfxPlayer", -- player monitoring and group monitoring
|
|
||||||
"nameStats", -- generic data module for weight
|
"nameStats", -- generic data module for weight
|
||||||
"cargoSuper",
|
"cargoSuper",
|
||||||
-- "cfxCommander", -- needed only if you want to hand-create CSAR missions
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
--
|
|
||||||
-- OPTIONS
|
|
||||||
--
|
|
||||||
csarManager.useSmoke = true
|
|
||||||
csarManager.smokeColor = 4 -- when using smoke
|
|
||||||
|
|
||||||
|
|
||||||
-- unitConfigs contain the config data for any helicopter
|
-- unitConfigs contain the config data for any helicopter
|
||||||
-- currently in the game. The Array is indexed by unit name
|
-- currently in the game. The Array is indexed by unit name
|
||||||
csarManager.unitConfigs = {}
|
csarManager.unitConfigs = {}
|
||||||
csarManager.myEvents = {3, 4, 5} -- 3 = take off, 4 = land, 5 = crash
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- CASR MISSION
|
-- CASR MISSION
|
||||||
@ -157,15 +91,10 @@ function csarManager.createDownedPilot(theMission, existingUnit)
|
|||||||
aLocation.z,
|
aLocation.z,
|
||||||
-aHeading + 1.5) -- + 1.5 to turn inwards
|
-aHeading + 1.5) -- + 1.5 to turn inwards
|
||||||
|
|
||||||
-- WARNING:
|
local theSideCJTF = dcsCommon.getACountryForCoalition(theMission.side)
|
||||||
-- coalition.addGroup takes the COUNTRY of the group, and derives the
|
|
||||||
-- coalition from that. So if mission.sie is 0, we use UN, if it is 1 (red) it
|
|
||||||
-- is joint red, if 2 it is joint blue
|
|
||||||
local theSideCJTF = dcsCommon.coalition2county(theMission.side) -- get the correct county CJTF
|
|
||||||
theMission.group = coalition.addGroup(theSideCJTF,
|
theMission.group = coalition.addGroup(theSideCJTF,
|
||||||
Group.Category.GROUND,
|
Group.Category.GROUND,
|
||||||
theBoyGroup)
|
theBoyGroup)
|
||||||
|
|
||||||
if theBoyGroup then
|
if theBoyGroup then
|
||||||
|
|
||||||
else
|
else
|
||||||
@ -176,10 +105,10 @@ function csarManager.createDownedPilot(theMission, existingUnit)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- we now use commands to send radio transmissions
|
-- we now use commands to send radio transmissions
|
||||||
local ADF = 20 + math.random(90)
|
local ADF = 20 + math.random(150) -- create a random number between 20 and 110 --> 200'000 .. 1'700'000 KHz = 200KHz .. 1'700 KHz
|
||||||
if theMission.freq then ADF = theMission.freq else theMission.freq = ADF end
|
if theMission.freq then ADF = theMission.freq else theMission.freq = ADF end
|
||||||
local theCommands = cfxCommander.createCommandDataTableFor(theMission.group)
|
local theCommands = cfxCommander.createCommandDataTableFor(theMission.group)
|
||||||
local cmd = cfxCommander.createSetFrequencyCommand(ADF) -- freq in 10000 Hz
|
local cmd = cfxCommander.createSetFrequencyCommand(ADF) -- freq in 10'000 Hz
|
||||||
cfxCommander.addCommand(theCommands, cmd)
|
cfxCommander.addCommand(theCommands, cmd)
|
||||||
cmd = cfxCommander.createTransmissionCommand(csarManager.beaconSound)
|
cmd = cfxCommander.createTransmissionCommand(csarManager.beaconSound)
|
||||||
cfxCommander.addCommand(theCommands, cmd)
|
cfxCommander.addCommand(theCommands, cmd)
|
||||||
@ -259,7 +188,7 @@ end
|
|||||||
-- UNIT CONFIG
|
-- UNIT CONFIG
|
||||||
--
|
--
|
||||||
function csarManager.resetConfig(conf)
|
function csarManager.resetConfig(conf)
|
||||||
-- reset only ovberwrites mission-relevant data
|
-- reset only overwrites mission-relevant data
|
||||||
conf.troopsOnBoard = {} -- number of rescued missions
|
conf.troopsOnBoard = {} -- number of rescued missions
|
||||||
local myName = conf.name
|
local myName = conf.name
|
||||||
cargoSuper.removeAllMassForCargo(myName, "Evacuees") -- will allocate new empty table
|
cargoSuper.removeAllMassForCargo(myName, "Evacuees") -- will allocate new empty table
|
||||||
@ -309,47 +238,17 @@ end
|
|||||||
--
|
--
|
||||||
-- E V E N T H A N D L I N G
|
-- E V E N T H A N D L I N G
|
||||||
--
|
--
|
||||||
function csarManager.isInteresting(eventID)
|
function csarManager:onEvent(event)
|
||||||
-- return true if we are interested in this event, false else
|
|
||||||
for key, evType in pairs(csarManager.myEvents) do
|
|
||||||
if evType == eventID then return true end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function csarManager.preProcessor(event)
|
|
||||||
-- make sure it has an initiator
|
-- make sure it has an initiator
|
||||||
if not event.initiator then return false end -- no initiator
|
if not event.initiator then return end
|
||||||
local theUnit = event.initiator
|
local theUnit = event.initiator
|
||||||
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
|
|
||||||
|
|
||||||
--trigger.action.outText("+++csar: event " .. event.id .. " for cat = " .. cat .. " (helicopter?) unit " .. theUnit:getName(), 30)
|
if not dcsCommon.isPlayerUnit(theUnit) then return end -- not a player unit
|
||||||
|
|
||||||
if not cfxPlayer.isPlayerUnit(theUnit) then
|
-- only proceed if troop carrier (no more helo checks, all troop carriers, so osprey and harrier can be used if so desired)
|
||||||
--trigger.action.outText("+++csar: rejected event: " .. theUnit:getName() .. " not a player helo", 30)
|
if not dcsCommon.isTroopCarrier(theUnit, csarManager.troopCarriers) then return end
|
||||||
return false
|
|
||||||
end -- not a player unit
|
|
||||||
return csarManager.isInteresting(event.id)
|
|
||||||
end
|
|
||||||
|
|
||||||
function csarManager.postProcessor(event)
|
|
||||||
-- don't do anything for now
|
|
||||||
end
|
|
||||||
|
|
||||||
function csarManager.somethingHappened(event)
|
|
||||||
-- when this is invoked, the preprocessor guarantees that
|
|
||||||
-- it's an interesting event
|
|
||||||
-- unit is valid and player
|
|
||||||
-- airframe category is helicopter
|
|
||||||
local theUnit = event.initiator
|
|
||||||
local ID = event.id
|
local ID = event.id
|
||||||
|
|
||||||
local myType = theUnit:getTypeName()
|
|
||||||
|
|
||||||
if ID == 4 then -- landed
|
if ID == 4 then -- landed
|
||||||
csarManager.heloLanded(theUnit)
|
csarManager.heloLanded(theUnit)
|
||||||
end
|
end
|
||||||
@ -362,15 +261,16 @@ function csarManager.somethingHappened(event)
|
|||||||
csarManager.heloCrashed(theUnit)
|
csarManager.heloCrashed(theUnit)
|
||||||
end
|
end
|
||||||
|
|
||||||
csarManager.setCommsMenu(theUnit)
|
if ID == 15 then -- player helicopter birth
|
||||||
|
-- we need to set up comms for this unit
|
||||||
|
csarManager.setCommsMenu(theUnit)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
--
|
|
||||||
--
|
--
|
||||||
-- CSAR LANDED
|
-- CSAR LANDED
|
||||||
--
|
--
|
||||||
--
|
|
||||||
|
|
||||||
function csarManager.successMission(who, where, theMission)
|
function csarManager.successMission(who, where, theMission)
|
||||||
-- who is
|
-- who is
|
||||||
-- where is
|
-- where is
|
||||||
@ -397,7 +297,6 @@ function csarManager.successMission(who, where, theMission)
|
|||||||
|
|
||||||
-- now call callback for coalition side
|
-- now call callback for coalition side
|
||||||
-- callback has format callback(coalition, success true/false, numberSaved, descriptionText)
|
-- callback has format callback(coalition, success true/false, numberSaved, descriptionText)
|
||||||
|
|
||||||
csarManager.invokeCallbacks(theMission.side, true, 1, "success")
|
csarManager.invokeCallbacks(theMission.side, true, 1, "success")
|
||||||
|
|
||||||
trigger.action.outSoundForCoalition(theMission.side, csarManager.actionSound) -- "Quest Snare 3.wav")
|
trigger.action.outSoundForCoalition(theMission.side, csarManager.actionSound) -- "Quest Snare 3.wav")
|
||||||
@ -491,13 +390,11 @@ function csarManager.heloLanded(theUnit)
|
|||||||
conf.troopsOnBoard = {} -- empty out troops on board
|
conf.troopsOnBoard = {} -- empty out troops on board
|
||||||
-- we do *not* return so we can pick up troops on
|
-- we do *not* return so we can pick up troops on
|
||||||
-- a CSARBASE if they were dropped there
|
-- a CSARBASE if they were dropped there
|
||||||
|
|
||||||
else
|
else
|
||||||
if csarManager.verbose or base.zone.verbose then
|
if csarManager.verbose or base.zone.verbose then
|
||||||
trigger.action.outText("+++csar: touchdown of <" .. myName .. "> occured outside of csar zone <" .. base.zone.name .. ">", 30)
|
trigger.action.outText("+++csar: touchdown of <" .. myName .. "> occured outside of csar zone <" .. base.zone.name .. ">", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
else -- not on my side
|
else -- not on my side
|
||||||
if csarManager.verbose or base.zone.verbose then
|
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)
|
trigger.action.outText("+++csar: base <" .. base.zone.name .. "> is on side <" .. currentBaseSide .. ">, which is not on my side <" .. mySide .. ">.", 30)
|
||||||
@ -930,46 +827,6 @@ function csarManager.directions(args)
|
|||||||
trigger.action.outTextForGroup(conf.id, report, 30)
|
trigger.action.outTextForGroup(conf.id, report, 30)
|
||||||
trigger.action.outSoundForGroup(conf.id, csarManager.actionSound)
|
trigger.action.outSoundForGroup(conf.id, csarManager.actionSound)
|
||||||
end
|
end
|
||||||
--
|
|
||||||
-- Player event callbacks
|
|
||||||
--
|
|
||||||
function csarManager.playerChangeEvent(evType, description, player, data)
|
|
||||||
if evType == "newGroup" then
|
|
||||||
local theUnit = data.primeUnit
|
|
||||||
if not dcsCommon.isTroopCarrier(theUnit, csarManager.troopCarriers) then return end
|
|
||||||
|
|
||||||
csarManager.setCommsMenu(theUnit) -- allocates new config
|
|
||||||
-- trigger.action.outText("+++csar: added " .. theUnit:getName() .. " to comms menu", 30)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if evType == "removeGroup" then
|
|
||||||
-- trigger.action.outText("+++csar: a group disappeared", 30)
|
|
||||||
local conf = csarManager.getConfigForUnitNamed(data.primeUnitName)
|
|
||||||
if conf then
|
|
||||||
csarManager.removeCommsFromConfig(conf)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if evType == "leave" then
|
|
||||||
local conf = csarManager.getConfigForUnitNamed(player.unitName)
|
|
||||||
if conf then
|
|
||||||
csarManager.resetConfig(conf)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if evType == "unit" then
|
|
||||||
-- player changed units. almost never in MP, but possible in solo
|
|
||||||
-- because of 1 seconds timing loop
|
|
||||||
-- will result in a new group appearing and a group disappearing, so we are good,
|
|
||||||
-- except we need to reset the conf so no troops are carried any longer
|
|
||||||
local conf = csarManager.getConfigForUnitNamed(data.oldUnitName)
|
|
||||||
if conf then
|
|
||||||
csarManager.resetConfig(conf)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--
|
--
|
||||||
-- CSAR Bases
|
-- CSAR Bases
|
||||||
@ -1056,6 +913,10 @@ function csarManager.launchFlare(args)
|
|||||||
trigger.action.signalFlare(loc, color, 0)
|
trigger.action.signalFlare(loc, color, 0)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- WE ASSUME MISSIONS AREN'T TOO CLOSE TOGETHER TO
|
||||||
|
-- MESS UP MESSAGING OR PICKUP
|
||||||
|
-- if they are less than 2d apart, they can crosstalk each other
|
||||||
function csarManager.update() -- every second
|
function csarManager.update() -- every second
|
||||||
-- schedule next invocation
|
-- schedule next invocation
|
||||||
timer.scheduleFunction(csarManager.update, {}, timer.getTime() + 1/csarManager.ups)
|
timer.scheduleFunction(csarManager.update, {}, timer.getTime() + 1/csarManager.ups)
|
||||||
@ -1065,147 +926,161 @@ function csarManager.update() -- every second
|
|||||||
|
|
||||||
-- now scan through all helo groups and see if they are close to a
|
-- now scan through all helo groups and see if they are close to a
|
||||||
-- CSAR zone and initiate the help sequence
|
-- CSAR zone and initiate the help sequence
|
||||||
local allPlayerGroups = cfxPlayerGroups -- cfxPlayerGroups is a global, don't fuck with it!
|
-- local allPlayerGroups = cfxPlayerGroups -- cfxPlayerGroups is a global, don't fuck with it!
|
||||||
-- contains per group a player record, use prime unit to access player's unit
|
local allPlayerUnits = dcsCommon.getAllExistingPlayersAndUnits() -- indexed by player name
|
||||||
for gname, pgroup in pairs(allPlayerGroups) do
|
--old -- contains per group a player record, use prime unit to access player's unit
|
||||||
local aUnit = pgroup.primeUnit -- get prime unit of that group
|
for pname, aUnit in pairs(allPlayerUnits) do
|
||||||
if aUnit:isExist() and aUnit:inAir() then -- exists and is flying
|
if --aUnit:isExist() and
|
||||||
|
aUnit:inAir() and
|
||||||
|
dcsCommon.isTroopCarrier(aUnit, csarManager.troopCarriers)
|
||||||
|
then -- troop carrier and is flying
|
||||||
local uPoint = aUnit:getPoint()
|
local uPoint = aUnit:getPoint()
|
||||||
local uName = aUnit:getName()
|
local uName = aUnit:getName()
|
||||||
local uGroup = aUnit:getGroup()
|
local uGroup = aUnit:getGroup()
|
||||||
local uID = uGroup:getID()
|
local uID = uGroup:getID()
|
||||||
local uSide = aUnit:getCoalition()
|
local uSide = aUnit:getCoalition()
|
||||||
local agl = dcsCommon.getUnitAGL(aUnit)
|
local agl = dcsCommon.getUnitAGL(aUnit)
|
||||||
if dcsCommon.isTroopCarrier(aUnit, csarManager.troopCarriers) then
|
local needsGC = false
|
||||||
-- scan through all available csar missions to see if we are close
|
-- local hasMessaged = false
|
||||||
-- enough to trigger comms
|
for idx, csarMission in pairs (csarManager.openMissions) do
|
||||||
for idx, csarMission in pairs (csarManager.openMissions) do
|
-- check if we are inside trigger range on the same side
|
||||||
-- check if we are inside trigger range on the same side
|
local mp = cfxZones.getPoint(csarMission.zone, true)
|
||||||
local mp = cfxZones.getPoint(csarMission.zone, true)
|
local d = dcsCommon.distFlat(uPoint, mp)
|
||||||
local d = dcsCommon.distFlat(uPoint, mp)
|
if ((uSide == csarMission.side) or (csarMission.side == 0) )
|
||||||
if ((uSide == csarMission.side) or (csarMission.side == 0) )
|
and (d < csarManager.rescueTriggerRange) then
|
||||||
and (d < csarManager.rescueTriggerRange) then
|
-- we are in trigger distance. if we did not notify before
|
||||||
-- we are in trigger distance. if we did not notify before
|
-- do it now, we ever only do this once for a unit for any mission
|
||||||
-- do it now
|
if not dcsCommon.arrayContainsString(csarMission.messagedUnits, uName) then
|
||||||
if not dcsCommon.arrayContainsString(csarMission.messagedUnits, uName) then
|
-- radio this unit with oclock and tell it they are in 2k range
|
||||||
-- radio this unit with oclock and tell it they are in 2k range
|
-- also note if LZ is hot
|
||||||
-- also note if LZ is hot
|
local ownHeading = dcsCommon.getUnitHeadingDegrees(aUnit)
|
||||||
local ownHeading = dcsCommon.getUnitHeadingDegrees(aUnit)
|
local oclock = dcsCommon.clockPositionOfARelativeToB(csarMission.zone.point, uPoint, ownHeading) .. " o'clock"
|
||||||
local oclock = dcsCommon.clockPositionOfARelativeToB(csarMission.zone.point, uPoint, ownHeading) .. " o'clock"
|
local msg = "\n" .. uName ..", " .. csarMission.name .. ". We can hear you, check your " .. oclock
|
||||||
local msg = "\n" .. uName ..", " .. csarMission.name .. ". We can hear you, check your " .. oclock
|
if csarManager.useSmoke then msg = msg .. " - popping smoke" end
|
||||||
if csarManager.useSmoke then msg = msg .. " - popping smoke" end
|
if csarManager.useFlare then
|
||||||
if csarManager.useFlare then
|
if csarManager.useSmoke then
|
||||||
if csarManager.useSmoke then
|
msg = msg .. " and will launch flare in a few seconds"
|
||||||
msg = msg .. " and will launch flare in a few seconds"
|
|
||||||
else
|
|
||||||
msg = msg .. " - preparing flare"
|
|
||||||
end
|
|
||||||
-- schedule flare launch in 5-10 seconds
|
|
||||||
local args = {}
|
|
||||||
args.loc = mp
|
|
||||||
args.color = csarManager.flareColor
|
|
||||||
args.uID = uID
|
|
||||||
timer.scheduleFunction(csarManager.launchFlare, args, timer.getTime() + math.random(5))
|
|
||||||
end
|
|
||||||
msg = msg .. "."
|
|
||||||
|
|
||||||
if csarMission.isHot then
|
|
||||||
msg = msg .. " Be advised: LZ is hot."
|
|
||||||
end
|
|
||||||
msg = msg .. "\n"
|
|
||||||
trigger.action.outTextForGroup(uID, msg, 30)
|
|
||||||
trigger.action.outSoundForGroup(uID, csarManager.actionSound) -- "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 5 minutes ago
|
|
||||||
if csarManager.useSmoke and (timer.getTime() - csarMission.lastSmokeTime) >= 5 * 60 then
|
|
||||||
local smokePoint = dcsCommon.randomPointOnPerimeter(
|
|
||||||
csarManager.smokeDist, csarMission.zone.point.x, csarMission.zone.point.z) --cfxZones.createHeightCorrectedPoint(csarMission.zone.point)
|
|
||||||
-- trigger.action.smoke(smokePoint, 4 )
|
|
||||||
dcsCommon.markPointWithSmoke(smokePoint, csarManager.smokeColor)
|
|
||||||
csarMission.lastSmokeTime = timer.getTime()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- now check if we are inside hover range and alt
|
|
||||||
-- in order to simultate winch ops
|
|
||||||
-- WARNING: WE ALWAYS ONLY CHECK A SINGLE UNIT - the first alive
|
|
||||||
local evacuee = csarMission.group:getUnit(1)
|
|
||||||
if evacuee then
|
|
||||||
local ep = evacuee:getPoint()
|
|
||||||
d = dcsCommon.distFlat(uPoint, ep)
|
|
||||||
d = math.floor(d * 10) / 10
|
|
||||||
if d < csarManager.rescueTriggerRange * 0.5 then --csarManager.hoverRadius * 2 then
|
|
||||||
local ownHeading = dcsCommon.getUnitHeadingDegrees(aUnit)
|
|
||||||
local oclock = dcsCommon.clockPositionOfARelativeToB(ep, uPoint, ownHeading) .. " o'clock"
|
|
||||||
-- log distance
|
|
||||||
local hoverMsg = "Closing on " .. csarMission.name .. ", " .. d * 1 .. "m on your " .. oclock .. " o'clock"
|
|
||||||
|
|
||||||
if d < csarManager.hoverRadius then
|
|
||||||
if (agl <= csarManager.hoverAlt) and (agl > 3) then
|
|
||||||
local hoverTime = csarMission.hoveringUnits[uName]
|
|
||||||
if not hoverTime then
|
|
||||||
-- create new entry
|
|
||||||
hoverTime = timer.getTime()
|
|
||||||
csarMission.hoveringUnits[uName] = timer.getTime()
|
|
||||||
end
|
|
||||||
hoverTime = timer.getTime() - hoverTime -- calculate number of seconds
|
|
||||||
local remainder = math.floor(csarManager.hoverDuration - hoverTime)
|
|
||||||
if remainder < 1 then remainder = 1 end
|
|
||||||
hoverMsg = "Steady... " .. d * 1 .. "m to your " .. oclock .. " o'clock, winching... (" .. remainder .. ")"
|
|
||||||
if hoverTime > csarManager.hoverDuration then
|
|
||||||
-- we rescued the guy!
|
|
||||||
hoverMsg = "We have " .. csarMission.name .. " safely on board!"
|
|
||||||
local conf = csarManager.getUnitConfig(aUnit)
|
|
||||||
csarManager.removeMission(csarMission)
|
|
||||||
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, csarManager.actionSound) --"Quest Snare 3.wav")
|
|
||||||
|
|
||||||
return -- we only ever rescue one
|
|
||||||
end -- hovered long enough
|
|
||||||
trigger.action.outTextForGroup(uID, hoverMsg, 30, true)
|
|
||||||
return -- only ever one winch op
|
|
||||||
else -- too high for hover
|
|
||||||
hoverMsg = "Evacuee " .. d * 1 .. "m on your " .. oclock .. " o'clock; land or descend to between 10 and 90 AGL for winching"
|
|
||||||
csarMission.hoveringUnits[uName] = nil -- reset timer
|
|
||||||
end
|
|
||||||
else -- not inside hover dist
|
|
||||||
-- remove the hover indicator for this
|
|
||||||
csarMission.hoveringUnits[uName] = nil
|
|
||||||
end
|
|
||||||
trigger.action.outTextForGroup(uID, hoverMsg, 30, true)
|
|
||||||
return -- only ever one winch op
|
|
||||||
else
|
else
|
||||||
-- remove the hover indicator for this unit
|
msg = msg .. " - preparing flare"
|
||||||
csarMission.hoveringUnits[uName] = nil
|
end
|
||||||
end -- inside 2 * hover dist?
|
-- schedule flare launch in 5-10 seconds
|
||||||
|
local args = {}
|
||||||
|
args.loc = mp
|
||||||
|
args.color = csarManager.flareColor
|
||||||
|
args.uID = uID
|
||||||
|
timer.scheduleFunction(csarManager.launchFlare, args, timer.getTime() + math.random(5))
|
||||||
|
end
|
||||||
|
msg = msg .. "."
|
||||||
|
|
||||||
end -- has evacuee
|
if csarMission.isHot then
|
||||||
end -- if in range
|
msg = msg .. " Be advised: LZ is hot."
|
||||||
end -- for all missions
|
end
|
||||||
end -- if troop carrier
|
msg = msg .. "\n"
|
||||||
end -- if exists
|
trigger.action.outTextForGroup(uID, msg, 30)
|
||||||
end -- for all players
|
trigger.action.outSoundForGroup(uID, csarManager.actionSound) -- "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 5 minutes ago
|
||||||
|
if csarManager.useSmoke and (timer.getTime() - csarMission.lastSmokeTime) >= 5 * 60 then
|
||||||
|
local smokePoint = dcsCommon.randomPointOnPerimeter(
|
||||||
|
csarManager.smokeDist, csarMission.zone.point.x, csarMission.zone.point.z)
|
||||||
|
dcsCommon.markPointWithSmoke(smokePoint, csarManager.smokeColor)
|
||||||
|
csarMission.lastSmokeTime = timer.getTime()
|
||||||
|
end
|
||||||
|
|
||||||
|
-- now check if we are inside hover range and alt
|
||||||
|
-- in order to simultate winch ops
|
||||||
|
-- if competition picked up, we skip this loop
|
||||||
|
local evacuee = nil
|
||||||
|
if csarMission.group then evacuee = csarMission.group:getUnit(1) end
|
||||||
|
if evacuee then
|
||||||
|
local ep = evacuee:getPoint()
|
||||||
|
d = dcsCommon.distFlat(uPoint, ep)
|
||||||
|
d = math.floor(d * 10) / 10
|
||||||
|
if d < csarManager.rescueTriggerRange * 0.5 then
|
||||||
|
local ownHeading = dcsCommon.getUnitHeadingDegrees(aUnit)
|
||||||
|
local oclock = dcsCommon.clockPositionOfARelativeToB(ep, uPoint, ownHeading) .. " o'clock"
|
||||||
|
-- log distance
|
||||||
|
local hoverMsg = "Closing on " .. csarMission.name .. ", " .. d * 1 .. "m on your " .. oclock .. " o'clock"
|
||||||
|
|
||||||
|
if d < csarManager.hoverRadius then
|
||||||
|
if (agl <= csarManager.hoverAlt) and (agl > 3) then
|
||||||
|
local hoverTime = csarMission.hoveringUnits[uName]
|
||||||
|
if not hoverTime then
|
||||||
|
-- create new entry
|
||||||
|
hoverTime = timer.getTime()
|
||||||
|
csarMission.hoveringUnits[uName] = timer.getTime()
|
||||||
|
end
|
||||||
|
hoverTime = timer.getTime() - hoverTime -- calculate number of seconds
|
||||||
|
local remainder = math.floor(csarManager.hoverDuration - hoverTime)
|
||||||
|
if remainder < 1 then remainder = 1 end
|
||||||
|
hoverMsg = "Steady... " .. d * 1 .. "m to your " .. oclock .. " o'clock, winching... (" .. remainder .. ")"
|
||||||
|
if hoverTime > csarManager.hoverDuration then
|
||||||
|
-- we rescued the guy!
|
||||||
|
hoverMsg = "We have " .. csarMission.name .. " safely on board!"
|
||||||
|
local conf = csarManager.getUnitConfig(aUnit)
|
||||||
|
-- mission now GC's after iteration csarManager.removeMission(csarMission)
|
||||||
|
table.insert(conf.troopsOnBoard, csarMission)
|
||||||
|
csarMission.group:destroy() -- will shut up radio as well
|
||||||
|
csarMission.group = nil -- no more evacuees
|
||||||
|
needsGC = true -- need filtering missions
|
||||||
|
|
||||||
|
-- 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, csarManager.actionSound)
|
||||||
|
|
||||||
|
--return -- we only ever rescue one
|
||||||
|
end -- hovered long enough
|
||||||
|
--trigger.action.outTextForGroup(uID, hoverMsg, 30, true)
|
||||||
|
-- return -- only ever one winch op
|
||||||
|
else -- too high for hover
|
||||||
|
hoverMsg = "Evacuee " .. d * 1 .. "m on your " .. oclock .. " o'clock; land or descend to between 10 and 90 AGL for winching"
|
||||||
|
csarMission.hoveringUnits[uName] = nil -- reset timer
|
||||||
|
end
|
||||||
|
else -- not inside hover dist
|
||||||
|
-- remove the hover indicator for this
|
||||||
|
csarMission.hoveringUnits[uName] = nil
|
||||||
|
end
|
||||||
|
trigger.action.outTextForGroup(uID, hoverMsg, 30, true)
|
||||||
|
--return -- only ever one winch op
|
||||||
|
else
|
||||||
|
-- remove the hover indicator for this unit
|
||||||
|
csarMission.hoveringUnits[uName] = nil
|
||||||
|
end -- inside 2 * hover dist?
|
||||||
|
else
|
||||||
|
-- somebody snatched the evacuee
|
||||||
|
end -- if has evacuee
|
||||||
|
end -- if in range
|
||||||
|
end -- for all missions
|
||||||
|
-- now GC all missions if we lifted a pilot up (we no longer return after first succesful)
|
||||||
|
if needsGC then
|
||||||
|
local filtered = {}
|
||||||
|
for idx, csarMission in pairs(csarManager.openMissions) do
|
||||||
|
if csarMission.group then
|
||||||
|
table.insert(filtered, csarMission)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
csarManager.openMissions = filtered
|
||||||
|
end
|
||||||
|
end -- if in Air
|
||||||
|
end -- for all player units
|
||||||
|
|
||||||
-- now see and check if we need to spawn from a csar zone
|
-- now see and check if we need to spawn from a csar zone
|
||||||
-- that has been told to spawn
|
-- that has been told to spawn
|
||||||
@ -1216,32 +1091,37 @@ function csarManager.update() -- every second
|
|||||||
-- local currVal = theZone:getFlagValue(theZone.startCSAR)
|
-- local currVal = theZone:getFlagValue(theZone.startCSAR)
|
||||||
-- if currVal ~= theZone.lastCSARVal then
|
-- if currVal ~= theZone.lastCSARVal then
|
||||||
if theZone:testZoneFlag(theZone.startCSAR, theZone.triggerMethod, "lastCSARVal") then
|
if theZone:testZoneFlag(theZone.startCSAR, theZone.triggerMethod, "lastCSARVal") then
|
||||||
-- set up random point in zone
|
local theMission = csarManager.createCSARMissionFromZone(theZone)
|
||||||
local mPoint = theZone:getPoint()
|
|
||||||
if theZone.rndLoc then mPoint = theZone:createRandomPointInZone() end
|
|
||||||
if theZone.onRoad then
|
|
||||||
mPoint.x, mPoint.z = land.getClosestPointOnRoads('roads',mPoint.x, mPoint.z)
|
|
||||||
end
|
|
||||||
local theMission = csarManager.createCSARMissionData(
|
|
||||||
mPoint,
|
|
||||||
theZone.csarSide, -- theSide
|
|
||||||
theZone.csarFreq, -- freq
|
|
||||||
theZone.csarName, -- name
|
|
||||||
theZone.numCrew, -- numCrew
|
|
||||||
theZone.timeLimit, -- timeLimit
|
|
||||||
theZone.csarMapMarker, -- mapMarker
|
|
||||||
0.1, --theZone.radius) -- radius
|
|
||||||
nil) -- parashoo unit
|
|
||||||
csarManager.addMission(theMission)
|
csarManager.addMission(theMission)
|
||||||
--theZone.lastCSARVal = currVal
|
--theZone.lastCSARVal = currVal
|
||||||
if csarManager.verbose then
|
if csarManager.verbose or theZone.verbose then
|
||||||
trigger.action.outText("+++csar: started CSAR mission " .. theZone.csarName, 30)
|
trigger.action.outText("+++csar: started CSAR mission for <" .. theZone.csarName .. ">", 30)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function csarManager.createCSARMissionFromZone(theZone)
|
||||||
|
-- set up random point in zone
|
||||||
|
local mPoint = theZone:getPoint()
|
||||||
|
if theZone.rndLoc then mPoint = theZone:createRandomPointInZone() end
|
||||||
|
if theZone.onRoad then
|
||||||
|
mPoint.x, mPoint.z = land.getClosestPointOnRoads('roads',mPoint.x, mPoint.z)
|
||||||
|
end
|
||||||
|
local theMission = csarManager.createCSARMissionData(
|
||||||
|
mPoint,
|
||||||
|
theZone.csarSide, -- theSide
|
||||||
|
theZone.csarFreq, -- freq
|
||||||
|
theZone.csarName, -- name
|
||||||
|
theZone.numCrew, -- numCrew
|
||||||
|
theZone.timeLimit, -- timeLimit
|
||||||
|
theZone.csarMapMarker, -- mapMarker
|
||||||
|
0.1, --theZone.radius) -- radius
|
||||||
|
nil) -- parashoo unit
|
||||||
|
return theMission
|
||||||
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- create a CSAR Mission for a unit
|
-- create a CSAR Mission for a unit
|
||||||
--
|
--
|
||||||
@ -1412,9 +1292,6 @@ function csarManager.readConfigZone()
|
|||||||
csarManager.name = "csarManagerConfig" -- compat with cfxZones
|
csarManager.name = "csarManagerConfig" -- compat with cfxZones
|
||||||
local theZone = cfxZones.getZoneByName("csarManagerConfig")
|
local theZone = cfxZones.getZoneByName("csarManagerConfig")
|
||||||
if not theZone then
|
if not theZone then
|
||||||
if csarManager.verbose then
|
|
||||||
trigger.action.outText("+++csar: NO config zone!", 30)
|
|
||||||
end
|
|
||||||
theZone = cfxZones.createSimpleZone("csarManagerConfig")
|
theZone = cfxZones.createSimpleZone("csarManagerConfig")
|
||||||
end
|
end
|
||||||
csarManager.configZone = theZone -- save for flag banging compatibility
|
csarManager.configZone = theZone -- save for flag banging compatibility
|
||||||
@ -1487,20 +1364,6 @@ function csarManager.start()
|
|||||||
-- read config
|
-- read config
|
||||||
csarManager.readConfigZone()
|
csarManager.readConfigZone()
|
||||||
|
|
||||||
-- install callbacks for helo-relevant events
|
|
||||||
dcsCommon.addEventHandler(csarManager.somethingHappened, csarManager.preProcessor, csarManager.postProcessor)
|
|
||||||
|
|
||||||
-- now iterate through all player groups and install the CSAR Menu
|
|
||||||
|
|
||||||
local allPlayerGroups = cfxPlayerGroups -- cfxPlayerGroups is a global, don't fuck with it!
|
|
||||||
-- contains per group a player record, use prime unit to access player's unit
|
|
||||||
for gname, pgroup in pairs(allPlayerGroups) do
|
|
||||||
local aUnit = pgroup.primeUnit -- get prime unit of that group
|
|
||||||
csarManager.setCommsMenu(aUnit)
|
|
||||||
end
|
|
||||||
-- now install the new group notifier for new groups so we can remove and add CSAR menus
|
|
||||||
cfxPlayer.addMonitor(csarManager.playerChangeEvent)
|
|
||||||
|
|
||||||
-- now scan all zones that are CSAR drop-off for quick access
|
-- now scan all zones that are CSAR drop-off for quick access
|
||||||
csarManager.processCSARBASE()
|
csarManager.processCSARBASE()
|
||||||
|
|
||||||
@ -1508,17 +1371,27 @@ function csarManager.start()
|
|||||||
-- and populate the available mission.
|
-- and populate the available mission.
|
||||||
csarManager.processCSARZones()
|
csarManager.processCSARZones()
|
||||||
|
|
||||||
-- now call update so we can monitor progress of all helos, and alert them
|
-- install callbacks for helo-relevant events
|
||||||
-- when they are close to a CSAR
|
--dcsCommon.addEventHandler(csarManager.somethingHappened, csarManager.preProcessor, csarManager.postProcessor)
|
||||||
|
world.addEventHandler(csarManager)
|
||||||
|
|
||||||
|
-- now iterate through all player groups and install the CSAR Menu
|
||||||
|
local allPlayerUnits = dcsCommon.getAllExistingPlayerUnitsRaw()
|
||||||
|
for pName, aUnit in pairs(allPlayerUnits) do
|
||||||
|
csarManager.setCommsMenu(aUnit)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- start updating and track all helicopters in the air against missions
|
||||||
csarManager.update()
|
csarManager.update()
|
||||||
|
|
||||||
-- say hi!
|
-- say hi!
|
||||||
trigger.action.outText("cf/x CSAR v" .. csarManager.version .. " started", 30)
|
trigger.action.outText("cf/x CSAR Manager v" .. csarManager.version .. " started", 30)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- let's get rolling
|
-- let's get rolling
|
||||||
if not csarManager.start() then
|
if not csarManager.start() then
|
||||||
|
trigger.action.outText("cf/x CSAR Manager v" .. csarManager.version .. " FAILED to run", 30)
|
||||||
csarManager = nil
|
csarManager = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -1540,5 +1413,6 @@ end
|
|||||||
|
|
||||||
-- allow any airfied to be csarsafe by default, no longer *requires* csarbase
|
-- allow any airfied to be csarsafe by default, no longer *requires* csarbase
|
||||||
|
|
||||||
-- remove cfxPlayer dependency
|
-- minFreq, maxFreq settings for config and mission-individual
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
@ -1,5 +1,5 @@
|
|||||||
dcsCommon = {}
|
dcsCommon = {}
|
||||||
dcsCommon.version = "3.0.0"
|
dcsCommon.version = "3.0.1"
|
||||||
--[[-- VERSION HISTORY
|
--[[-- VERSION HISTORY
|
||||||
3.0.0 - removed bad bug in stringStartsWith, only relevant if caseSensitive is false
|
3.0.0 - removed bad bug in stringStartsWith, only relevant if caseSensitive is false
|
||||||
- point2text new intsOnly option
|
- point2text new intsOnly option
|
||||||
@ -8,6 +8,7 @@ dcsCommon.version = "3.0.0"
|
|||||||
- new pointInDirectionOfPointXYY()
|
- new pointInDirectionOfPointXYY()
|
||||||
- createGroundGroupWithUnits now supports liveries
|
- createGroundGroupWithUnits now supports liveries
|
||||||
- new getAllExistingPlayersAndUnits()
|
- new getAllExistingPlayersAndUnits()
|
||||||
|
3.0.1 - clone: better handling of string type
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
-- dcsCommon is a library of common lua functions
|
-- dcsCommon is a library of common lua functions
|
||||||
@ -1187,6 +1188,9 @@ dcsCommon.version = "3.0.0"
|
|||||||
copy = tmp
|
copy = tmp
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
elseif orig_type == "string" then
|
||||||
|
local tmp = ""
|
||||||
|
copy = tmp .. orig
|
||||||
else -- number, string, boolean, etc
|
else -- number, string, boolean, etc
|
||||||
copy = orig
|
copy = orig
|
||||||
end
|
end
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
factoryZone = {}
|
factoryZone = {}
|
||||||
factoryZone.version = "3.0.0"
|
factoryZone.version = "3.1.0"
|
||||||
factoryZone.verbose = false
|
factoryZone.verbose = false
|
||||||
factoryZone.name = "factoryZone"
|
factoryZone.name = "factoryZone"
|
||||||
|
|
||||||
@ -11,6 +11,12 @@ factoryZone.name = "factoryZone"
|
|||||||
- use maxRadius from zone for spawning to support quad zones
|
- use maxRadius from zone for spawning to support quad zones
|
||||||
3.0.0 - support for liveries via "factoryLiveries" zone
|
3.0.0 - support for liveries via "factoryLiveries" zone
|
||||||
- OOP dmlZones
|
- OOP dmlZones
|
||||||
|
3.1.0 - redD!, blueD!
|
||||||
|
- redP!, blueP!
|
||||||
|
- method
|
||||||
|
- productionTime config synonyme
|
||||||
|
- defendMe? attribute
|
||||||
|
- triggered 'shocked' mode via defendMe
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
factoryZone.requiredLibs = {
|
factoryZone.requiredLibs = {
|
||||||
@ -104,16 +110,55 @@ function factoryZone.addFactoryZone(aZone)
|
|||||||
aZone.factoryTriggerMethod = aZone:getStringFromZoneProperty( "factoryTriggerMethod", "change")
|
aZone.factoryTriggerMethod = aZone:getStringFromZoneProperty( "factoryTriggerMethod", "change")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
aZone.factoryMethod = aZone:getStringFromZoneProperty("factoryMethod", "inc")
|
||||||
|
if aZone:hasProperty("method") then
|
||||||
|
aZone.factoryMethod = aZone:getStringFromZoneProperty("method", "inc")
|
||||||
|
end
|
||||||
|
|
||||||
|
if aZone:hasProperty("redP!") then
|
||||||
|
aZone.redP = aZone:getStringFromZoneProperty("redP!", "none")
|
||||||
|
end
|
||||||
|
if aZone.redP and aZone.attackersRED ~= "none" then
|
||||||
|
trigger.action.outText("***WARNING: factory <" .. aZone.name .. "> has RED production and uses 'redP!'", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
if aZone:hasProperty("blueP!") then
|
||||||
|
aZone.blueP = aZone:getStringFromZoneProperty("blueP!", "none")
|
||||||
|
end
|
||||||
|
if aZone.blueP and aZone.attackersBLUE ~= "none" then
|
||||||
|
trigger.action.outText("***WARNING: factory <" .. aZone.name .. "> has BLUE production and uses 'blueP!'", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
if aZone:hasProperty("redD!") then
|
||||||
|
aZone.redD = aZone:getStringFromZoneProperty("redD!", "none")
|
||||||
|
end
|
||||||
|
if aZone.redD and aZone.defendersRED ~= "none" then
|
||||||
|
trigger.action.outText("***WARNING: factory <" .. aZone.name .. "> has RED defenders and uses 'redD!'", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if aZone:hasProperty("blueD!") then
|
||||||
|
aZone.blueD = aZone:getStringFromZoneProperty("blueD!", "none")
|
||||||
|
end
|
||||||
|
if aZone.blueD and aZone.defendersBLUE ~= "none" then
|
||||||
|
trigger.action.outText("***WARNING: factory <" .. aZone.name .. "> has BLUE defenders and uses 'blueD!'", 30)
|
||||||
|
end
|
||||||
|
|
||||||
|
if aZone:hasProperty("defendMe?") then
|
||||||
|
aZone.defendMe = aZone:getStringFromZoneProperty("defendMe?", "none")
|
||||||
|
aZone.lastDefendMeValue = trigger.misc.getUserFlag(aZone.defendMe)
|
||||||
|
end
|
||||||
|
|
||||||
factoryZone.zones[aZone.name] = aZone
|
factoryZone.zones[aZone.name] = aZone
|
||||||
factoryZone.verifyZone(aZone)
|
factoryZone.verifyZone(aZone)
|
||||||
end
|
end
|
||||||
|
|
||||||
function factoryZone.verifyZone(aZone)
|
function factoryZone.verifyZone(aZone)
|
||||||
-- do some sanity checks
|
-- do some sanity checks
|
||||||
if not cfxGroundTroops and (aZone.attackersRED ~= "none" or aZone.attackersBLUE ~= "none") then
|
-- if not cfxGroundTroops and (aZone.attackersRED ~= "none" or aZone.attackersBLUE ~= "none") then
|
||||||
trigger.action.outText("+++factZ: " .. aZone.name .. " attackers need cfxGroundTroops to function", 30)
|
-- now can also bang on flags, no more verification
|
||||||
end
|
-- unless we want to beef them up
|
||||||
|
-- end
|
||||||
end
|
end
|
||||||
|
|
||||||
function factoryZone.spawnAttackTroops(theTypes, aZone, aCoalition, aFormation)
|
function factoryZone.spawnAttackTroops(theTypes, aZone, aCoalition, aFormation)
|
||||||
@ -183,6 +228,7 @@ end
|
|||||||
--
|
--
|
||||||
|
|
||||||
function factoryZone.sendOutAttackers(aZone)
|
function factoryZone.sendOutAttackers(aZone)
|
||||||
|
|
||||||
-- sanity check: never done for neutral zones
|
-- sanity check: never done for neutral zones
|
||||||
if aZone.owner == 0 then
|
if aZone.owner == 0 then
|
||||||
if aZone.verbose or factoryZone.verbose then
|
if aZone.verbose or factoryZone.verbose then
|
||||||
@ -193,16 +239,31 @@ function factoryZone.sendOutAttackers(aZone)
|
|||||||
|
|
||||||
-- only spawn if there are zones to attack
|
-- only spawn if there are zones to attack
|
||||||
if not cfxOwnedZones.enemiesRemaining(aZone) then
|
if not cfxOwnedZones.enemiesRemaining(aZone) then
|
||||||
if factoryZone.verbose then
|
if aZone.verbose or factoryZone.verbose then
|
||||||
trigger.action.outText("+++factZ - no enemies, resting ".. aZone.name, 30)
|
trigger.action.outText("+++factZ - no enemies, resting ".. aZone.name, 30)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if factoryZone.verbose then
|
if factoryZone.verbose or aZone.verbose then
|
||||||
trigger.action.outText("+++factZ - attack cycle for ".. aZone.name, 30)
|
trigger.action.outText("+++factZ - attack cycle for ".. aZone.name, 30)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- bang on xxxP!
|
||||||
|
if aZone.owner == 1 and aZone.redP then
|
||||||
|
if aZone.verbose or factoryZone.verbose then
|
||||||
|
trigger.action.outText("+++factZ: polling redP! <" .. aZone.redP .. "> for factrory <" .. aZone.name .. ">")
|
||||||
|
end
|
||||||
|
aZone:pollFlag(aZone.redP, aZone.factoryMethod)
|
||||||
|
end
|
||||||
|
|
||||||
|
if aZone.owner == 2 and aZone.blueP then
|
||||||
|
if aZone.verbose or factoryZone.verbose then
|
||||||
|
trigger.action.outText("+++factZ: polling blueP! <" .. aZone.blueP .. "> for factrory <" .. aZone.name .. ">")
|
||||||
|
end
|
||||||
|
aZone:pollFlag(aZone.blueP, aZone.factoryMethod)
|
||||||
|
end
|
||||||
|
|
||||||
-- step one: get the attackers
|
-- step one: get the attackers
|
||||||
local attackers = aZone.attackersRED;
|
local attackers = aZone.attackersRED;
|
||||||
if (aZone.owner == 2) then attackers = aZone.attackersBLUE end
|
if (aZone.owner == 2) then attackers = aZone.attackersBLUE end
|
||||||
@ -248,8 +309,23 @@ function factoryZone.repairDefenders(aZone)
|
|||||||
if (aZone.owner == 2) then defenders = aZone.defendersBLUE end
|
if (aZone.owner == 2) then defenders = aZone.defendersBLUE end
|
||||||
local unitTypes = {} -- build type names
|
local unitTypes = {} -- build type names
|
||||||
|
|
||||||
-- if none, we are done
|
-- if none, we are done, save for the outputs
|
||||||
if defenders == "none" then return end
|
if (not defenders) or (defenders == "none") then
|
||||||
|
if aZone.owner == 1 and aZone.redD then
|
||||||
|
if aZone.verbose or factoryZone.verbose then
|
||||||
|
trigger.action.outText("+++factZ: polling redD! <" .. aZone.redD .. "> for repair factory <" .. aZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
aZone:pollFlag(aZone.redD, aZone.factoryMethod)
|
||||||
|
end
|
||||||
|
|
||||||
|
if aZone.owner == 2 and aZone.blueD then
|
||||||
|
if aZone.verbose or factoryZone.verbose then
|
||||||
|
trigger.action.outText("+++factZ: polling blueD! <" .. aZone.blueD .. "> for repair factory <" .. aZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
aZone:pollFlag(aZone.blueD, aZone.factoryMethod)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
-- split theTypes into an array of types
|
-- split theTypes into an array of types
|
||||||
allTypes = dcsCommon.trimArray(
|
allTypes = dcsCommon.trimArray(
|
||||||
@ -308,6 +384,10 @@ end
|
|||||||
|
|
||||||
function factoryZone.spawnDefenders(aZone)
|
function factoryZone.spawnDefenders(aZone)
|
||||||
-- sanity check: never done for non-neutral zones
|
-- sanity check: never done for non-neutral zones
|
||||||
|
if aZone.verbose or factoryZone.verbose then
|
||||||
|
trigger.action.outText("+++factZ: starting defender cycle for <" .. aZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
|
||||||
if aZone.owner == 0 then
|
if aZone.owner == 0 then
|
||||||
if aZone.verbose or factoryZone.verbose then
|
if aZone.verbose or factoryZone.verbose then
|
||||||
trigger.action.outText("+++factZ: spawnDefenders invoked for NEUTRAL zone <" .. aZone.name .. ">", 30)
|
trigger.action.outText("+++factZ: spawnDefenders invoked for NEUTRAL zone <" .. aZone.name .. ">", 30)
|
||||||
@ -315,7 +395,21 @@ function factoryZone.spawnDefenders(aZone)
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- bang! on xxxD!
|
||||||
local defenders = aZone.defendersRED;
|
local defenders = aZone.defendersRED;
|
||||||
|
if aZone.owner == 1 and aZone.redD then
|
||||||
|
if aZone.verbose or factoryZone.verbose then
|
||||||
|
trigger.action.outText("+++factZ: polling redD! <" .. aZone.redD .. "> for factrory <" .. aZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
aZone:pollFlag(aZone.redD, aZone.factoryMethod)
|
||||||
|
end
|
||||||
|
|
||||||
|
if aZone.owner == 2 and aZone.blueD then
|
||||||
|
if aZone.verbose or factoryZone.verbose then
|
||||||
|
trigger.action.outText("+++factZ: polling blueD! <" .. aZone.blueD .. "> for factory <" .. aZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
aZone:pollFlag(aZone.blueD, aZone.factoryMethod)
|
||||||
|
end
|
||||||
|
|
||||||
if (aZone.owner == 2) then defenders = aZone.defendersBLUE end
|
if (aZone.owner == 2) then defenders = aZone.defendersBLUE end
|
||||||
-- before we spawn new defenders, remove the old ones
|
-- before we spawn new defenders, remove the old ones
|
||||||
@ -388,7 +482,7 @@ function factoryZone.updateZoneProduction(aZone)
|
|||||||
aZone.defenders then
|
aZone.defenders then
|
||||||
-- we have defenders
|
-- we have defenders
|
||||||
if aZone.defenders:isExist() then
|
if aZone.defenders:isExist() then
|
||||||
-- isee if group was damaged
|
-- see if group was damaged
|
||||||
if not aZone.lastDefenders then
|
if not aZone.lastDefenders then
|
||||||
-- fresh group, probably from persistence, needs init
|
-- fresh group, probably from persistence, needs init
|
||||||
aZone.lastDefenders = -1
|
aZone.lastDefenders = -1
|
||||||
@ -458,7 +552,7 @@ function factoryZone.updateZoneProduction(aZone)
|
|||||||
if timer.getTime() > aZone.timeStamp + factoryZone.repairTime then
|
if timer.getTime() > aZone.timeStamp + factoryZone.repairTime then
|
||||||
aZone.timeStamp = timer.getTime()
|
aZone.timeStamp = timer.getTime()
|
||||||
-- wait's up, repair one defender, then check if full strength
|
-- wait's up, repair one defender, then check if full strength
|
||||||
factoryZone.repairDefenders(aZone)
|
factoryZone.repairDefenders(aZone) -- will also bang on redD and blueD if present
|
||||||
-- see if we are full strenght and if so go to attack, else set timer to reair the next unit
|
-- see if we are full strenght and if so go to attack, else set timer to reair the next unit
|
||||||
if aZone.defenders and aZone.defenders:isExist() and aZone.defenders:getSize() >= aZone.defenders:getInitialSize() then
|
if aZone.defenders and aZone.defenders:isExist() and aZone.defenders:getSize() >= aZone.defenders:getInitialSize() then
|
||||||
-- we are at max size, time to produce some attackers
|
-- we are at max size, time to produce some attackers
|
||||||
@ -468,6 +562,13 @@ function factoryZone.updateZoneProduction(aZone)
|
|||||||
if factoryZone.verbose then
|
if factoryZone.verbose then
|
||||||
trigger.action.outText("+++factZ: State " .. aZone.state .. " to " .. nextState .. " for " .. aZone.name, 30)
|
trigger.action.outText("+++factZ: State " .. aZone.state .. " to " .. nextState .. " for " .. aZone.name, 30)
|
||||||
end
|
end
|
||||||
|
elseif (aZone.redD or aZone.blueD) then
|
||||||
|
-- we start attacking cycle for out signal
|
||||||
|
nextState = "attacking"
|
||||||
|
aZone.timeStamp = timer.getTime()
|
||||||
|
if factoryZone.verbose then
|
||||||
|
trigger.action.outText("+++factZ: progessing tate " .. aZone.state .. " to " .. nextState .. " for " .. aZone.name .. " for redD/blueD", 30)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@ -540,6 +641,19 @@ function factoryZone.update()
|
|||||||
if theZone.activateFlag and cfxZones.testZoneFlag(theZone, theZone.activateFlag, theZone.factoryTriggerMethod, "lastActivateValue") then
|
if theZone.activateFlag and cfxZones.testZoneFlag(theZone, theZone.activateFlag, theZone.factoryTriggerMethod, "lastActivateValue") then
|
||||||
theZone.paused = false
|
theZone.paused = false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- see if zone external defendMe was polled to bring it to
|
||||||
|
-- shoked state
|
||||||
|
if theZone.defendMe and theZone:testZoneFlag(theZone.defendMe, theZone.factoryTriggerMethod, "lastDefendMeValue") then
|
||||||
|
if theZone.verbose or factoryZone.verbose then
|
||||||
|
trigger.action.outText("+++factZ: setting factory <" .. theZone.name .. "> to shocked/produce defender mode", 30)
|
||||||
|
end
|
||||||
|
theZone.state = "shocked"
|
||||||
|
theZone.timeStamp = timer.getTime()
|
||||||
|
theZone.lastDefenders = 0
|
||||||
|
theZone.defenders = nil -- nil, but no delete!
|
||||||
|
end
|
||||||
|
|
||||||
-- do production for this zone
|
-- do production for this zone
|
||||||
factoryZone.updateZoneProduction(theZone)
|
factoryZone.updateZoneProduction(theZone)
|
||||||
end -- iterating all zones
|
end -- iterating all zones
|
||||||
@ -677,6 +791,9 @@ function factoryZone.readConfigZone(theZone)
|
|||||||
factoryZone.verbose = theZone.verbose
|
factoryZone.verbose = theZone.verbose
|
||||||
factoryZone.defendingTime = theZone:getNumberFromZoneProperty( "defendingTime", 100)
|
factoryZone.defendingTime = theZone:getNumberFromZoneProperty( "defendingTime", 100)
|
||||||
factoryZone.attackingTime = theZone:getNumberFromZoneProperty( "attackingTime", 300)
|
factoryZone.attackingTime = theZone:getNumberFromZoneProperty( "attackingTime", 300)
|
||||||
|
if theZone:hasProperty("productionTime") then
|
||||||
|
factoryZone.attackingTime = theZone:getNumberFromZoneProperty( "productionTime", 300)
|
||||||
|
end
|
||||||
factoryZone.shockTime = theZone:getNumberFromZoneProperty("shockTime", 200)
|
factoryZone.shockTime = theZone:getNumberFromZoneProperty("shockTime", 200)
|
||||||
factoryZone.repairTime = theZone:getNumberFromZoneProperty( "repairTime", 200)
|
factoryZone.repairTime = theZone:getNumberFromZoneProperty( "repairTime", 200)
|
||||||
factoryZone.targetZones = "OWNED"
|
factoryZone.targetZones = "OWNED"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
cfxObjectDestructDetector = {}
|
cfxObjectDestructDetector = {}
|
||||||
cfxObjectDestructDetector.version = "2.0.0"
|
cfxObjectDestructDetector.version = "2.0.2"
|
||||||
cfxObjectDestructDetector.verbose = false
|
cfxObjectDestructDetector.verbose = false
|
||||||
cfxObjectDestructDetector.requiredLibs = {
|
cfxObjectDestructDetector.requiredLibs = {
|
||||||
"dcsCommon", -- always
|
"dcsCommon", -- always
|
||||||
@ -18,6 +18,10 @@ cfxObjectDestructDetector.requiredLibs = {
|
|||||||
ID changes (happens with map updates)
|
ID changes (happens with map updates)
|
||||||
fail addZone when name property is missing
|
fail addZone when name property is missing
|
||||||
2.0.1 check that the object is within the zone onEvent
|
2.0.1 check that the object is within the zone onEvent
|
||||||
|
2.0.2 redScore and bluescore attributes
|
||||||
|
API for PlayerScore to pass back redScore/blueScore
|
||||||
|
if objects was killed by player
|
||||||
|
verbosity bug fixed after kill (ref to old ID)
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
cfxObjectDestructDetector.objectZones = {}
|
cfxObjectDestructDetector.objectZones = {}
|
||||||
@ -78,8 +82,59 @@ function cfxObjectDestructDetector.processObjectDestructZone(aZone)
|
|||||||
elseif aZone:hasProperty("objectDestroyed!") then
|
elseif aZone:hasProperty("objectDestroyed!") then
|
||||||
aZone.outDestroyFlag = aZone:getStringFromZoneProperty( "objectDestroyed!", "*none")
|
aZone.outDestroyFlag = aZone:getStringFromZoneProperty( "objectDestroyed!", "*none")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--PlayerScore interface (data)
|
||||||
|
if aZone:hasProperty("redScore") then
|
||||||
|
aZone.redScore = aZone:getNumberFromZoneProperty("redScore", 0)
|
||||||
|
-- if aZone.verbose then
|
||||||
|
-- trigger.action.outText("")
|
||||||
|
-- end
|
||||||
|
end
|
||||||
|
|
||||||
|
if aZone:hasProperty("blueScore") then
|
||||||
|
aZone.blueScore = aZone:getNumberFromZoneProperty("blueScore", 0)
|
||||||
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--
|
||||||
|
-- Interface with PlayerScore
|
||||||
|
-- ==========================
|
||||||
|
-- PlayerScore invokes us when it finds a scenery object was killed
|
||||||
|
-- we check if it is one of ours, and if so, if a score is attached
|
||||||
|
-- for that side
|
||||||
|
function cfxObjectDestructDetector.playerScoreForKill(theObject, killSide)
|
||||||
|
if not theObject then return nil end
|
||||||
|
if not killSide then return nil end
|
||||||
|
local pos = theObject:getPoint()
|
||||||
|
local desc = theObject:getDesc()
|
||||||
|
if not desc then return nil end
|
||||||
|
desc = desc.typeName -- deref type name to match zone objName
|
||||||
|
if not desc then return end
|
||||||
|
for idx, theZone in pairs (cfxObjectDestructDetector.objectZones) do
|
||||||
|
-- see if we can find a matching ODD
|
||||||
|
if (not theZone.isDestroyed) -- make sure it's not a dupe
|
||||||
|
and theZone.objName == desc
|
||||||
|
and theZone:pointInZone(pos)
|
||||||
|
then
|
||||||
|
-- yes, ODD tracks this object
|
||||||
|
if cfxObjectDestructDetector.verbose or theZone.verbose then
|
||||||
|
trigger.action.outText("OOD: score invocation for hit scenery object <" .. desc .. ">, tracked with <" .. theZone.name .. ">", 30)
|
||||||
|
end
|
||||||
|
if killSide == 1 then return theZone.redScore end -- can be nil!
|
||||||
|
if killSide == 2 then return theZone.blueScore end
|
||||||
|
-- if we get here, the object is tracked, but has no
|
||||||
|
-- playerScore attached. simply exist with nil
|
||||||
|
if cfxObjectDestructDetector.verbose or theZone.verbose then
|
||||||
|
trigger.action.outText("OOD: scenery object <" .. desc .. ">, tracked but no player score defined for coa <" .. killSide .. ">.", 30)
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- ON EVENT
|
-- ON EVENT
|
||||||
--
|
--
|
||||||
@ -106,7 +161,7 @@ function cfxObjectDestructDetector:onEvent(event)
|
|||||||
-- invoke callbacks
|
-- invoke callbacks
|
||||||
cfxObjectDestructDetector.invokeCallbacksFor(aZone)
|
cfxObjectDestructDetector.invokeCallbacksFor(aZone)
|
||||||
if aZone.verbose or cfxObjectDestructDetector.verbose then
|
if aZone.verbose or cfxObjectDestructDetector.verbose then
|
||||||
trigger.action.outText("OBJECT KILL: " .. id, 30)
|
trigger.action.outText("OBJECT KILL: " .. matchMe .. " for odd <" .. aZone.name .. ">", 30)
|
||||||
end
|
end
|
||||||
-- save state for persistence
|
-- save state for persistence
|
||||||
aZone.isDestroyed = true
|
aZone.isDestroyed = true
|
||||||
|
|||||||
@ -12,6 +12,7 @@ cfxPlayerScore.firstSave = true -- to force overwrite
|
|||||||
- sceneryObject detection improvements
|
- sceneryObject detection improvements
|
||||||
- DCS 2.9 safe
|
- DCS 2.9 safe
|
||||||
3.0.1 - cleanup
|
3.0.1 - cleanup
|
||||||
|
3.0.2 - interface with ObjectDestructDetector for scoring scenery objects
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
@ -208,8 +209,9 @@ function cfxPlayerScore.cat2BaseScore(inCat)
|
|||||||
return 1
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function cfxPlayerScore.object2score(inVictim) -- does not have group
|
function cfxPlayerScore.object2score(inVictim, killSide) -- does not have group
|
||||||
if not inVictim then return 0 end
|
if not inVictim then return 0 end
|
||||||
|
if not killSide then killSide = -1 end
|
||||||
local inName = inVictim:getName()
|
local inName = inVictim:getName()
|
||||||
if dcsCommon.isSceneryObject(inVictim) then
|
if dcsCommon.isSceneryObject(inVictim) then
|
||||||
local desc = inVictim:getDesc()
|
local desc = inVictim:getDesc()
|
||||||
@ -217,6 +219,12 @@ function cfxPlayerScore.object2score(inVictim) -- does not have group
|
|||||||
-- same as object destruct detector to
|
-- same as object destruct detector to
|
||||||
-- avoid ID changes
|
-- avoid ID changes
|
||||||
inName = desc.typeName
|
inName = desc.typeName
|
||||||
|
if cfxObjectDestructDetector then
|
||||||
|
-- ask ODD if it knows the object and what score was
|
||||||
|
-- awarded for a kill from that side
|
||||||
|
local objectScore = cfxObjectDestructDetector.playerScoreForKill(inVictim, killSide)
|
||||||
|
if objectScore then return objectScore end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if not inName then return 0 end
|
if not inName then return 0 end
|
||||||
if type(inName) == "number" then
|
if type(inName) == "number" then
|
||||||
@ -744,7 +752,7 @@ function cfxPlayerScore.killDetected(theEvent)
|
|||||||
if wasBuilding then
|
if wasBuilding then
|
||||||
-- these objects have no coalition; we simply award the score if
|
-- these objects have no coalition; we simply award the score if
|
||||||
-- it exists in look-up table.
|
-- it exists in look-up table.
|
||||||
local staticScore = cfxPlayerScore.object2score(victim)
|
local staticScore = cfxPlayerScore.object2score(victim, killSide)
|
||||||
if staticScore > 0 then
|
if staticScore > 0 then
|
||||||
trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.scoreSound)
|
trigger.action.outSoundForCoalition(killSide, cfxPlayerScore.scoreSound)
|
||||||
cfxPlayerScore.awardScoreTo(killSide, staticScore, killerName)
|
cfxPlayerScore.awardScoreTo(killSide, staticScore, killerName)
|
||||||
@ -754,8 +762,10 @@ function cfxPlayerScore.killDetected(theEvent)
|
|||||||
end
|
end
|
||||||
|
|
||||||
-- was it fratricide?
|
-- was it fratricide?
|
||||||
|
-- if we get here, it CANT be a scenery object
|
||||||
|
-- but can be a static object, and stO have a coalition
|
||||||
local vicSide = victim:getCoalition()
|
local vicSide = victim:getCoalition()
|
||||||
local fraternicide = killSide == vicSide
|
local fraternicide = (killSide == vicSide)
|
||||||
local vicDesc = victim:getTypeName()
|
local vicDesc = victim:getTypeName()
|
||||||
local scoreMod = 1 -- start at one
|
local scoreMod = 1 -- start at one
|
||||||
|
|
||||||
@ -767,7 +777,7 @@ function cfxPlayerScore.killDetected(theEvent)
|
|||||||
-- static objects have no group
|
-- static objects have no group
|
||||||
local staticName = victim:getName() -- on statics, this returns
|
local staticName = victim:getName() -- on statics, this returns
|
||||||
-- name as entered in TOP LINE
|
-- name as entered in TOP LINE
|
||||||
local staticScore = cfxPlayerScore.object2score(victim)
|
local staticScore = cfxPlayerScore.object2score(victim, killSide)
|
||||||
|
|
||||||
if staticScore > 0 then
|
if staticScore > 0 then
|
||||||
-- this was a named static, return the score - unless our own
|
-- this was a named static, return the score - unless our own
|
||||||
@ -1488,6 +1498,7 @@ score zones
|
|||||||
- zones outside of which no scoring counts, but feats are still ok
|
- zones outside of which no scoring counts, but feats are still ok
|
||||||
|
|
||||||
- add take off feats
|
- add take off feats
|
||||||
|
- integrate with objectDestructDetector
|
||||||
|
|
||||||
can be extended with other, standalone feat modules that follow the
|
can be extended with other, standalone feat modules that follow the
|
||||||
same pattern, e.g. enter a zone, detect someone
|
same pattern, e.g. enter a zone, detect someone
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
-- theDebugger
|
-- theDebugger 2.x
|
||||||
debugger = {}
|
debugger = {}
|
||||||
debugger.version = "2.0.0"
|
debugger.version = "2.1.0"
|
||||||
debugDemon = {}
|
debugDemon = {}
|
||||||
debugDemon.version = "2.0.0"
|
debugDemon.version = "2.1.0"
|
||||||
|
|
||||||
debugger.verbose = false
|
debugger.verbose = false
|
||||||
debugger.ups = 4 -- every 0.25 second
|
debugger.ups = 4 -- every 0.25 second
|
||||||
@ -33,6 +33,13 @@ debugger.log = ""
|
|||||||
- debuggerSpawnTypes zone
|
- debuggerSpawnTypes zone
|
||||||
- reading debuggerSpawnTypes
|
- reading debuggerSpawnTypes
|
||||||
- removed some silly bugs / inconsistencies
|
- removed some silly bugs / inconsistencies
|
||||||
|
2.1.0 - debugging code is now invoked deferred to avoid
|
||||||
|
DCS crash after exiting. Debug code now executes
|
||||||
|
outside of the event code's bracket.
|
||||||
|
debug invocation on clone of data structure
|
||||||
|
readback verification of flag set
|
||||||
|
fixed getProperty() in debugger with zone
|
||||||
|
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
debugger.requiredLibs = {
|
debugger.requiredLibs = {
|
||||||
@ -201,7 +208,7 @@ end
|
|||||||
function debugger.createDebuggerWithZone(theZone)
|
function debugger.createDebuggerWithZone(theZone)
|
||||||
-- watchflag input trigger
|
-- watchflag input trigger
|
||||||
theZone.debugInputMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
|
theZone.debugInputMethod = theZone:getStringFromZoneProperty( "triggerMethod", "change")
|
||||||
if theZone.hasProperty("debugTriggerMethod") then
|
if theZone:hasProperty("debugTriggerMethod") then
|
||||||
theZone.debugInputMethod = theZone:getStringFromZoneProperty("debugTriggerMethod", "change")
|
theZone.debugInputMethod = theZone:getStringFromZoneProperty("debugTriggerMethod", "change")
|
||||||
elseif theZone:hasProperty("inputMethod") then
|
elseif theZone:hasProperty("inputMethod") then
|
||||||
theZone.debugInputMethod = theZone:getStringFromZoneProperty(theZone, "inputMethod", "change")
|
theZone.debugInputMethod = theZone:getStringFromZoneProperty(theZone, "inputMethod", "change")
|
||||||
@ -644,7 +651,8 @@ debugDemon.splitDelimiter = " "
|
|||||||
debugDemon.commandTable = {} -- key, value pair for command processing per keyword
|
debugDemon.commandTable = {} -- key, value pair for command processing per keyword
|
||||||
debugDemon.keepOpen = false -- keep mark open after a successful command
|
debugDemon.keepOpen = false -- keep mark open after a successful command
|
||||||
debugDemon.snapshot = {}
|
debugDemon.snapshot = {}
|
||||||
|
debugDemon.activeIdx = -1 -- to detect if a window was close
|
||||||
|
-- and prevent execution of debugger
|
||||||
function debugDemon.hasMark(theString)
|
function debugDemon.hasMark(theString)
|
||||||
-- check if the string begins with the sequece to identify commands
|
-- check if the string begins with the sequece to identify commands
|
||||||
if not theString then return false end
|
if not theString then return false end
|
||||||
@ -676,6 +684,7 @@ function debugDemon:onEvent(theEvent)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if theEvent.id == world.event.S_EVENT_MARK_CHANGE then
|
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
|
-- when changed, the mark's text is examined for a command
|
||||||
-- if it starts with the 'mark' string ("-" by default) it is processed
|
-- if it starts with the 'mark' string ("-" by default) it is processed
|
||||||
-- by the command processor
|
-- by the command processor
|
||||||
@ -683,12 +692,19 @@ function debugDemon:onEvent(theEvent)
|
|||||||
-- else an error is displayed and the mark remains.
|
-- else an error is displayed and the mark remains.
|
||||||
if debugDemon.hasMark(theEvent.text) then
|
if debugDemon.hasMark(theEvent.text) then
|
||||||
-- strip the mark
|
-- strip the mark
|
||||||
local commandString = theEvent.text:sub(1+debugDemon.markOfDemon:len())
|
local cCommand = dcsCommon.clone(theEvent.text, true)
|
||||||
|
local commandString = cCommand:sub(1+debugDemon.markOfDemon:len())
|
||||||
-- break remainder apart into <command> <arg1> ... <argn>
|
-- break remainder apart into <command> <arg1> ... <argn>
|
||||||
local commands = dcsCommon.splitString(commandString, debugDemon.splitDelimiter)
|
local commands = dcsCommon.splitString(commandString, debugDemon.splitDelimiter)
|
||||||
|
|
||||||
-- this is a command. process it and then remove it if it was executed successfully
|
-- this is a command. process it and then remove it if it was executed successfully
|
||||||
local success = debugDemon.executeCommand(commands, theEvent)
|
local cTheEvent = dcsCommon.clone(theEvent, true) -- 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
|
-- remove this mark after successful execution
|
||||||
if success then
|
if success then
|
||||||
@ -696,13 +712,35 @@ function debugDemon:onEvent(theEvent)
|
|||||||
else
|
else
|
||||||
-- we could play some error sound
|
-- we could play some error sound
|
||||||
end
|
end
|
||||||
|
--]]--
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if theEvent.id == world.event.S_EVENT_MARK_REMOVED then
|
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
|
||||||
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
|
||||||
|
|
||||||
|
-- remove this mark after successful execution
|
||||||
|
if success then
|
||||||
|
trigger.action.removeMark(cTheEvent.idx)
|
||||||
|
debugDemon.activeIdx = nil
|
||||||
|
else
|
||||||
|
-- we could play some error sound
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--
|
--
|
||||||
-- add / remove commands to/from vocabulary
|
-- add / remove commands to/from vocabulary
|
||||||
--
|
--
|
||||||
@ -1103,6 +1141,11 @@ function debugDemon.processSetCommand(args, event)
|
|||||||
|
|
||||||
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debug: set flag <" .. theName .. "> to <" .. theVal .. ">" .. note, 30)
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debug: set flag <" .. theName .. "> to <" .. theVal .. ">" .. note, 30)
|
||||||
|
|
||||||
|
local newVal = trigger.misc.getUserFlag(theName)
|
||||||
|
if theVal ~= newVal then
|
||||||
|
debugger.outText("*** [" .. dcsCommon.nowString() .. "] debug: readback failure for flag <" .. theName .. ">: expected <" .. theVal .. ">, got <" .. newVal .. "!", 30)
|
||||||
|
end
|
||||||
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
williePete = {}
|
williePete = {}
|
||||||
williePete.version = "2.0.0"
|
williePete.version = "2.0.2"
|
||||||
williePete.ups = 10 -- we update at 10 fps, so accuracy of a
|
williePete.ups = 10 -- we update at 10 fps, so accuracy of a
|
||||||
-- missile moving at Mach 2 is within 33 meters,
|
-- missile moving at Mach 2 is within 33 meters,
|
||||||
-- with interpolation even at 3 meters
|
-- with interpolation even at 3 meters
|
||||||
@ -17,6 +17,8 @@ williePete.requiredLibs = {
|
|||||||
2.0.0 - dmlZones, OOP
|
2.0.0 - dmlZones, OOP
|
||||||
- Guards for multi-unit player groups
|
- Guards for multi-unit player groups
|
||||||
- getFirstLivingPlayerInGroupNamed()
|
- getFirstLivingPlayerInGroupNamed()
|
||||||
|
2.0.1 - added Harrier's FFAR M156 WP
|
||||||
|
2.0.2 - hardened playerUpdate()
|
||||||
--]]--
|
--]]--
|
||||||
|
|
||||||
williePete.willies = {}
|
williePete.willies = {}
|
||||||
@ -28,7 +30,7 @@ williePete.blastedObjects = {} -- used when we detonate something
|
|||||||
|
|
||||||
-- recognizes WP munitions. May require regular update when new
|
-- recognizes WP munitions. May require regular update when new
|
||||||
-- models come out.
|
-- models come out.
|
||||||
williePete.smokeWeapons = {"HYDRA_70_M274","HYDRA_70_MK61","HYDRA_70_MK1","HYDRA_70_WTU1B","HYDRA_70_M156","HYDRA_70_M158","BDU_45B","BDU_33","BDU_45","BDU_45LGB","BDU_50HD","BDU_50LD","BDU_50LGB","C_8CM", "SNEB_TYPE254_H1_GREEN", "SNEB_TYPE254_H1_RED", "SNEB_TYPE254_H1_YELLOW"}
|
williePete.smokeWeapons = {"HYDRA_70_M274","HYDRA_70_MK61","HYDRA_70_MK1","HYDRA_70_WTU1B","HYDRA_70_M156","HYDRA_70_M158","BDU_45B","BDU_33","BDU_45","BDU_45LGB","BDU_50HD","BDU_50LD","BDU_50LGB","C_8CM", "SNEB_TYPE254_H1_GREEN", "SNEB_TYPE254_H1_RED", "SNEB_TYPE254_H1_YELLOW", "FFAR M156 WP"}
|
||||||
|
|
||||||
function williePete.addWillie(theWillie)
|
function williePete.addWillie(theWillie)
|
||||||
table.insert(williePete.willies, theWillie)
|
table.insert(williePete.willies, theWillie)
|
||||||
@ -617,19 +619,23 @@ function williePete.playerUpdate()
|
|||||||
-- make sure at least one unit still exists
|
-- make sure at least one unit still exists
|
||||||
local dropUnit = true
|
local dropUnit = true
|
||||||
local theGroup = Group.getByName(unitInfo.gName)
|
local theGroup = Group.getByName(unitInfo.gName)
|
||||||
local allUnits = theGroup:getUnits()
|
if theGroup then
|
||||||
for idx, theUnit in pairs(allUnits) do
|
local allUnits = theGroup:getUnits()
|
||||||
--local theUnit = Unit.getByName(unitInfo.name)
|
for idx, theUnit in pairs(allUnits) do
|
||||||
if theUnit and Unit.isExist(theUnit) and
|
--local theUnit = Unit.getByName(unitInfo.name)
|
||||||
theUnit.getPlayerName and theUnit:getPlayerName() then
|
if theUnit and Unit.isExist(theUnit) and
|
||||||
local up = theUnit:getPoint()
|
theUnit.getPlayerName and theUnit:getPlayerName() then
|
||||||
up.y = 0
|
local up = theUnit:getPoint()
|
||||||
local isInside, dist = cfxZones.isPointInsideZone(up, theZone, theZone.checkInRange)
|
up.y = 0
|
||||||
|
local isInside, dist = cfxZones.isPointInsideZone(up, theZone, theZone.checkInRange)
|
||||||
|
|
||||||
if isInside then
|
if isInside then
|
||||||
dropUnit = false
|
dropUnit = false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
trigger.action.outText("+++wp: strange issues with group <" .. gName .. ">, does not exist. Skipped in playerUpdate()", 30)
|
||||||
end
|
end
|
||||||
if dropUnit then
|
if dropUnit then
|
||||||
-- all outside, remove from zone check-in
|
-- all outside, remove from zone check-in
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
tutorial & demo missions/demo - Clone Factory.miz
Normal file
BIN
tutorial & demo missions/demo - Clone Factory.miz
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user