DML/modules/milHelo.lua
Christian Franz 76083ff2b6 Version 2,27
The Debugger XRef
2024-07-04 11:03:00 +02:00

864 lines
27 KiB
Lua

milHelo = {}
milHelo.version = "1.0.2"
milHelo.requiredLibs = {
"dcsCommon",
"cfxZones",
"cfxMX",
}
milHelo.zones = {}
milHelo.targetKeywords = {
"milTarget", -- my own zone
"camp", -- camps
"airfield", -- airfields
"FARP", -- FARPzones
}
milHelo.targets = {}
milHelo.flights = {} -- all currently active mil helo flights
milHelo.ups = 1
milHelo.missionTypes = {
"cas", -- standard cas
"patrol", -- orbit over zone for duration
"insert", -- insert one of the ground groups in the src zone after landing
"casz", -- engage in zone for target zone's radius
-- missing csar
}
function milHelo.addMilHeloZone(theZone)
milHelo.zones[theZone.name] = theZone
end
function milHelo.addMilTargetZone(theZone)
milHelo.targets[theZone.name] = theZone -- overwrite if duplicate
end
--[[--
function milHelo.partOfGroupDataInZone(theZone, theUnits) -- move to mx?
--local zP --= cfxZones.getPoint(theZone)
local zP = theZone:getDCSOrigin() -- don't use getPoint now.
zP.y = 0
for idx, aUnit in pairs(theUnits) do
local uP = {}
uP.x = aUnit.x
uP.y = 0
uP.z = aUnit.y -- !! y-z
if theZone:pointInZone(uP) then return true end
end
return false
end
function milHelo.allGroupsInZoneByData(theZone) -- move to MX?
local theGroupsInZone = {}
local count = 0
for groupName, groupData in pairs(cfxMX.groupDataByName) do
if groupData.units then
if milHelo.partOfGroupDataInZone(theZone, groupData.units) then
theGroupsInZone[groupName] = groupData -- DATA! work on clones!
count = count + 1
if theZone.verbose then
trigger.action.outText("+++milH: added group <" .. groupName .. "> for zone <" .. theZone.name .. ">", 30)
end
end
end
end
return theGroupsInZone, count
end
--]]--
function milHelo.readMilHeloZone(theZone) -- process attributes
-- get mission type. part of milHelo
theZone.msnType = string.lower(theZone:getStringFromZoneProperty("milHelo", "cas"))
if dcsCommon.arrayContainsString(milHelo.missionTypes, theZone.msnType) then
-- great, mission type is known
else
trigger.action.outText("+++milH: zone <" .. theZone.name .. ">: unknown mission type <" .. theZone.msnType .. ">, defaulting to 'CAS'", 30)
theZone.msnType = "cas"
end
-- see if our ownership is tied to a master
-- adds dynamic coalition capability
if theZone:hasProperty("masterOwner") then
local mo = theZone:getStringFromZoneProperty("masterOwner")
local mz = cfxZones.getZoneByName(mo)
if not mz then
trigger.action.outText("+++milH: WARNING: Master Owner <" .. mo .. "> for zone <" .. theZone.name .. "> does not exist!", 30)
else
theZone.masterOwner = mz
end
theZone.isDynamic = theZone:getBoolFromZoneProperty("dynamic", true)
end
-- get all groups inside me
local myGroups, count = cfxMX.allGroupsInZoneByData(theZone)
theZone.myGroups = myGroups
theZone.groupCount = count
theZone.hGroups = {}
theZone.hCount = 0
theZone.gGroups = {}
theZone.gCount = 0
theZone.fGroups = {}
theZone.fCount = 0
-- sort into ground, helo and fixed
for groupName, data in pairs(myGroups) do
local catRaw = cfxMX.groupTypeByName[groupName]
if theZone.verbose then
trigger.action.outText("Proccing zone <" .. theZone.name .. ">: group <" .. groupName .. "> - type <" .. catRaw .. ">", 30)
end
if catRaw == "helicopter" then
theZone.hGroups[groupName] = data
theZone.hCount = theZone.hCount + 1
elseif catRaw == "plane" then
theZone.fGroups[groupName] = data
theZone.fCount = theZone.fCount + 1
elseif catRaw == "vehicle" then
theZone.gGroups[groupName] = data
theZone.gCount = theZone.gCount + 1
else
trigger.action.outText("+++milH: ignored group <" .. groupName .. ">: unknown type <" .. catRaw .. ">", 30)
end
end
theZone.coa = theZone:getCoalitionFromZoneProperty("coalition", 0)
theZone.hot = theZone:getBoolFromZoneProperty("hot", false)
theZone.speed = theZone:getNumberFromZoneProperty("speed", 50) -- 110 mph
theZone.alt = theZone:getNumberFromZoneProperty("alt", 100) -- we are always radar alt
theZone.loiter = theZone:getNumberFromZoneProperty("loiter", 3600) -- 1 hour loiter default
-- wipe all existing
for groupName, data in pairs(myGroups) do
local g = Group.getByName(groupName)
if g then
Group.destroy(g)
end
end
if theZone.verbose or milHelo.verbose then
trigger.action.outText("+++milH: processed milHelo zone <" .. theZone.name .. ">", 30)
end
end
function milHelo.readMilTargetZone(theZone)
-- can also be "camp", "farp", "airfield"
theZone.casRadius = theZone:getNumberFromZoneProperty("casRadius", theZone.radius)
if (not theZone.isCircle) and not theZone:hasProperty("casRadius") then
-- often when we have a camp there is no cas radius, use 10km
-- and zone is ploygonal
if theZone.verbose then
trigger.action.outText("+++milH: Warning - milH target zone <" .. theZone.name .. "> is polygonal and has no CAS radius attribute. Defaulting to 10km", 30)
end
theZone.casRadius = 10000
end
if theZone.verbose or milHelo.verbose then
trigger.action.outText("+++milH: processed milHelo TARGET zone <" .. theZone.name .. ">", 30)
end
end
--
-- Spawning for a zone
--
function milHelo.createCASTask(num, auto)
if not auto then auto = false end
if not num then num = 1 end
local task = {}
task.number = num
task.key = "CAS"
task.id = "EngageTargets"
task.enabled = true
task.auto = auto
local params = {}
params.priority = 0
local targetTypes = {[1] = "Helicopters", [2] = "Ground Units", [3] = "Light armed ships",}
params.targetTypes = targetTypes
task.params = params
return task
end
function milHelo.createROETask(num, roe)
if not num then num = 1 end
if not roe then roe = 0 end
local task = {}
task.number = num
task.enabled = true
task.auto = false
task.id = "WrappedAction"
local params = {}
local action = {}
action.id = "Option"
local p2 = {}
p2.value = roe -- 0 = Weapons free
p2.name = 0 -- name 0 = ROE
action.params = p2
params.action = action
task.params = params
return task
end
function milHelo.createEngageIZTask(num, theZone)
-- trigger.action.outText("Creating engage in zone task for zone <" .. theZone.name .. ">, marking on map", 30)
-- theZone:drawZone()
-- theZone:drawText("casz - " .. theZone.name, 20)
local p = theZone:getPoint()
if not num then num = 1 end
local task = {}
task.number = num
task.enabled = true
task.auto = false
task.id = "EngageTargetsInZone"
local params = {}
targetTypes = {}
targetTypes[1] = "All"
params.targetTypes = targetTypes
params.x = p.x
params.y = p.z -- !!!!
params.value = "All;"
params.noTargetTypes = {}
params.priority = 0
local radius = theZone.casRadius
params.zoneRadius = radius
task.params = params
return task
end
function milHelo.createOrbitTask(num, duration, theZone)
if not num then num = 1 end
local task = {}
task.number = num
task.auto = false
task.id = "ControlledTask"
task.enabled = true
local params = {}
local t2 = {}
t2.id = "Orbit"
local p2 = {}
p2.altitude = theZone.alt
p2.pattern = "Circle"
p2.speed = theZone.speed
p2.altitudeEdited = true
t2.params = p2
params.task = t2
params.stopCondition = {}
params.stopCondition.duration = duration
task.params = params
return task
end
function milHelo.createLandTask(p, duration, num)
if not num then num = 1 end
local t = {}
t.enabled = true
t.auto = false
t.id = "ControlledTask"
t.number = num
local params = {}
t.params = params
local ptsk = {}
params.task = ptsk
ptsk.id = "Land"
local ptp = {}
ptsk.params = ptp
ptp.x = p.x
ptp.y = p.z
ptp.duration = "300" -- not sure why
ptp.durationFlag = false -- off anyway
local stopCon = {}
stopCon.duration = duration
params.stopCondition = stopCon
return t
end
function milHelo.createCommandTask(theCommand, num)
if not num then num = 1 end
local t = {}
t.enabled = true
t.auto = false
t.id = "WrappedAction"
t.number = num
local params = {}
t.params = params
local action = {}
params.action = action
action.id = "Script"
local p2 = {}
action.params = p2
p2.command = theCommand
return t
end
function milHelo.createTakeOffWP(theZone, engageInZone, engageZone, ROE)
if not ROE then ROE = 0 end -- wepons free
local WP = {}
WP.alt = 500 -- theZone.alt
WP.alt_type = "BARO"
WP.properties = {}
WP.properties.addopt = {}
WP.action = "From Ground Area"
if theZone.hot then WP.action = "From Ground Area Hot" end
WP.speed = 0 -- theZone.speed
WP.task = {}
WP.task.id = "ComboTask"
WP.task.params = {}
local tasks = {}
local casTask = milHelo.createCASTask(1)
tasks[1] = casTask
local roeTask = milHelo.createROETask(2,ROE) -- 0 = weapons free, 4 = weapon hold
tasks[2] = roeTask
if engageInZone then
if not engageZone then
trigger.action.outText("+++milH: Warning - caz task with no engage zone!", 30)
end
local eiz = milHelo.createEngageIZTask(3, engageZone)
tasks[3] = eiz
end
WP.task.params.tasks = tasks
--
WP.type = "TakeOffGround"
if theZone.hot then WP.type = "TakeOffGroundHot" end
p = theZone:getPoint()
WP.x = p.x
WP.y = p.z
WP.ETA = 0
WP.ETA_locked = true
WP.speed_locked = true
WP.formation_template = ""
return WP
end
function milHelo.createOrbitWP(theZone, targetPoint)
local WP = {}
WP.alt = theZone.alt
WP.alt_type = "RADIO"
WP.properties = {}
WP.properties.addopt = {}
WP.action = "Turning Point"
WP.speed = theZone.speed
WP.task = {}
WP.task.id = "ComboTask"
WP.task.params = {}
-- start params construct
local tasks = {}
local casTask = milHelo.createCASTask(1)
tasks[1] = casTask
local oTask = milHelo.createOrbitTask(2, theZone.loiter, theZone)
tasks[2] = oTask
WP.task.params.tasks = tasks
WP.type = "Turning Point"
WP.x = targetPoint.x
WP.y = targetPoint.z
WP.ETA = 0
WP.ETA_locked = false
WP.speed_locked = true
WP.formation_template = ""
return WP
end
function milHelo.createLandWP(gName, theZone, targetZone)
local toWP
toWP = dcsCommon.createSimpleRoutePointData(targetZone:getPoint(), theZone.alt, theZone.speed)
toWP.alt_type = "RADIO"
local task = {}
task.id = "ComboTask"
task.params = {}
local ttsk = {}
local p = targetZone:getPoint()
ttsk[1] = milHelo.createLandTask(p, milHelo.landingDuration, 1)
local command = "milHelo.landedCB('" .. gName .. "', '" .. targetZone:getName() .. "', '" .. theZone:getName() .. "')"
ttsk[2] = milHelo.createCommandTask(command,2)
task.params.tasks = ttsk
toWP.task = task
return toWP
end
function milHelo.createOMWCallbackWP(gName, number, pt, alt, speed, action, ROE) -- name is group name
if not action then action = "none" end
local omwWP = dcsCommon.createSimpleRoutePointData(pt, alt, speed)
omwWP.alt_type = "RADIO"
-- create a command waypoint
local task = {}
task.id = "ComboTask"
task.params = {}
local ttsk = {}
local command = "milHelo.reachedWP('" .. gName .. "', '" .. number .. "', '" .. action .."')"
ttsk[1] = milHelo.createCommandTask(command,1)
if ROE then
ttsk[2] = milHelo.createROETask(2, ROE)
end
task.params.tasks = ttsk
omwWP.task = task
return omwWP
end
function milHelo.spawnForZone(theZone, targetZone)
-- note that each zone only has a single msnType, so zone
-- defines msn type
local n = dcsCommon.randomBetween(1, theZone.hCount)
local theRawData = dcsCommon.getNthItem(theZone.hGroups, n)
local gData = dcsCommon.clone(theRawData)
local oName = gData.name
gData.lateActivation = false
-- pre-process gData: names, id etc
gData.name = dcsCommon.uuid(gData.name)
local gName = gData.name
for idx, uData in pairs(gData.units) do
uData.name = dcsCommon.uuid(uData.name)
uData.alt = 10
uData.alt_type = "RADIO"
uData.speed = 0
uData.unitId = nil
end
gData.groupId = nil
-- change task according to missionType in Zone
-- we currently use CAS for all
gData.task = "CAS"
-- create and process route
local route = {}
route.points = {}
gData.route = route
-- create take-off waypoint
local casInZone = theZone.msnType == "casz"
if theZone.verbose and casInZone then
trigger.action.outText("Setting up casZ for <" .. theZone.name .. "> to <" .. targetZone.name .. ">", 30)
end
local wpTOff = milHelo.createTakeOffWP(theZone, casInZone, targetZone) -- no ROE = weapons free
-- depending on mission, create an orbit or land WP
local dest = targetZone:getPoint()
local B = dest
local A = theZone:getPoint()
if theZone.msnType == "cas" or theZone.msnType == "patrol" then
-- patrol and cas go straight to the target, they do not
-- have an ingress. Meaning: they have the same route
-- profile as 'insert'
wpTOff = milHelo.createTakeOffWP(theZone, casInZone, targetZone, 4) -- 4 = weapons HOLD
dcsCommon.addRoutePointForGroupData(gData, wpTOff) -- wp 1
-- on approach, 70% at target, go weapons hot
local apr = dcsCommon.vLerp(A, B, 0.75)
local omw2 = milHelo.createOMWCallbackWP(gName, 2, apr, theZone.alt, theZone.speed, "weapons free", 0) -- wp 2
dcsCommon.addRoutePointForGroupData(gData, omw2)
-- possible expandion: if cas, we have an ingress point?
local wpDest = milHelo.createOrbitWP(theZone, dest)
dcsCommon.addRoutePointForGroupData(gData, wpDest) -- wp 3
--local retPt = milHelo.createLandWP(gName, theZone, theZone)
--dcsCommon.addRoutePointForGroupData(gData, retPt)
local retpt = theZone:getPoint()
local omw4 = milHelo.createOMWCallbackWP(gName, 4, retpt, theZone.alt, theZone.speed, "remove")
dcsCommon.addRoutePointForGroupData(gData, omw4) -- wp 4
elseif theZone.msnType == "casz" then
wpTOff = milHelo.createTakeOffWP(theZone, casInZone, targetZone, 4) -- 4 = ROE weapons hold
dcsCommon.addRoutePointForGroupData(gData, wpTOff) -- wp 1
-- go to CAS destination with Engage in Zone active
-- we may want to make ingress and egress wp before heading to
-- the 'real' CASZ point
-- make ingress point, in direction of target, 30 degrees to the right, half distance.
local ingress = dcsCommon.pointXpercentYdegOffAB(A, B, math.random(50,80), math.random(20,50))
--local pt = targetZone:getPoint()
local omw1 = milHelo.createOMWCallbackWP(gName, 2, ingress, theZone.alt, theZone.speed, "weapons free", 0) -- wp 2
dcsCommon.addRoutePointForGroupData(gData, omw1)
local omw2 = milHelo.createOMWCallbackWP(gName, 3, B, theZone.alt, theZone.speed, "none")
dcsCommon.addRoutePointForGroupData(gData, omw2) -- wp 3
-- egress point
local egress = dcsCommon.pointXpercentYdegOffAB(B, A, math.random(20, 50), math.random(20,50))
local omw3 = milHelo.createOMWCallbackWP(gName, 4, egress, theZone.alt, theZone.speed, "none")
dcsCommon.addRoutePointForGroupData(gData, omw3) -- wp 4
-- return to aerodrome, deallocate
local retpt = theZone:getPoint()
local omw4 = milHelo.createOMWCallbackWP(gName, 5, retpt, theZone.alt, theZone.speed, "remove")
dcsCommon.addRoutePointForGroupData(gData, omw4) -- wp 5
elseif theZone.msnType == "insert" then
local wpDest = milHelo.createLandWP(gName, theZone, targetZone)
dcsCommon.addRoutePointForGroupData(gData, wpTOff) -- wp 1
dcsCommon.addRoutePointForGroupData(gData, wpDest) -- wp 2
-- will land and dealloc there after spawning troops
end
-- make coa a cty
if theZone.coa == 0 then
trigger.action.outText("+++milH: WARNING - zone <" .. theZone.name .. "> is NEUTRAL", 30)
end
local cty = dcsCommon.getACountryForCoalition(theZone.coa)
-- spawn
local groupCat = Group.Category.HELICOPTER
local theSpawnedGroup = coalition.addGroup(cty, groupCat, gData)
local theFlight = {}
theFlight.oName = oName
theFlight.spawn = theSpawnedGroup
theFlight.origin = theZone
theFlight.destination = targetZone
milHelo.flights[gName] = theFlight --theSpawnedGroup
return theSpawnedGroup, gData
end
--
-- mil helo landed callback (insertion)
--
function milHelo.insertTroops(theUnit, targetZone, srcZone)
local theZone = srcZone
local n = dcsCommon.randomBetween(1, theZone.gCount)
local theRawData = dcsCommon.getNthItem(theZone.gGroups, n)
-- local theRawData = dcsCommon.getNthItem(srcZone.gGroups, 1)
if not theRawData then
trigger.action.outText("+++milH: WARNING: no troops to insert for zone <" .. srcZone.name .. ">", 30)
return
end
local gData = dcsCommon.clone(theRawData)
gData.lateActivation = false -- force false
-- deploy in ring formation
-- remove all routes
-- mayhaps prepare for orders and formation
local p = theUnit:getPoint()
gData.route = nil -- no more route. stand in place
gData.name = dcsCommon.uuid(gData.name)
local gName = gData.name
for idx, uData in pairs(gData.units) do
uData.name = dcsCommon.uuid(uData.name)
uData.speed = 0
uData.heading = 0
uData.unitId = nil
end
gData.groupId = nil
dcsCommon.moveGroupDataTo(gData, 0, 0) -- move to origin so we can arrange them
dcsCommon.arrangeGroupDataIntoFormation(gData, 20, nil, "CIRCLE_OUT")
dcsCommon.moveGroupDataTo(gData, p.x, p.z) -- move arranged group to helo
-- make coa a cty
if theZone.coa == 0 then
trigger.action.outText("+++milH: WARNING - zone <" .. theZone.name .. "> is NEUTRAL", 30)
end
local cty = dcsCommon.getACountryForCoalition(theZone.coa)
-- spawn
local groupCat = Group.Category.GROUND
local theSpawnedGroup = coalition.addGroup(cty, groupCat, gData)
--trigger.action.outText("Inserted troops <" .. gName .. ">", 30)
return theSpawnedGroup, gData
end
function milHelo.replaceUnitsWithStatics(gName)
end
function milHelo.getRawDataFromGroupNamed(gName, oName)
local theGroup = Group.getByName(gName)
local groupName = gName
local cat = theGroup:getCategory()
-- access mxdata for livery because getDesc does not return the livery
local liveries = {}
local mxData = cfxMX.getGroupFromDCSbyName(oName)
for idx, theUnit in pairs (mxData.units) do
liveries[theUnit.name] = theUnit.livery_id
end
local ctry
local gID = theGroup:getID()
local allUnits = theGroup:getUnits()
local rawGroup = {}
rawGroup.name = groupName
local rawUnits = {}
for idx, theUnit in pairs(allUnits) do
local ir = {}
local unitData = theUnit:getDesc()
-- build record
ir.heading = dcsCommon.getUnitHeading(theUnit)
ir.name = theUnit:getName()
ir.type = unitData.typeName -- warning: fields are called differently! typename vs type
ir.livery_id = liveries[ir.name] -- getDesc does not return livery
ir.groupId = gID
ir.unitId = theUnit:getID()
local up = theUnit:getPoint()
ir.x = up.x
ir.y = up.z -- !!! warning!
-- see if any zones are linked to this unit
ir.linkedZones = cfxZones.zonesLinkedToUnit(theUnit)
table.insert(rawUnits, ir)
ctry = theUnit:getCountry()
end
rawGroup.ctry = ctry
rawGroup.cat = cat
rawGroup.units = rawUnits
return rawGroup, cat, ctry
end
function milHelo.spawnImpostorsFromData(rawData, cat, ctry)
for idx, unitData in pairs(rawData.units) do
-- build impostor record
local ir = {}
ir.heading = unitData.heading
ir.type = unitData.type
ir.name = dcsCommon.uuid(rawData.name) -- .. "-" .. tostring(impostors.uniqueID())
ir.groupID = nil -- impostors.uniqueID()
ir.unitId = nil -- impostors.uniqueID()
ir.x = unitData.x
ir.y = unitData.y
ir.livery_id = unitData.livery_id
-- spawn the impostor
local theImp = coalition.addStaticObject(ctry, ir)
end
end
function milHelo.reachedWP(gName, wpNum, action)
if not action then action = "NIL" end
if milHelo.verbose then
trigger.action.outText("MilH group <" .. gName .. " reached wp #" .. wpNum .. " with action <" .. action .. ">.", 30)
end
if action == "remove" then
theGroup = Group.getByName(gName)
if theGroup and Group.isExist(theGroup) then
if milHelo.verbose then
trigger.action.outText("%%%%%%%%%% removing mil hel <" .. gName .. ">", 30)
end
Group.destroy(theGroup)
end
end
end
function milHelo.landedCB(who, where, from) -- who group name, where a zone
-- trigger.action.outText("milhelo landed CB for group <" .. who .. ">", 30)
-- step 1: remove the flight
local theGroup = Group.getByName(who)
if theGroup then
if Group.isExist(theGroup) then
Group.destroy(theGroup)
end
else
trigger.action.outText("+++milH: cannot find group <" .. who .. ">", 30)
end
-- step 3: replace with static helo
local aGroup = theGroup
local theFlight = milHelo.flights[who]
local oName = theFlight.oName
local theZone = theFlight.origin
-- note: "insertion" is probably wrong, remove in line below
if theZone.msnType == "insertion" or theZone.msnType == "insert" then
-- create a static stand-in for scenery
local rawData, cat, ctry = milHelo.getRawDataFromGroupNamed(who, oName)
Group.destroy(aGroup)
milHelo.spawnImpostorsFromData(rawData, cat, ctry)
else
-- remove group
Group.destroy(aGroup)
end
-- remove flight from list of active flights
milHelo.flights[who] = nil
end
--
-- update and event
--
function milHelo.update()
timer.scheduleFunction(milHelo.update, {}, timer.getTime() + 1/milHelo.ups)
-- update all master owners
for idx, theZone in pairs (milHelo.zones) do
local mo = theZone.masterOwner
if mo then
theZone.owner = mo.owner
if theZone.isDynamic then
theZone.coa = mo.owner
end
end
end
end
function milHelo.GCcollected(gName)
-- do some housekeeping?
if milHelo.verbose then
trigger.action.outText("removed flight <" .. gName .. ">", 30)
end
end
function milHelo.GC()
timer.scheduleFunction(milHelo.GC, {}, timer.getTime() + 1)
local filtered = {}
for gName, theFlight in pairs(milHelo.flights) do
local theGroup = Group.getByName(gName)
if theGroup and Group.isExist(theGroup) then
-- all fine, keep it
filtered[gName] = theFlight
else
milHelo.GCcollected(gName)
end
end
milHelo.flights = filtered
end
function milHelo:onEvent(theEvent)
if not theEvent then return end
if not theEvent.initiator then return end
local theUnit = theEvent.initiator
if not theUnit.getGroup then return end
local theGroup = theUnit:getGroup()
if not theGroup then
-- trigger.action.outText("event <" .. theEvent.id .. ">: group shenenigans for unit detected", 30)
return
end
local gName = theGroup:getName()
local theFlight = milHelo.flights[gName]
if not theFlight then return end
local id = theEvent.id
if id == 4 then
-- flight landed
-- did it land in target zone?
local p = theUnit:getPoint()
local srcZone = theFlight.origin
local tgtZone = theFlight.destination
if tgtZone:pointInZone(p) then
trigger.action.outText("Flight <" .. gName .. "> originating from <" .. srcZone.name .. "> landed in zone <" .. tgtZone.name .. ">", 30)
if srcZone.msnType == "insert" then
trigger.action.outText("Commencing Troop Insertion", 30)
milHelo.insertTroops(theUnit, tgtZone, srcZone)
end
else
-- maybe its a return flight
if srcZone:pointInZone(p) then
-- trigger.action.outText("Flight <" .. gName .. "> originating from <" .. srcZone.name .. "> landed back home", 30)
else
-- trigger.action.outText("Flight <" .. gName .. "> originating from <" .. srcZone.name .. "> landed OUTSIDE of src or target zone <" .. tgtZone.name .. ">, clearing.", 30)
end
-- remove it now
local theGroup = Group.getByName(gName)
if theGroup and Group.isExist(theGroup) then
Group.destroy(theGroup)
end
end
end
-- trigger.action.outText("Event <" .. theEvent.id .. "> for milHelo flight <" .. gName .. ">", 30)
end
--
-- API
--
function milHelo.getMilSources(side, msnType) -- msnType is optional
if side == "red" then side = 1 end -- better safe...
if side == "blue" then side = 2 end
local sources = {}
for idx, theZone in pairs(milHelo.zones) do
if theZone.coa == side then -- coa must be same side, use masterOwner for dynamism
if msnType then
if theZone.msnType == msnType then
table.insert(sources, theZone)
end
else
table.insert(sources, theZone)
end
end
end
return sources -- an array, NOT dict so we can pickrandom
end
function milHelo.getMilTargets(side, ignoreNeutral) -- gets mil targets that DO NOT belong to side
if side == "red" then side = 1 end -- better safe...
if side == "blue" then side = 2 end
local tgt = {}
for idx, theZone in pairs(milHelo.targets) do
-- we use OWNER, not COA here!
if theZone.owner ~= side then -- must NOT be owned by same side
if ignoreNeutral and theZone.owner == 0 then
else
table.insert(tgt, theZone)
--trigger.action.outText("zone <" .. theZone.name .. "> owned by <" .. theZone.owner .. "> is possible target for coa <" .. side .. ">", 30)
end
end
end
return tgt
end
--
-- Config & start
--
function milHelo.readConfigZone()
local theZone = cfxZones.getZoneByName("milHeloConfig")
if not theZone then
theZone = cfxZones.createSimpleZone("milHeloConfig")
end
milHelo.verbose = theZone.verbose
milHelo.landingDuration = theZone:getNumberFromZoneProperty("landingDuration", 180) -- seconds = 3 minutes
milHelo.ups = theZone:getNumberFromZoneProperty("ups", 1)
end
function milHelo.start()
-- lib check
if not dcsCommon.libCheck then
trigger.action.outText("cfx mil helo requires dcsCommon", 30)
return false
end
if not dcsCommon.libCheck("cfx mil helo", milHelo.requiredLibs) then
return false
end
-- read config
milHelo.readConfigZone()
-- process milHelo Zones
local attrZones = cfxZones.getZonesWithAttributeNamed("milHelo")
for k, aZone in pairs(attrZones) do
milHelo.readMilHeloZone(aZone) -- process attributes
milHelo.addMilHeloZone(aZone) -- add to list
end
for idx, keyWord in pairs(milHelo.targetKeywords) do
attrZones = cfxZones.getZonesWithAttributeNamed(keyWord)
for k, aZone in pairs(attrZones) do
milHelo.readMilTargetZone(aZone) -- process attributes
milHelo.addMilTargetZone(aZone) -- add to list
end
end
-- start update in 5 seconds
timer.scheduleFunction(milHelo.update, {}, timer.getTime() + 1/milHelo.ups)
-- start GC
milHelo.GC()
-- install event handler
world.addEventHandler(milHelo)
-- say hi
trigger.action.outText("milHelo v" .. milHelo.version .. " started.", 30)
return true
end
if not milHelo.start() then
trigger.action.outText("milHelo failed to start.", 30)
milHelo = nil
end
--[[
function milHelo.latestuff()
trigger.action.outText("doing stuff", 30)
local theZone = cfxZones.getZoneByName("milCAS") --dcsCommon.getFirstItem(milHelo.zones)
local targetZone = cfxZones.getZoneByName("mh Target") -- dcsCommon.getFirstItem(milHelo.targets)
milHelo.spawnForZone(theZone, targetZone)
theZone = cfxZones.getZoneByName("milInsert") --dcsCommon.getNthItem(milHelo.zones, 2)
milHelo.spawnForZone(theZone, targetZone)
theZone = cfxZones.getZoneByName("doCASZ")
targetZone = cfxZones.getZoneByName("milTarget Z")
if not theZone then trigger.action.outText("Not theZone", 30) end
if not targetZone then trigger.action.OutText("Not targetZone", 30) end
milHelo.spawnForZone(theZone, targetZone)
end
-- do some one-time stuff
timer.scheduleFunction(milHelo.latestuff, {}, timer.getTime() + 1)
--]]--