mirror of
https://github.com/weyne85/DML.git
synced 2025-10-29 16:57:49 +00:00
Version 1.01
Impostors
This commit is contained in:
parent
c4a7547dbd
commit
cb3cd4ccd2
Binary file not shown.
Binary file not shown.
@ -5,7 +5,7 @@
|
||||
-- Copyright (c) 2021, 2022 by Christian Franz and cf/x AG
|
||||
--
|
||||
cfxZones = {}
|
||||
cfxZones.version = "2.7.9"
|
||||
cfxZones.version = "2.8.1"
|
||||
--[[-- VERSION HISTORY
|
||||
- 2.2.4 - getCoalitionFromZoneProperty
|
||||
- getStringFromZoneProperty
|
||||
@ -80,7 +80,8 @@ cfxZones.version = "2.7.9"
|
||||
- unpulse
|
||||
- 2.7.9 - getFlagValue QoL for <none>
|
||||
- setFlagValue QoL for <none>
|
||||
|
||||
- 2.8.0 - new allGroupNamesInZone()
|
||||
- 2.8.1 - new zonesLinkedToUnit()
|
||||
|
||||
--]]--
|
||||
cfxZones.verbose = false
|
||||
@ -599,6 +600,22 @@ function cfxZones.allGroupsInZone(theZone, categ) -- categ is optional, must be
|
||||
return inZones
|
||||
end
|
||||
|
||||
function cfxZones.allGroupNamesInZone(theZone, categ) -- categ is optional, must be code
|
||||
-- warning: does not check for exiting!
|
||||
--trigger.action.outText("Zone " .. theZone.name .. " radius " .. theZone.radius, 30)
|
||||
local inZones = {}
|
||||
local coals = {0, 1, 2} -- all coalitions
|
||||
for idx, coa in pairs(coals) do
|
||||
local allGroups = coalition.getGroups(coa, categ)
|
||||
for key, group in pairs(allGroups) do -- iterate all groups
|
||||
if cfxZones.isGroupPartiallyInZone(group, theZone) then
|
||||
table.insert(inZones, group:getName())
|
||||
end
|
||||
end
|
||||
end
|
||||
return inZones
|
||||
end
|
||||
|
||||
function cfxZones.allStaticsInZone(theZone) -- categ is optional, must be code
|
||||
-- warning: does not check for exiting!
|
||||
local inZones = {}
|
||||
@ -1928,6 +1945,17 @@ function cfxZones.linkUnitToZone(theUnit, theZone, dx, dy) -- note: dy is really
|
||||
theZone.dy = dy
|
||||
end
|
||||
|
||||
function cfxZones.zonesLinkedToUnit(theUnit) -- returns all zones linked to this unit
|
||||
if not theUnit then return {} end
|
||||
local linkedZones = {}
|
||||
for idx, theZone in pairs (cfxZones.zones) do
|
||||
if theZone.linkedUnit == theUnit then
|
||||
table.insert(linkedZones, theZone)
|
||||
end
|
||||
end
|
||||
return linkedZones
|
||||
end
|
||||
|
||||
function cfxZones.updateMovingZones()
|
||||
cfxZones.updateSchedule = timer.scheduleFunction(cfxZones.updateMovingZones, {}, timer.getTime() + 1/cfxZones.ups)
|
||||
-- simply scan all cfx zones for the linkedUnit property and if there
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
groupTracker = {}
|
||||
groupTracker.version = "1.1.2"
|
||||
groupTracker.version = "1.1.3"
|
||||
groupTracker.verbose = false
|
||||
groupTracker.ups = 1
|
||||
groupTracker.requiredLibs = {
|
||||
@ -17,7 +17,9 @@ groupTracker.trackers = {}
|
||||
1.1.1 - corrected clone zone reference bug
|
||||
1.1.2 - corrected naming (removed bang from flags), deprecated old
|
||||
- more zone-local verbosity
|
||||
|
||||
1.1.3 - spellings
|
||||
- addGroupToTrackerNamed bug removed accessing tracker
|
||||
- new removeGroupNamedFromTrackerNamed()
|
||||
--]]--
|
||||
|
||||
function groupTracker.addTracker(theZone)
|
||||
@ -56,7 +58,7 @@ function groupTracker.addGroupToTracker(theGroup, theTracker)
|
||||
end
|
||||
|
||||
if groupTracker.verbose or theTracker.verbose then
|
||||
trigger.action.outText("+++gTrk: will add group <" .. theGroup:getName() .. "> to tracker " .. theTracker.name, 30)
|
||||
trigger.action.outText("+++gTrk: adding group <" .. theGroup:getName() .. "> to tracker " .. theTracker.name, 30)
|
||||
end
|
||||
|
||||
-- we have the tracker, add the group
|
||||
@ -86,14 +88,59 @@ function groupTracker.addGroupToTrackerNamed(theGroup, trackerName)
|
||||
end
|
||||
|
||||
if not theGroup:isExist() then
|
||||
trigger.action.outText("+++gTrk: group does not exist in when adding to tracker <" .. trackerName .. ">", 30)
|
||||
trigger.action.outText("+++gTrk: group does not exist when adding to tracker <" .. trackerName .. ">", 30)
|
||||
return
|
||||
end
|
||||
|
||||
local theTracker = groupTracker.getTrackerByName(trackerName)
|
||||
if not theTracker then return end
|
||||
|
||||
groupTracker.addGroupToTracker(theGroup, theTracker)
|
||||
end
|
||||
|
||||
function groupTracker.removeGroupNamedFromTrackerNamed(gName, trackerName)
|
||||
local theTracker = groupTracker.getTrackerByName(trackerName)
|
||||
if not theTracker then return end
|
||||
if not gName then
|
||||
trigger.action.outText("+++gTrk: <nil> group name in removeGroupNameFromTrackerNamed <" .. trackerName .. ">", 30)
|
||||
return
|
||||
end
|
||||
|
||||
local filteredGroups = {}
|
||||
local foundOne = false
|
||||
for idx, aGroup in pairs(theTracker.trackedGroups) do
|
||||
if aGroup:getName() == gName then
|
||||
-- skip and remember
|
||||
foundOne = true
|
||||
else
|
||||
table.insert(filteredGroups, aGroup)
|
||||
end
|
||||
end
|
||||
if (not foundOne) and (theTracker.verbose or groupTracker.verbose) then
|
||||
trigger.action.outText("+++gTrk: Removal Request Note: group <" .. gName .. "> wasn't tracked by <" .. trackerName .. ">", 30)
|
||||
end
|
||||
|
||||
-- remember the new, cleanded set
|
||||
theTracker.trackedGroups = filteredGroups
|
||||
|
||||
|
||||
if foundOne then
|
||||
if theTracker.verbose or groupTracker.verbose then
|
||||
trigger.action.outText("+++gTrk: removed group <" .. gName .. "> from tracker <" .. trackerName .. ">", 30)
|
||||
end
|
||||
|
||||
-- now bang/invoke addGroup!
|
||||
if theTracker.tRemoveGroup then
|
||||
cfxZones.pollFlag(theTracker.tRemoveGroup, "inc", theTracker)
|
||||
end
|
||||
|
||||
-- now set numGroups
|
||||
if theTracker.tNumGroups then
|
||||
cfxZones.setFlagValue(theTracker.tNumGroups, #theTracker.trackedGroups, theTracker)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- read zone
|
||||
function groupTracker.createTrackerWithZone(theZone)
|
||||
-- init group tracking set
|
||||
|
||||
559
modules/impostors.lua
Normal file
559
modules/impostors.lua
Normal file
@ -0,0 +1,559 @@
|
||||
impostors={}
|
||||
|
||||
impostors.version = "1.0.0"
|
||||
impostors.verbose = false
|
||||
impostors.ups = 1
|
||||
impostors.requiredLibs = {
|
||||
"dcsCommon", -- always
|
||||
"cfxZones", -- Zones, of course
|
||||
"cfxMX",
|
||||
}
|
||||
|
||||
impostors.impostorZones = {}
|
||||
--impostors.impostors = {} -- these are sorted by name of the orig group and contain the units by name of the impostors
|
||||
impostors.callbacks = {}
|
||||
impostors.uniqueCounter = 8200000 -- clones start at 9200000
|
||||
|
||||
--[[--
|
||||
LIMITATIONS:
|
||||
must be on ground (or would be very silly
|
||||
does not work with any units deployed on ships
|
||||
Positioning AI Planed (ME shortcoming): add a waypoint so it orients itself.
|
||||
|
||||
--]]--
|
||||
|
||||
--
|
||||
-- adding / removing from list
|
||||
--
|
||||
function impostors.addImpostorZone(theZone)
|
||||
table.insert(impostors.impostorZones, theZone)
|
||||
end
|
||||
|
||||
function impostors.getCloneZoneByName(aName)
|
||||
for idx, aZone in pairs(impostors.impostorZones) do
|
||||
if aName == aZone.name then return aZone end
|
||||
end
|
||||
if impostors.verbose then
|
||||
trigger.action.outText("+++ipst: no impostor with name <" .. aName ..">", 30)
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- spawn impostors from data
|
||||
--
|
||||
function impostors.uniqueID()
|
||||
local uid = impostors.uniqueCounter
|
||||
impostors.uniqueCounter = impostors.uniqueCounter + 1
|
||||
return uid
|
||||
end
|
||||
|
||||
function impostors.spawnImpostorsFromData(rawData, cat, ctry)
|
||||
local theImpostors = {}
|
||||
-- we iterate a group's raw data unit by unit and create
|
||||
-- a static for each unit, named exactly as the original unit
|
||||
-- modifies rawData for use later
|
||||
for idx, unitData in pairs(rawData.units) do
|
||||
-- build impostor record
|
||||
local ir = {}
|
||||
ir.heading = unitData.heading
|
||||
ir.type = unitData.type
|
||||
ir.name = rawData.name .. "-" .. tostring(impostors.uniqueID())
|
||||
ir.groupID = impostors.uniqueID()
|
||||
ir.unitId = impostors.uniqueID()
|
||||
theImpostors[unitData.name] = ir.name -- for lookup later
|
||||
ir.x = unitData.x
|
||||
ir.y = unitData.y
|
||||
ir.livery_id = unitData.livery_id
|
||||
|
||||
if impostors.verbose then
|
||||
trigger.action.outText("+++impostoring unit <" .. unitData.name .. ">: name <" .. ir.name .. ">, x <" .. ir.x .. ">, y <" .. ir.y .. ">, heading <" .. ir.heading .. ">, type <" .. ir.type .. "> ", 30)
|
||||
end
|
||||
local linkedZones = unitData.linkedZones
|
||||
-- spawn the impostor
|
||||
local theImp = coalition.addStaticObject(ctry, ir)
|
||||
-- relink linked zones to this
|
||||
if #linkedZones > 0 then
|
||||
for idx, theZone in pairs(linkedZones) do
|
||||
theZone.linkedUnit = theImp
|
||||
if theZone.verbose then
|
||||
trigger.action.outText("+++ipst: imp-linked zone <" .. theZone.name .. "> to imp <" .. theImp:getName() .. ">", 30)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return theImpostors
|
||||
end
|
||||
--
|
||||
-- read impostor zone
|
||||
--
|
||||
|
||||
function impostors.getRawDataFromGroupNamed(gName)
|
||||
if gName then
|
||||
theGroup = Group.getByName(gName)
|
||||
if not theGroup then
|
||||
trigger.action.outText("+++ipst: getRawDataFromGroupName cant find group <" .. gName .. ">", 30)
|
||||
return nil, nil, nil
|
||||
end
|
||||
else
|
||||
trigger.action.outText("+++ipst: getRawDataFromGroupName has no name to look up", 30)
|
||||
return nil, nil, nil
|
||||
end
|
||||
local groupName = gName
|
||||
local cat = theGroup:getCategory()
|
||||
-- access mxdata for livery because getDesc does not return the livery
|
||||
local liveries = {}
|
||||
local mxData = cfxMX.getGroupFromDCSbyName(gName)
|
||||
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 impostors.createImpostorWithZone(theZone) -- has "impostor?"
|
||||
if impostors.verbose or theZone.verbose then
|
||||
trigger.action.outText("+++ipst: new impostor " .. theZone.name, 30)
|
||||
end
|
||||
|
||||
-- the impostor? is the flag. we always have it.
|
||||
-- must match aZone.impostorFlag, aZone.impostorTriggerMethod, "lastImpostorValue"
|
||||
theZone.impostorFlag = cfxZones.getStringFromZoneProperty(theZone, "impostor?", "*<none>")
|
||||
theZone.lastImpostorValue = cfxZones.getFlagValue(theZone.impostorFlag, theZone)
|
||||
|
||||
if cfxZones.hasProperty(theZone, "reanimate?") then
|
||||
theZone.reanimateFlag = cfxZones.getStringFromZoneProperty(theZone, "reanimate?", "*<none>")
|
||||
theZone.lastReanimateValue = cfxZones.getFlagValue(theZone.reanimateFlag, theZone)
|
||||
end
|
||||
|
||||
-- watchflag:
|
||||
-- triggerMethod
|
||||
theZone.impostorTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "triggerMethod", "change")
|
||||
|
||||
if cfxZones.hasProperty(theZone, "impostorTriggerMethod") then
|
||||
theZone.impostorTriggerMethod = cfxZones.getStringFromZoneProperty(theZone, "impostorTriggerMethod", "change")
|
||||
end
|
||||
|
||||
-- local localGroups = impostors.allGroupsInZoneByData(theZone)
|
||||
theZone.groupNames = cfxZones.allGroupNamesInZone(theZone)
|
||||
theZone.impostor = false -- we have not yet turned units into impostors
|
||||
theZone.myImpostors = {}
|
||||
theZone.origin = cfxZones.getPoint(theZone) -- save reference point for all groupVectors
|
||||
|
||||
theZone.onStart = cfxZones.getBoolFromZoneProperty(theZone, "onStart", false)
|
||||
|
||||
-- blinking
|
||||
theZone.blinkTime = cfxZones.getNumberFromZoneProperty(theZone, "blink", -1)
|
||||
theZone.blinkCount = 0
|
||||
|
||||
-- interface to groupTracker tbc
|
||||
if cfxZones.hasProperty(theZone, "trackWith:") then
|
||||
theZone.trackWith = cfxZones.getStringFromZoneProperty(theZone, "trackWith:", "<None>")
|
||||
end
|
||||
|
||||
-- check onStart, and act accordingly
|
||||
if theZone.onStart then
|
||||
impostors.turnZoneIntoImpostors(theZone)
|
||||
end
|
||||
|
||||
-- all dead
|
||||
if cfxZones.hasProperty(theZone, "allDead!") then
|
||||
theZone.allDead = cfxZones.getStringFromZoneProperty(theZone, "allDead", "<None>")
|
||||
end
|
||||
|
||||
theZone.impostorMethod = cfxZones.getStringFromZoneProperty(theZone, "method", "inc")
|
||||
if cfxZones.hasProperty(theZone, "impostorMethod") then
|
||||
theZone.impostorMethod = cfxZones.getStringFromZoneProperty(theZone, "impostorMethod", "inc")
|
||||
end
|
||||
|
||||
-- declare all units as alive
|
||||
theZone.allImpsDead = false
|
||||
-- we end with group replaced by impostors
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- Spawning
|
||||
--
|
||||
|
||||
-- REAL --> IMP
|
||||
function impostors.turnGroupsIntoImpostors(theZone)
|
||||
-- can be handed an array of strings or groups.
|
||||
-- returns a dict of impostors, indexed by group names
|
||||
local theGroupNames = theZone.groupNames
|
||||
local myImpostors = {}
|
||||
for idx, aGroupName in pairs(theGroupNames) do
|
||||
local gName = aGroupName
|
||||
if type(gName) == "table" then -- this is a group. get its name
|
||||
trigger.action.outText("+++ipst: converting table gName to string in turnGroupsIntoImpostors",30)
|
||||
gName = gName:getName()
|
||||
end
|
||||
if not gName then
|
||||
trigger.action.outText("+++ipst: nil group name in turnGroupsIntoImpostors",30)
|
||||
return nil
|
||||
end
|
||||
local aGroup = Group.getByName(gName)
|
||||
if aGroup and gName then
|
||||
-- record unit data to create impostors
|
||||
local rawData, cat, ctry = impostors.getRawDataFromGroupNamed(gName)
|
||||
-- if we are tracking the group, remove it from tracker
|
||||
if theZone.trackWith and groupTracker.removeGroupNamedFromTrackerNamed then
|
||||
groupTracker.removeGroupNamedFromTrackerNamed(gName, theZone.trackWith)
|
||||
end
|
||||
|
||||
-- despawn the group. we'll spawn statics now
|
||||
-- we may do some book-keeping first for the
|
||||
-- names. we'll see later
|
||||
Group.destroy(aGroup)
|
||||
-- local rawData, cat, ctry = cfxMX.getGroupFromDCSbyName(gName)
|
||||
-- local origID = rawData.groupId -- may be redundant
|
||||
-- now spawn impostors based on the rawData,
|
||||
-- and return impostorGroup
|
||||
local impostorGroup = impostors.spawnImpostorsFromData(rawData, cat, ctry)
|
||||
myImpostors[gName] = impostorGroup
|
||||
end
|
||||
end
|
||||
return myImpostors
|
||||
end
|
||||
|
||||
function impostors.turnZoneIntoImpostors(theZone)
|
||||
if theZone.verbose then
|
||||
trigger.action.outText("+++ipst: creating impostors for zone <" .. theZone.name ..">", 30)
|
||||
end
|
||||
theZone.myImpostors = impostors.turnGroupsIntoImpostors(theZone)
|
||||
if theZone.myImpostors then
|
||||
theZone.impostor = true
|
||||
else
|
||||
if theZone.verbose or impostors.verbose then
|
||||
trigger.action.outText("+++ipst: groups to impostors failed for <" .. theZone.name .. ">",30)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- IMP --> REAL
|
||||
function impostors.relinkZonesForGroup(relinkZones, newGroup)
|
||||
-- may be called sync and async!
|
||||
local allUnits = newGroup:getUnits()
|
||||
for idx, theUnit in pairs(allUnits) do
|
||||
local unitName = theUnit:getName()
|
||||
local linkedZones = relinkZones[unitName]
|
||||
if linkedZones and #linkedZones > 0 then
|
||||
for idy, theZone in pairs(linkedZones) do
|
||||
theZone.linkedUnit = theUnit
|
||||
if theZone.verbose then
|
||||
trigger.action.outText("+++ipst: re-linked zone <" .. theZone.name .. "> to unit <" .. unitName .. ">", 30)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function impostors.spawnGroupsFromImpostor(theZone)
|
||||
-- turn zone's impostors (static objects) into units
|
||||
if theZone.verbose or impostors.verbose then
|
||||
trigger.action.outText("+++ipst: spawning for impostor <" .. theZone.name .. ">", 30)
|
||||
end
|
||||
|
||||
if not theZone.impostor then
|
||||
if theZone.verbose or impostors.verbose then
|
||||
trigger.action.outText("+++ipst: <> groups are not impostors.", 30)
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local deadUnits = {} -- collect all dead units for immediate delete
|
||||
-- after spawning
|
||||
|
||||
for idx, groupName in pairs(theZone.groupNames) do
|
||||
-- get my group data from MX based on my name
|
||||
-- we get from MX so we get all path and order info
|
||||
local rawData, cat, ctry = cfxMX.getGroupFromDCSbyName(groupName)
|
||||
local impostorGroup = theZone.myImpostors[groupName]
|
||||
local relinkZones = {}
|
||||
-- now iterate all units in that group, and remove their impostors
|
||||
for idy, theUnit in pairs(rawData.units) do
|
||||
local impName = impostorGroup[theUnit.name]
|
||||
local impStat = StaticObject.getByName(impName)
|
||||
if impStat and impStat:isExist() and impStat:getLife() > 1 then
|
||||
-- still alive. read x, y and heading
|
||||
local sp = impStat:getPoint()
|
||||
theUnit.x = sp.x
|
||||
theUnit.y = sp.z -- !!!
|
||||
theUnit.heading = dcsCommon.getUnitHeading(impStat) -- should also work for statics
|
||||
-- should automatically handle ["livery_id"]
|
||||
relinkZones[theUnit.name] = cfxZones.zonesLinkedToUnit(impStat)
|
||||
else
|
||||
-- dead
|
||||
table.insert(deadUnits, theUnit.name)
|
||||
end
|
||||
-- destroy imp
|
||||
if impStat and impStat:isExist() then
|
||||
impStat:destroy()
|
||||
end
|
||||
end
|
||||
|
||||
-- destroy impostor info
|
||||
theZone.myImpostors[groupName] = nil
|
||||
theZone.impostor = false
|
||||
|
||||
-- now create the group
|
||||
if theZone.blinkTime <= 0 then
|
||||
-- immediate spawn
|
||||
local newGroup = coalition.addGroup(ctry, cfxMX.catText2ID(cat), rawData)
|
||||
impostors.relinkZonesForGroup(relinkZones, newGroup)
|
||||
if theZone.trackWith and groupTracker.addGroupToTrackerNamed then
|
||||
-- add these groups to the group tracker
|
||||
if theZone.verbose or impostors.verbose then
|
||||
trigger.action.outText("+++ipst: attempting to add group <" .. newGroup:getName() .. "> to tracker <" .. theZone.trackWith .. ">", 30)
|
||||
end
|
||||
groupTracker.addGroupToTrackerNamed(newGroup, theZone.trackWith)
|
||||
end
|
||||
else
|
||||
-- scheduled spawn
|
||||
theZone.blinkCount = theZone.blinkCount + 1 -- so healthcheck avoids false positives
|
||||
local args = {}
|
||||
args.ctry = ctry
|
||||
args.cat = cfxMX.catText2ID(cat)
|
||||
args.rawData = rawData
|
||||
args.theZone = theZone
|
||||
args.relinkZones = relinkZones
|
||||
timer.scheduleFunction(impostors.delayedSpawn, args, timer.getTime() + theZone.blinkTime)
|
||||
end
|
||||
end
|
||||
|
||||
-- now remove all dead units
|
||||
if theZone.blinkTime <= 0 then
|
||||
for idx, unitName in pairs(deadUnits) do
|
||||
local theUnit = Unit.getByName(unitName)
|
||||
if theUnit then
|
||||
theUnit:destroy() -- BAD BAD BAD!!!! do some guarding, mon!
|
||||
end
|
||||
end
|
||||
else
|
||||
-- schedule removal of all dead units for later
|
||||
timer.scheduleFunction(impostors.delayedCleanup, deadUnits, timer.getTime() + theZone.blinkTime + 0.1)
|
||||
end
|
||||
theZone.myImpostors = nil
|
||||
end
|
||||
|
||||
function impostors.delayedSpawn(args)
|
||||
local rawData = args.rawData
|
||||
local cat = args.cat
|
||||
local ctry = args.ctry
|
||||
local theZone = args.theZone
|
||||
local relinkZones = args.relinkZones
|
||||
if theZone.verbose or impostors.verbose then
|
||||
trigger.action.outText("+++ipst: delayed spawn for group <" .. rawData.name .. "> of zone <" .. theZone.name .. ">", 30)
|
||||
end
|
||||
local newGroup = coalition.addGroup(ctry, cat, rawData)
|
||||
impostors.relinkZonesForGroup(relinkZones, newGroup)
|
||||
|
||||
if theZone.trackWith and groupTracker.addGroupToTrackerNamed then
|
||||
-- add these groups to the group tracker
|
||||
if theZone.verbose or impostors.verbose then
|
||||
trigger.action.outText("+++ipst: attempting to add group <" .. newGroup:getName() .. "> to tracker <" .. theZone.trackWith .. ">", 30)
|
||||
end
|
||||
groupTracker.addGroupToTrackerNamed(newGroup, theZone.trackWith)
|
||||
end
|
||||
-- close TRX bracket for blinking, health check can proceed
|
||||
theZone.blinkCount = theZone.blinkCount - 1
|
||||
end
|
||||
|
||||
function impostors.delayedCleanup(deadUnits)
|
||||
for idx, unitName in pairs(deadUnits) do
|
||||
local theUnit = Unit.getByName(unitName)
|
||||
if theUnit then
|
||||
theUnit:destroy() -- BAD BAD BAD!!!! do some guarding, mon!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- healthCheck
|
||||
--
|
||||
function impostors.healthCheck(theZone)
|
||||
-- make sure there is at least one living unit left
|
||||
-- if not, bang!
|
||||
if theZone.allImpsDead then return end -- we are already dead
|
||||
|
||||
if theZone.impostor then
|
||||
-- we have impostors. Check until you find the first live ones
|
||||
for gName, impNames in pairs (theZone.myImpostors) do
|
||||
-- impNames are the names of all the static objects
|
||||
-- in this group
|
||||
for idx, theImpName in pairs (impNames) do
|
||||
local theImp = StaticObject.getByName(theImpName)
|
||||
if theImp and theImp:isExist() then
|
||||
local life = theImp:getLife()
|
||||
if life > 1 then
|
||||
-- all is well, at least one imp alive
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- when we get here, all imps are dead,
|
||||
-- drop through
|
||||
if theZone.verbose or impostors.verbose then
|
||||
trigger.action.outText("+++ipst: Zone <" .. theZone.name .. "> - all impostors destroyed. Removing.", 30)
|
||||
end
|
||||
else
|
||||
-- we have real groups. Let's iterate
|
||||
if theZone.blinkCount > 0 then return end -- blinking, no healtch check
|
||||
theZone.BlinkCount = 0 -- just in case it went negative
|
||||
|
||||
for idx, groupName in pairs(theZone.groupNames) do
|
||||
local theGroup = Group.getByName(groupName)
|
||||
if theGroup and theGroup:isExist() then
|
||||
local allUnits = theGroup:getUnits()
|
||||
for idy, aUnit in pairs (allUnits) do
|
||||
if aUnit:isExist() then
|
||||
local life = aUnit:getLife()
|
||||
if life > 1 then
|
||||
return -- all is well
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- if we get here, all units ded
|
||||
if theZone.verbose or impostors.verbose then
|
||||
trigger.action.outText("+++ipst: Zone <" .. theZone.name .. "> - all active units destroyed. Removing.", 30)
|
||||
end
|
||||
end
|
||||
|
||||
-- when we get here , all are ded
|
||||
theZone.allImpsDead = true
|
||||
if theZone.allDead then
|
||||
cfxZones.pollFlag(theZone.allDead, theZone.impostorMethod, theZone)
|
||||
end
|
||||
end
|
||||
|
||||
--
|
||||
-- Update
|
||||
--
|
||||
function impostors.update()
|
||||
timer.scheduleFunction(impostors.update, {}, timer.getTime() + 1/impostors.ups)
|
||||
|
||||
for idx, aZone in pairs(impostors.impostorZones) do
|
||||
-- first perform health check on all zones
|
||||
impostors.healthCheck(aZone)
|
||||
|
||||
-- now see if we received signals
|
||||
if not aZone.allImpsDead then
|
||||
-- see if we got impostor? command
|
||||
if cfxZones.testZoneFlag(aZone, aZone.impostorFlag, aZone.impostorTriggerMethod, "lastImpostorValue") then
|
||||
if impostors.verbose or aZone.verbose then
|
||||
trigger.action.outText("+++ipst: turn group to impostors triggered for <" .. aZone.name .. "> on <" .. aZone.impostorFlag .. ">", 30)
|
||||
end
|
||||
impostors.turnZoneIntoImpostors(aZone)
|
||||
end
|
||||
|
||||
if aZone.reanimateFlag and cfxZones.testZoneFlag(aZone, aZone.reanimateFlag, aZone.impostorTriggerMethod, "lastReanimateValue") then
|
||||
if impostors.verbose or aZone.verbose then
|
||||
trigger.action.outText("+++ipst: impostor to live groups spawn triggered for <" .. aZone.name .. "> on <" .. aZone.impostorFlag .. ">", 30)
|
||||
end
|
||||
impostors.spawnGroupsFromImpostor(aZone)
|
||||
end
|
||||
else
|
||||
-- nothing to do, all dead
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--
|
||||
-- start
|
||||
--
|
||||
function impostors.readConfigZone()
|
||||
local theZone = cfxZones.getZoneByName("impostorsConfig")
|
||||
if not theZone then
|
||||
if impostors.verbose then
|
||||
trigger.action.outText("+++ipst: NO config zone!", 30)
|
||||
end
|
||||
theZone = cfxZones.createSimpleZone("impostorsConfig")
|
||||
end
|
||||
|
||||
impostors.ups = cfxZones.getNumberFromZoneProperty(theZone, "ups", 1)
|
||||
|
||||
impostors.verbose = cfxZones.getBoolFromZoneProperty(theZone, "verbose", false)
|
||||
|
||||
if impostors.verbose then
|
||||
trigger.action.outText("+++ipst: read config", 30)
|
||||
end
|
||||
end
|
||||
|
||||
function impostors.start()
|
||||
-- lib check
|
||||
if not dcsCommon.libCheck then
|
||||
trigger.action.outText("cfx Impostors requires dcsCommon", 30)
|
||||
return false
|
||||
end
|
||||
if not dcsCommon.libCheck("cfx Impostors",
|
||||
impostors.requiredLibs) then
|
||||
return false
|
||||
end
|
||||
|
||||
-- read config
|
||||
impostors.readConfigZone()
|
||||
|
||||
-- process cloner Zones
|
||||
local attrZones = cfxZones.getZonesWithAttributeNamed("impostor?")
|
||||
|
||||
-- now create an rnd gen for each one and add them
|
||||
-- to our watchlist
|
||||
for k, aZone in pairs(attrZones) do
|
||||
impostors.createImpostorWithZone(aZone) -- process attribute and add to zone
|
||||
impostors.addImpostorZone(aZone) -- remember it so we can smoke it
|
||||
end
|
||||
|
||||
-- start update
|
||||
impostors.update()
|
||||
|
||||
trigger.action.outText("cfx Impostors v" .. impostors.version .. " started.", 30)
|
||||
return true
|
||||
end
|
||||
|
||||
-- let's go!
|
||||
if not impostors.start() then
|
||||
trigger.action.outText("cf/x Impostors aborted: missing libraries", 30)
|
||||
impostors = nil
|
||||
end
|
||||
|
||||
--[[--
|
||||
To do
|
||||
- reset? flag: will reset all to MX locationS
|
||||
- add a zone's follow ability to impostors by allowing linkedUnit to work with impostors
|
||||
|
||||
--]]--
|
||||
@ -253,4 +253,5 @@ end
|
||||
--[[--
|
||||
to do: turn on/off via flags
|
||||
callbacks for the menus
|
||||
one-shot items
|
||||
--]]--
|
||||
BIN
tutorial & demo missions/demo - Impossible Impostors.miz
Normal file
BIN
tutorial & demo missions/demo - Impossible Impostors.miz
Normal file
Binary file not shown.
Loading…
x
Reference in New Issue
Block a user