Merge pull request #1433 from FlightControl-Master/FF/Ops

OPS
This commit is contained in:
Frank 2021-01-15 23:44:46 +01:00 committed by GitHub
commit 796561b8b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 415 additions and 77 deletions

View File

@ -101,6 +101,7 @@ function ARMYGROUP:New(Group)
self.lid=string.format("ARMYGROUP %s | ", self.groupname)
-- Defaults
self.isArmygroup=true
self:SetDefaultROE()
self:SetDefaultAlarmstate()
self:SetDetection()
@ -830,7 +831,7 @@ function ARMYGROUP:onafterEngageTarget(From, Event, To, Target)
end
--- On after "EngageTarget" event.
--- Update engage target.
-- @param #ARMYGROUP self
function ARMYGROUP:_UpdateEngageTarget()

View File

@ -101,6 +101,7 @@
--
-- @field #string missionTask Mission task. See `ENUMS.MissionTask`.
-- @field #number missionAltitude Mission altitude in meters.
-- @field #number missionSpeed Mission speed in km/h.
-- @field #number missionFraction Mission coordiante fraction. Default is 0.5.
-- @field #number missionRange Mission range in meters. Used in AIRWING class.
-- @field Core.Point#COORDINATE missionWaypointCoord Mission waypoint coordinate.
@ -315,6 +316,7 @@ _AUFTRAGSNR=0
-- @field #string TANKER Tanker mission.
-- @field #string TROOPTRANSPORT Troop transport mission.
-- @field #string ARTY Fire at point.
-- @field #string PATROLZONE Patrol a zone.
AUFTRAG.Type={
ANTISHIP="Anti Ship",
AWACS="AWACS",
@ -338,6 +340,7 @@ AUFTRAG.Type={
TANKER="Tanker",
TROOPTRANSPORT="Troop Transport",
ARTY="Fire At Point",
PATROLZONE="Patrol Zone",
}
--- Mission status.
@ -439,7 +442,7 @@ AUFTRAG.TargetType={
--- AUFTRAG class version.
-- @field #string version
AUFTRAG.version="0.5.0"
AUFTRAG.version="0.6.0"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@ -1191,6 +1194,32 @@ function AUFTRAG:NewARTY(Target, Nshots, Radius)
return mission
end
--- Create a PATROLZONE mission. Group(s) will go to the zone and patrol it randomly.
-- @param #AUFTRAG self
-- @param Core.Zone#ZONE Zone The patrol zone.
-- @param #number Speed Speed in knots.
-- @param #number Altitude Altitude in feet. Only for airborne units. Default 2000 feet ASL.
-- @return #AUFTRAG self
function AUFTRAG:NewPATROLZONE(Zone, Speed, Altitude)
local mission=AUFTRAG:New(AUFTRAG.Type.PATROLZONE)
mission:_TargetFromObject(Zone)
mission.optionROE=ENUMS.ROE.OpenFire
mission.optionROT=ENUMS.ROT.PassiveDefense
mission.optionAlarm=ENUMS.AlarmState.Auto
mission.missionFraction=1.0
mission.missionSpeed=Speed and UTILS.KnotsToKmph(Speed) or nil
mission.missionAltitude=Altitude and UTILS.FeetToMeters(Altitude) or nil
mission.DCStask=mission:GetDCSMissionTask()
return mission
end
--- Create a mission to attack a group. Mission type is automatically chosen from the group category.
-- @param #AUFTRAG self
-- @param Ops.Target#TARGET Target The target.
@ -2926,7 +2955,7 @@ end
-- @param #AUFTRAG self
-- @return Wrapper.Positionable#POSITIONABLE The target object. Could be many things.
function AUFTRAG:GetObjective()
return self:GetTargetData().Target
return self:GetTargetData():GetObject()
end
--- Get type of target.
@ -3389,6 +3418,26 @@ function AUFTRAG:GetDCSMissionTask(TaskControllable)
table.insert(DCStasks, DCStask)
elseif self.type==AUFTRAG.Type.PATROLZONE then
-------------------------
-- PATROL ZONE Mission --
-------------------------
local DCStask={}
DCStask.id="PatrolZone"
-- We create a "fake" DCS task and pass the parameters to the FLIGHTGROUP.
local param={}
param.zone=self:GetObjective()
param.altitude=self.missionAltitude
param.speed=self.missionSpeed
DCStask.params=param
table.insert(DCStasks, DCStask)
else
self:E(self.lid..string.format("ERROR: Unknown mission task!"))
return nil

View File

@ -251,6 +251,7 @@ function FLIGHTGROUP:New(group)
self:SetDefaultROE()
self:SetDefaultROT()
self:SetDetection()
self.isFlightgroup=true
-- Holding flag.
self.flaghold=USERFLAG:New(string.format("%s_FlagHold", self.groupname))
@ -277,10 +278,9 @@ function FLIGHTGROUP:New(group)
self:AddTransition("*", "OutOfMissilesAG", "*") -- Group is out of A2G missiles. Not implemented yet!
self:AddTransition("*", "OutOfMissilesAS", "*") -- Group is out of A2G missiles. Not implemented yet!
self:AddTransition("Airborne", "EngageTargets", "Engaging") -- Engage targets.
self:AddTransition("Airborne", "EngageTarget", "Engaging") -- Engage targets.
self:AddTransition("Engaging", "Disengage", "Airborne") -- Engagement over.
self:AddTransition("*", "ElementParking", "*") -- An element is parking.
self:AddTransition("*", "ElementEngineOn", "*") -- An element spooled up the engines.
self:AddTransition("*", "ElementTaxiing", "*") -- An element is taxiing to the runway.
@ -291,7 +291,6 @@ function FLIGHTGROUP:New(group)
self:AddTransition("*", "ElementOutOfAmmo", "*") -- An element is completely out of ammo.
self:AddTransition("*", "Parking", "Parking") -- The whole flight group is parking.
self:AddTransition("*", "Taxiing", "Taxiing") -- The whole flight group is taxiing.
self:AddTransition("*", "Takeoff", "Airborne") -- The whole flight group is airborne.
@ -512,6 +511,56 @@ function FLIGHTGROUP:SetFuelCriticalRTB(switch)
return self
end
--- Enable to automatically engage detected targets.
-- @param #FLIGHTGROUP self
-- @param #number RangeMax Max range in NM. Only detected targets within this radius from the group will be engaged. Default is 25 NM.
-- @param #table TargetTypes Types of target attributes that will be engaged. See [DCS enum attributes](https://wiki.hoggitworld.com/view/DCS_enum_attributes). Default "All".
-- @param Core.Set#SET_ZONE EngageZoneSet Set of zones in which targets are engaged. Default is anywhere.
-- @param Core.Set#SET_ZONE NoEngageZoneSet Set of zones in which targets are *not* engaged. Default is nowhere.
-- @return #FLIGHTGROUP self
function FLIGHTGROUP:SetEngageDetectedOn(RangeMax, TargetTypes, EngageZoneSet, NoEngageZoneSet)
-- Ensure table.
if TargetTypes then
if type(TargetTypes)~="table" then
TargetTypes={TargetTypes}
end
else
TargetTypes={"All"}
end
-- Ensure SET_ZONE if ZONE is provided.
if EngageZoneSet and EngageZoneSet:IsInstanceOf("ZONE_BASE") then
local zoneset=SET_ZONE:New():AddZone(EngageZoneSet)
EngageZoneSet=zoneset
end
if NoEngageZoneSet and NoEngageZoneSet:IsInstanceOf("ZONE_BASE") then
local zoneset=SET_ZONE:New():AddZone(NoEngageZoneSet)
NoEngageZoneSet=zoneset
end
-- Set parameters.
self.engagedetectedOn=true
self.engagedetectedRmax=UTILS.NMToMeters(RangeMax or 25)
self.engagedetectedTypes=TargetTypes
self.engagedetectedEngageZones=EngageZoneSet
self.engagedetectedNoEngageZones=NoEngageZoneSet
-- Ensure detection is ON or it does not make any sense.
self:SetDetection(true)
return self
end
--- Disable to automatically engage detected targets.
-- @param #FLIGHTGROUP self
-- @return #OPSGROUP self
function FLIGHTGROUP:SetEngageDetectedOff()
self.engagedetectedOn=false
return self
end
--- Enable that the group is despawned after landing. This can be useful to avoid DCS taxi issues with other AI or players or jamming taxiways.
-- @param #FLIGHTGROUP self
-- @return #FLIGHTGROUP self
@ -977,6 +1026,82 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
end
end
if self:IsAirborne() and self.detectionOn and self.engagedetectedOn then
-- Target.
local targetgroup=nil --Wrapper.Group#GROUP
local targetdist=math.huge
-- Loop over detected groups.
for _,_group in pairs(self.detectedgroups:GetSet()) do
local group=_group --Wrapper.Group#GROUP
if group and group:IsAlive() then
local targetcoord=group:GetCoordinate()
local distance=targetcoord:Get2DDistance(self:GetCoordinate())
if distance<=self.engagedetectedRmax and distance<targetdist then
-- Check type attribute.
local righttype=false
for _,attribute in pairs(self.engagedetectedTypes) do
if group:HasAttribute(attribute, false) then
righttype=true
break
end
end
-- We got the right type.
if righttype then
local insideEngage=true
local insideNoEngage=false
-- Check engage zones.
if self.engagedetectedEngageZones then
insideEngage=false
for _,_zone in pairs(self.engagedetectedEngageZones.Set) do
local zone=_zone --Core.Zone#ZONE
local inzone=zone:IsCoordinateInZone(targetcoord)
if inzone then
insideEngage=true
break
end
end
end
-- Check no engage zones.
if self.engagedetectedNoEngageZones then
for _,_zone in pairs(self.engagedetectedNoEngageZones.Set) do
local zone=_zone --Core.Zone#ZONE
local inzone=zone:IsCoordinateInZone(targetcoord)
if inzone then
insideNoEngage=true
break
end
end
end
-- If inside engage but not inside no engage zones.
if insideEngage and not insideNoEngage then
targetdist=distance
targetgroup=group
end
end
end
end
end
if targetgroup then
self:EngageTarget(targetgroup)
end
end
-- Next check in ~30 seconds.
if not self:IsStopped() then
@ -1795,9 +1920,15 @@ function FLIGHTGROUP:onbeforeUpdateRoute(From, Event, To, n)
end
if self.taskcurrent>0 then
local task=self:GetTaskCurrent()
if task.dcstask.id=="PatrolZone" then
-- For patrol zone, we need to allow the update.
else
self:E(self.lid.."Update route denied because taskcurrent>0")
allowed=false
end
end
-- Not good, because mission will never start. Better only check if there is a current task!
--if self.currentmission then
@ -1920,6 +2051,11 @@ function FLIGHTGROUP:_CheckGroupDone(delay)
return
end
-- Group is currently engaging.
if self:IsEngaging() then
return
end
-- Number of tasks remaining.
local nTasks=self:CountRemainingTasks()
@ -2377,30 +2513,85 @@ function FLIGHTGROUP:onafterHolding(From, Event, To)
end
--- On after "EngageTargets" event. Order to engage a set of units.
--- On after "EngageTarget" event.
-- @param #FLIGHTGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param #table Target Target object. Can be a UNIT, STATIC, GROUP, SET_UNIT or SET_GROUP object.
function FLIGHTGROUP:onafterEngageTarget(From, Event, To, Target)
-- DCS task.
local DCStask=nil
-- Check target object.
if Target:IsInstanceOf("UNIT") or Target:IsInstanceOf("STATIC") then
DCStask=self:GetGroup():TaskAttackUnit(Target, true)
elseif Target:IsInstanceOf("GROUP") then
DCStask=self:GetGroup():TaskAttackGroup(Target, nil, nil, nil, nil, nil, nil, true)
elseif Target:IsInstanceOf("SET_UNIT") then
local DCSTasks={}
for _,_unit in pairs(Target:GetSet()) do --detected by =HRP= Zero
local unit=_unit --Wrapper.Unit#UNIT
local task=self:GetGroup():TaskAttackUnit(unit, true)
table.insert(DCSTasks)
end
-- Task combo.
DCStask=self:GetGroup():TaskCombo(DCSTasks)
elseif Target:IsInstanceOf("SET_GROUP") then
local DCSTasks={}
for _,_unit in pairs(Target:GetSet()) do --detected by =HRP= Zero
local unit=_unit --Wrapper.Unit#UNIT
local task=self:GetGroup():TaskAttackGroup(Target, nil, nil, nil, nil, nil, nil, true)
table.insert(DCSTasks)
end
-- Task combo.
DCStask=self:GetGroup():TaskCombo(DCSTasks)
else
self:E("ERROR: unknown Target in EngageTarget! Needs to be a UNIT, STATIC, GROUP, SET_UNIT or SET_GROUP")
return
end
-- Create new task.The description "Engage_Target" is checked so do not change that lightly.
local Task=self:NewTaskScheduled(DCStask, 1, "Engage_Target", 0)
-- Backup ROE setting.
Task.backupROE=self:GetROE()
-- Switch ROE to open fire
self:SwitchROE(ENUMS.ROE.OpenFire)
-- Pause current mission.
local mission=self:GetMissionCurrent()
if mission then
self:PauseMission()
end
-- Execute task.
self:TaskExecute(Task)
end
--- On after "Disengage" event.
-- @param #FLIGHTGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Set#SET_UNIT TargetUnitSet
function FLIGHTGROUP:onafterEngageTargets(From, Event, To, TargetUnitSet)
local DCSTasks={}
for _,_unit in pairs(TargetUnitSet:GetSet()) do --detected by =HRP= Zero
local unit=_unit --Wrapper.Unit#UNIT
local task=self.group:TaskAttackUnit(unit, true)
table.insert(DCSTasks)
end
-- Task combo.
local DCSTask=self.group:TaskCombo(DCSTasks)
--TODO needs a task function that calls EngageDone or so event and updates the route again.
-- Lets try if pushtask actually leaves the remaining tasks untouched.
self:SetTask(DCSTask)
function FLIGHTGROUP:onafterDisengage(From, Event, To)
self:T(self.lid.."Disengage target")
end
--- On before "LandAt" event. Check we have a helo group.

View File

@ -123,6 +123,7 @@ function NAVYGROUP:New(GroupName)
self:SetDefaultAlarmstate()
self:SetPatrolAdInfinitum(true)
self:SetPathfinding(false)
self.isNavygroup=true
-- Add FSM transitions.
-- From State --> Event --> To State

View File

@ -22,6 +22,9 @@
-- @field #table template Template of the group.
-- @field #boolean isLateActivated Is the group late activated.
-- @field #boolean isUncontrolled Is the group uncontrolled.
-- @field #boolean isFlightgroup Is a FLIGHTGROUP.
-- @field #boolean isArmygroup Is an ARMYGROUP.
-- @field #boolean isNavygroup Is a NAVYGROUP.
-- @field #table elements Table of elements, i.e. units of the group.
-- @field #boolean isAI If true, group is purely AI.
-- @field #boolean isAircraft If true, group is airplane or helicopter.
@ -223,6 +226,7 @@ OPSGROUP.TaskType={
-- @field #number timestamp Abs. mission time, when task was started.
-- @field #number waypoint Waypoint index if task is a waypoint task.
-- @field Core.UserFlag#USERFLAG stopflag If flag is set to 1 (=true), the task is stopped.
-- @field #number backupROE Rules of engagement that are restored once the task is over.
--- Enroute task.
-- @type OPSGROUP.EnrouteTask
@ -326,7 +330,7 @@ OPSGROUP.TaskType={
--- NavyGroup version.
-- @field #string version
OPSGROUP.version="0.7.0"
OPSGROUP.version="0.7.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@ -2166,6 +2170,27 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
-- Start formation FSM.
Task.formation:Start()
elseif Task.dcstask.id=="PatrolZone" then
---
-- Task patrol zone.
---
-- Parameters.
local zone=Task.dcstask.params.zone --Core.Zone#ZONE
local Coordinate=zone:GetRandomCoordinate()
local Speed=UTILS.KmphToKnots(Task.dcstask.params.speed or self.speedCruise)
local Altitude=Task.dcstask.params.altitude and UTILS.MetersToFeet(Task.dcstask.params.altitude) or nil
-- New waypoint.
if self.isFlightgroup then
FLIGHTGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Altitude)
elseif self.isNavygroup then
ARMYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Formation)
elseif self.isArmygroup then
NAVYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Altitude)
end
else
-- If task is scheduled (not waypoint) set task.
@ -2245,6 +2270,8 @@ function OPSGROUP:onafterTaskCancel(From, Event, To, Task)
if Task.dcstask.id=="Formation" then
Task.formation:Stop()
done=true
elseif Task.dcstask.id=="PatrolZone" then
done=true
elseif stopflag==1 or (not self:IsAlive()) or self:IsDead() or self:IsStopped() then
-- Manual call TaskDone if setting flag to one was not successful.
done=true
@ -2310,6 +2337,11 @@ function OPSGROUP:onafterTaskDone(From, Event, To, Task)
-- Task status done.
Task.status=OPSGROUP.TaskStatus.DONE
-- Restore old ROE.
if Task.backupROE then
self:SwitchROE(Task.backupROE)
end
-- Check if this task was the task of the current mission ==> Mission Done!
local Mission=self:GetMissionByTaskID(Task.id)
@ -2324,6 +2356,11 @@ function OPSGROUP:onafterTaskDone(From, Event, To, Task)
--Mission paused. Do nothing!
end
else
if Task.description=="Engage_Target" then
self:Disengage()
end
self:T(self.lid.."Task Done but NO mission found ==> _CheckGroupDone in 1 sec")
self:_CheckGroupDone(1)
end
@ -2610,7 +2647,7 @@ function OPSGROUP:onafterPauseMission(From, Event, To)
local Task=Mission:GetGroupWaypointTask(self)
-- Debug message.
self:I(self.lid..string.format("Pausing current mission %s. Task=%s", tostring(Mission.name), tostring(Task and Task.description or "WTF")))
self:T(self.lid..string.format("Pausing current mission %s. Task=%s", tostring(Mission.name), tostring(Task and Task.description or "WTF")))
-- Cancelling the mission is actually cancelling the current task.
self:TaskCancel(Task)
@ -2629,7 +2666,8 @@ end
-- @param #string To To state.
function OPSGROUP:onafterUnpauseMission(From, Event, To)
self:I(self.lid..string.format("Unpausing mission"))
-- Debug info.
self:T(self.lid..string.format("Unpausing mission"))
if self.missionpaused then
@ -2856,6 +2894,8 @@ function OPSGROUP:RouteToMission(mission, delay)
end
elseif mission.type==AUFTRAG.Type.PATROLZONE then
end
local formation=nil
@ -2985,6 +3025,30 @@ end
-- @param #OPSGROUP.Waypoint Waypoint Waypoint data passed.
function OPSGROUP:onafterPassingWaypoint(From, Event, To, Waypoint)
-- Get the current task.
local task=self:GetTaskCurrent()
if task and task.dcstask.id=="PatrolZone" then
-- Remove old waypoint.
self:RemoveWaypointByID(Waypoint.uid)
local zone=task.dcstask.params.zone --Core.Zone#ZONE
local Coordinate=zone:GetRandomCoordinate()
local Speed=UTILS.KmphToKnots(task.dcstask.params.speed or self.speedCruise)
local Altitude=task.dcstask.params.altitude and UTILS.MetersToFeet(task.dcstask.params.altitude) or nil
if self.isFlightgroup then
FLIGHTGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Altitude)
elseif self.isNavygroup then
ARMYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Formation)
elseif self.isArmygroup then
NAVYGROUP.AddWaypoint(self, Coordinate, Speed, AfterWaypointWithID, Altitude)
end
else
-- Apply tasks of this waypoint.
local ntasks=self:_SetWaypointTasks(Waypoint)
@ -3012,6 +3076,8 @@ function OPSGROUP:onafterPassingWaypoint(From, Event, To, Waypoint)
tostring(wpindex), #self.waypoints, Waypoint.uid, tostring(self.passedfinalwp), tostring(Waypoint.detour), tostring(Waypoint.astar))
self:T(self.lid..text)
end
end
--- Set tasks at this waypoint
@ -4176,7 +4242,6 @@ function OPSGROUP:_CheckAmmoStatus()
self.outofAmmo=false
end
if ammo.Total==0 and not self.outofAmmo then
env.info("FF out of ammo")
self.outofAmmo=true
self:OutOfAmmo()
end
@ -4732,6 +4797,8 @@ function OPSGROUP:SwitchAlarmstate(alarmstate)
if self:IsAlive() or self:IsInUtero() then
if self.isArmygroup or self.isNavygroup then
self.option.Alarm=alarmstate or self.optionDefault.Alarm
if self:IsInUtero() then
@ -4753,6 +4820,8 @@ function OPSGROUP:SwitchAlarmstate(alarmstate)
self:T(self.lid..string.format("Setting current Alarm State=%d (0=Auto, 1=Green, 2=Red)", self.option.Alarm))
end
end
else
self:E(self.lid.."WARNING: Cannot switch Alarm State! Group is not alive.")
end

View File

@ -72,6 +72,7 @@ TARGET = {
-- @field #string SCENERY Target is a SCENERY object.
-- @field #string COORDINATE Target is a COORDINATE.
-- @field #string AIRBASE Target is an AIRBASE.
-- @field #string ZONE Target is a ZONE object.
TARGET.ObjectType={
GROUP="Group",
UNIT="Unit",
@ -79,6 +80,7 @@ TARGET.ObjectType={
SCENERY="Scenery",
COORDINATE="Coordinate",
AIRBASE="Airbase",
ZONE="Zone",
}
@ -89,12 +91,14 @@ TARGET.ObjectType={
-- @field #string NAVAL
-- @field #string AIRBASE
-- @field #string COORDINATE
-- @field #string ZONE
TARGET.Category={
AIRCRAFT="Aircraft",
GROUND="Ground",
NAVAL="Naval",
AIRBASE="Airbase",
COORDINATE="Coordinate",
ZONE="Zone",
}
--- Object status.
@ -124,7 +128,7 @@ _TARGETID=0
--- TARGET class version.
-- @field #string version
TARGET.version="0.3.0"
TARGET.version="0.3.1"
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list
@ -658,12 +662,12 @@ function TARGET:_AddObject(Object)
elseif Object:IsInstanceOf("ZONE_BASE") then
local zone=Object --Core.Zone#ZONE_BASE
Object=zone:GetCoordinate()
Object=zone --:GetCoordinate()
target.Type=TARGET.ObjectType.COORDINATE
target.Type=TARGET.ObjectType.ZONE
target.Name=zone:GetName()
target.Coordinate=Object
target.Coordinate=zone:GetCoordinate()
target.Life0=1
target.Life=1
@ -774,6 +778,12 @@ function TARGET:GetTargetLife(Target)
return 1
elseif Target.Type==TARGET.ObjectType.ZONE then
return 1
else
self:E("ERROR: unknown target object type in GetTargetLife!")
end
end
@ -865,6 +875,13 @@ function TARGET:GetTargetVec3(Target)
local vec3={x=object.x, y=object.y, z=object.z}
return vec3
elseif Target.Type==TARGET.ObjectType.ZONE then
local object=Target.Object --Core.Zone#ZONE
local vec3=object:GetVec3()
return vec3
end
self:E(self.lid.."ERROR: Unknown TARGET type! Cannot get Vec3")
@ -1033,6 +1050,12 @@ function TARGET:GetTargetCategory(Target)
return TARGET.Category.COORDINATE
elseif Target.Type==TARGET.ObjectType.ZONE then
return TARGET.Category.ZONE
else
self:E("ERROR: unknown target category!")
end
return category
@ -1141,6 +1164,10 @@ function TARGET:CountObjectives(Target)
-- No target we can check!
elseif Target.Type==TARGET.ObjectType.ZONE then
-- No target we can check!
else
self:E(self.lid.."ERROR: Unknown target type! Cannot count targets")
end