Capture Zone
This commit is contained in:
Frank 2022-12-30 02:44:16 +01:00
parent 30e6542887
commit 3011d625b2
6 changed files with 436 additions and 36 deletions

View File

@ -1919,6 +1919,41 @@ do -- SET_GROUP
end end
end end
--- Get the closest group of the set with respect to a given reference coordinate. Optionally, only groups of given coalitions are considered in the search.
-- @param #SET_GROUP self
-- @param Core.Point#COORDINATE Coordinate Reference Coordinate from which the closest group is determined.
-- @return Wrapper.Group#GROUP The closest group (if any).
-- @return #number Distance in meters to the closest group.
function SET_GROUP:GetClosestGroup(Coordinate, Coalitions)
local Set = self:GetSet()
local dmin=math.huge
local gmin=nil
for GroupID, GroupData in pairs( Set ) do -- For each GROUP in SET_GROUP
local group=GroupData --Wrapper.Group#GROUP
if Coalitions==nil or UTILS.IsAnyInTable(Coalitions, group:GetCoalition()) then
local coord=group:GetCoord()
-- Distance between ref. coordinate and group coordinate.
local d=UTILS.VecDist3D(Coordinate, coord)
if d<dmin then
dmin=d
gmin=group
end
end
end
return gmin, dmin
end
end end
do -- SET_UNIT do -- SET_UNIT

View File

@ -721,6 +721,32 @@ function ARMYGROUP:Status()
end end
end end
-- Get current mission (if any).
local mission=self:GetMissionCurrent()
-- If mission, check if DCS task needs to be updated.
if mission and mission.updateDCSTask and mission:GetGroupStatus(self)==AUFTRAG.GroupStatus.EXECUTING then
if mission.type==AUFTRAG.Type.CAPTUREZONE then
-- Get task.
local Task=self:GetTaskByID(mission.auftragsnummer)
local opszone=Task.target --Ops.OpsZone#OPSZONE
env.info(string.format("FF Opszone %s owner=%s, engaging=%s", opszone:GetName(), opszone:GetOwnerName(), tostring(self:IsEngaging())))
-- Update task: Engage or get new zone.
self:_UpdateTask(Task, mission)
end
end
else else
-- Check damage of elements and group. -- Check damage of elements and group.
self:_CheckDamage() self:_CheckDamage()
@ -1721,10 +1747,11 @@ function ARMYGROUP:onbeforeEngageTarget(From, Event, To, Target, Speed, Formatio
return false return false
end end
-- Pause current mission. -- Get current mission.
local mission=self:GetMissionCurrent() local mission=self:GetMissionCurrent()
if mission and mission.type~=AUFTRAG.Type.GROUNDATTACK then -- Pause current mission unless it uses the EngageTarget command.
if mission and mission.type~=AUFTRAG.Type.GROUNDATTACK and mission.type~=AUFTRAG.Type.CAPTUREZONE then
self:T(self.lid.."Engage command but have current mission ==> Pausing mission!") self:T(self.lid.."Engage command but have current mission ==> Pausing mission!")
self:PauseMission() self:PauseMission()
dt=-0.1 dt=-0.1
@ -1804,8 +1831,8 @@ function ARMYGROUP:_UpdateEngageTarget()
-- Distance to last known position of target. -- Distance to last known position of target.
local dist=UTILS.VecDist3D(vec3, self.engage.Coordinate:GetVec3()) local dist=UTILS.VecDist3D(vec3, self.engage.Coordinate:GetVec3())
-- Check if target moved more than 100 meters. -- Check if target moved more than 100 meters or we do not have line of sight.
if dist>100 then if dist>100 or not self:HasLoS(self.engage.Target:GetCoordinate()) then
--env.info("FF Update Engage Target Moved "..self.engage.Target:GetName()) --env.info("FF Update Engage Target Moved "..self.engage.Target:GetName())

View File

@ -422,7 +422,8 @@ _AUFTRAGSNR=0
-- @field #string AIRDEFENSE Air defense. -- @field #string AIRDEFENSE Air defense.
-- @field #string EWR Early Warning Radar. -- @field #string EWR Early Warning Radar.
-- @field #string RECOVERYTANKER Recovery tanker. -- @field #string RECOVERYTANKER Recovery tanker.
-- @filed #string REARMING Rearming mission. -- @field #string REARMING Rearming mission.
-- @field #string CAPTUREZONE Capture zone mission.
-- @field #string NOTHING Nothing. -- @field #string NOTHING Nothing.
AUFTRAG.Type={ AUFTRAG.Type={
ANTISHIP="Anti Ship", ANTISHIP="Anti Ship",
@ -465,6 +466,7 @@ AUFTRAG.Type={
EWR="Early Warning Radar", EWR="Early Warning Radar",
RECOVERYTANKER="Recovery Tanker", RECOVERYTANKER="Recovery Tanker",
REARMING="Rearming", REARMING="Rearming",
CAPTUREZONE="Capture Zone",
NOTHING="Nothing", NOTHING="Nothing",
} }
@ -487,6 +489,7 @@ AUFTRAG.Type={
-- @field #string EWR Early Warning Radar. -- @field #string EWR Early Warning Radar.
-- @field #string RECOVERYTANKER Recovery tanker. -- @field #string RECOVERYTANKER Recovery tanker.
-- @field #string REARMING Rearming. -- @field #string REARMING Rearming.
-- @field #string CAPTUREZONE Capture OPS zone.
-- @field #string NOTHING Nothing. -- @field #string NOTHING Nothing.
AUFTRAG.SpecialTask={ AUFTRAG.SpecialTask={
FORMATION="Formation", FORMATION="Formation",
@ -507,6 +510,7 @@ AUFTRAG.SpecialTask={
EWR="Early Warning Radar", EWR="Early Warning Radar",
RECOVERYTANKER="Recovery Tanker", RECOVERYTANKER="Recovery Tanker",
REARMING="Rearming", REARMING="Rearming",
CAPTUREZONE="Capture Zone",
NOTHING="Nothing", NOTHING="Nothing",
} }
@ -1964,6 +1968,51 @@ function AUFTRAG:NewPATROLZONE(Zone, Speed, Altitude, Formation)
return mission return mission
end end
--- **[AIR, GROUND, NAVAL]** Create a CAPTUREZONE mission. Group(s) will go to the zone and patrol it randomly.
-- @param #AUFTRAG self
-- @param Ops.OpsZone#OPSZONE OpsZone The OPS zone to capture.
-- @param #number Coalition The coalition which should capture the zone for the mission to be successful.
-- @param #number Speed Speed in knots.
-- @param #number Altitude Altitude in feet. Only for airborne units. Default 2000 feet ASL.
-- @param #string Formation Formation used by ground units during patrol. Default "Off Road".
-- @return #AUFTRAG self
function AUFTRAG:NewCAPTUREZONE(OpsZone, Coalition, Speed, Altitude, Formation)
local mission=AUFTRAG:New(AUFTRAG.Type.CAPTUREZONE)
mission:_TargetFromObject(OpsZone)
mission.coalition=Coalition
mission.missionTask=mission:GetMissionTaskforMissionType(AUFTRAG.Type.CAPTUREZONE)
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.categories={AUFTRAG.Category.ALL}
mission.DCStask=mission:GetDCSMissionTask()
mission.updateDCSTask=true
local params={}
params.formation=Formation or "Off Road"
params.zone=mission:GetObjective()
params.altitude=mission.missionAltitude
params.speed=mission.missionSpeed
mission.DCStask.params=params
return mission
end
--- **[OBSOLETE]** Create a ARMORATTACK mission. --- **[OBSOLETE]** Create a ARMORATTACK mission.
-- ** Note that this is actually creating a GROUNDATTACK mission!** -- ** Note that this is actually creating a GROUNDATTACK mission!**
@ -4947,8 +4996,11 @@ function AUFTRAG:CountMissionTargets()
local N=0 local N=0
-- Count specific coalitions.
local Coalitions=self.coalition and UTILS.GetCoalitionEnemy(self.coalition, true) or nil
if self.engageTarget then if self.engageTarget then
N=self.engageTarget:CountTargets() N=self.engageTarget:CountTargets(Coalitions)
end end
return N return N
@ -5013,9 +5065,13 @@ end
--- Get mission objective object. Could be many things depending on the mission type. --- Get mission objective object. Could be many things depending on the mission type.
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @param Core.Point#COORDINATE RefCoordinate (Optional) Reference coordinate from which the closest target is determined.
-- @param #table Coalitions (Optional) Only consider targets of the given coalition(s).
-- @return Wrapper.Positionable#POSITIONABLE The target object. Could be many things. -- @return Wrapper.Positionable#POSITIONABLE The target object. Could be many things.
function AUFTRAG:GetObjective() function AUFTRAG:GetObjective(RefCoordinate, Coalitions)
local objective=self:GetTargetData():GetObject()
local objective=self:GetTargetData():GetObject(RefCoordinate, Coalitions)
return objective return objective
end end
@ -5754,6 +5810,22 @@ function AUFTRAG:GetDCSMissionTask()
table.insert(DCStasks, DCStask) table.insert(DCStasks, DCStask)
elseif self.type==AUFTRAG.Type.CAPTUREZONE then
--------------------------
-- CAPTURE ZONE Mission --
--------------------------
local DCStask={}
DCStask.id=AUFTRAG.SpecialTask.CAPTUREZONE
-- We create a "fake" DCS task and pass the parameters to the FLIGHTGROUP.
local param={}
DCStask.params=param
table.insert(DCStasks, DCStask)
elseif self.type==AUFTRAG.Type.CASENHANCED then elseif self.type==AUFTRAG.Type.CASENHANCED then
------------------------- -------------------------

View File

@ -335,6 +335,7 @@ OPSGROUP.TaskType={
-- @field #number waypoint Waypoint index if task is a waypoint task. -- @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 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. -- @field #number backupROE Rules of engagement that are restored once the task is over.
-- @field Ops.Target#TARGET target Target object.
--- Option data. --- Option data.
-- @type OPSGROUP.Option -- @type OPSGROUP.Option
@ -4091,12 +4092,13 @@ function OPSGROUP:onafterTaskExecute(From, Event, To, Task)
end end
--- Push task. --- Update (DCS) task.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param Ops.OpsGroup#OPSGROUP.Task Task The task. -- @param Ops.OpsGroup#OPSGROUP.Task Task The task.
-- @param Ops.Auftrag#AUFTRAG Mission The mission.
function OPSGROUP:_UpdateTask(Task, Mission) function OPSGROUP:_UpdateTask(Task, Mission)
local Mission=Mission or self:GetMissionByTaskID(self.taskcurrent) Mission=Mission or self:GetMissionByTaskID(self.taskcurrent)
if Task.dcstask.id==AUFTRAG.SpecialTask.FORMATION then if Task.dcstask.id==AUFTRAG.SpecialTask.FORMATION then
@ -4379,6 +4381,64 @@ function OPSGROUP:_UpdateTask(Task, Mission)
wp.missionUID=Mission and Mission.auftragsnummer or nil wp.missionUID=Mission and Mission.auftragsnummer or nil
elseif Task.dcstask.id==AUFTRAG.SpecialTask.CAPTUREZONE then
---
-- Task "CaptureZone" Mission.
---
env.info("FF Update Task Capture zone")
-- Find the closest enemy group and engage!
-- Not enganging already.
if self:IsEngaging() then
self:T(self.lid..string.format("Engaging currently!"))
else
local Coalitions=UTILS.GetCoalitionEnemy(self:GetCoalition(), false)
local zoneCurr=Task.target --Ops.OpsZone#OPSZONE
if zoneCurr then
self:T(self.lid..string.format("Current target zone=%s", zoneCurr:GetName()))
if zoneCurr:GetOwner()==self:GetCoalition() then
-- Current zone captured ==> Find next zone or call it a day!
self:T(self.lid..string.format("Zone %s captured ==> Task DONE!", zoneCurr:GetName()))
self:TaskDone(Task)
else
-- Current zone NOT captured yet ==> Find Target
if Mission:GetGroupStatus(self)==AUFTRAG.GroupStatus.EXECUTING then
-- Get closest target.
local targetgroup=zoneCurr:GetScannedGroupSet():GetClosestGroup(self.coordinate, Coalitions)
if targetgroup then
self:EngageTarget(targetgroup)
else
-- Error Message.
self:E(self.lid..string.format("ERROR: Current zone not captured but no target group could be found. This should NOT happen!"))
end
end
end
else
self:T(self.lid..string.format("NO Current target zone=%s"))
end
end
else else
-- If task is scheduled (not waypoint) set task. -- If task is scheduled (not waypoint) set task.
@ -4662,9 +4722,18 @@ function OPSGROUP:onafterTaskDone(From, Event, To, Task)
-- Check if mission is paused. -- Check if mission is paused.
if status~=AUFTRAG.GroupStatus.PAUSED then if status~=AUFTRAG.GroupStatus.PAUSED then
--- ---
-- Mission is NOT over ==> trigger done -- Mission is NOT over ==> trigger DONE
--- ---
if Mission.type==AUFTRAG.Type.CAPTUREZONE and Mission:CountMissionTargets()>0 then
env.info("FF task done route to mission 1000")
self:RouteToMission(Mission)
return
end
-- Get egress waypoint uid. -- Get egress waypoint uid.
local EgressUID=Mission:GetGroupEgressWaypointUID(self) local EgressUID=Mission:GetGroupEgressWaypointUID(self)
@ -5496,6 +5565,13 @@ function OPSGROUP:RouteToMission(mission, delay)
surfacetypes={land.SurfaceType.WATER, land.SurfaceType.SHALLOW_WATER} surfacetypes={land.SurfaceType.WATER, land.SurfaceType.SHALLOW_WATER}
end end
-- Get target object.
local targetobject=mission:GetObjective(currentcoord, UTILS.GetCoalitionEnemy(self:GetCoalition(), true))
if targetobject then
self:T(self.lid..string.format("Route to mission target object %s", targetobject:GetName()))
end
-- Get ingress waypoint. -- Get ingress waypoint.
if mission.opstransport and not mission.opstransport:IsCargoDelivered(self.groupname) then if mission.opstransport and not mission.opstransport:IsCargoDelivered(self.groupname) then
@ -5526,7 +5602,7 @@ function OPSGROUP:RouteToMission(mission, delay)
--- ---
-- Get the zone. -- Get the zone.
targetzone=mission.engageTarget:GetObject() --Core.Zone#ZONE targetzone=targetobject --Core.Zone#ZONE
-- Random coordinate. -- Random coordinate.
waypointcoord=targetzone:GetRandomCoordinate(nil , nil, surfacetypes) waypointcoord=targetzone:GetRandomCoordinate(nil , nil, surfacetypes)
@ -5545,7 +5621,7 @@ function OPSGROUP:RouteToMission(mission, delay)
--- ---
-- Get the zone. -- Get the zone.
targetzone=mission.engageTarget:GetObject() --Core.Zone#ZONE targetzone=targetobject --Core.Zone#ZONE
-- Random coordinate. -- Random coordinate.
waypointcoord=targetzone:GetRandomCoordinate(nil , nil, surfacetypes) waypointcoord=targetzone:GetRandomCoordinate(nil , nil, surfacetypes)
@ -5555,7 +5631,8 @@ function OPSGROUP:RouteToMission(mission, delay)
-- Hover -- Hover
--- ---
local zone=mission.engageTarget:GetObject() --Core.Zone#ZONE local zone=targetobject --Core.Zone#ZONE
waypointcoord=zone:GetCoordinate() waypointcoord=zone:GetCoordinate()
elseif mission.type==AUFTRAG.Type.RELOCATECOHORT then elseif mission.type==AUFTRAG.Type.RELOCATECOHORT then
@ -5581,6 +5658,15 @@ function OPSGROUP:RouteToMission(mission, delay)
waypointcoord=currentcoord:GetIntermediateCoordinate(ToCoordinate, 0.05) waypointcoord=currentcoord:GetIntermediateCoordinate(ToCoordinate, 0.05)
end end
elseif mission.type==AUFTRAG.Type.CAPTUREZONE then
-- Get the zone.
targetzone=targetobject:GetZone()
-- Random coordinate.
waypointcoord=targetzone:GetRandomCoordinate(nil , nil, surfacetypes)
else else
--- ---
-- Default case -- Default case
@ -5707,6 +5793,8 @@ function OPSGROUP:RouteToMission(mission, delay)
local waypointtask=self:AddTaskWaypoint(mission.DCStask, waypoint, mission.name, mission.prio, mission.duration) local waypointtask=self:AddTaskWaypoint(mission.DCStask, waypoint, mission.name, mission.prio, mission.duration)
waypointtask.ismission=true waypointtask.ismission=true
waypointtask.target=targetobject
-- Set waypoint task. -- Set waypoint task.
mission:SetGroupWaypointTask(self, waypointtask) mission:SetGroupWaypointTask(self, waypointtask)

View File

@ -84,6 +84,7 @@ TARGET = {
-- @field #string COORDINATE Target is a COORDINATE. -- @field #string COORDINATE Target is a COORDINATE.
-- @field #string AIRBASE Target is an AIRBASE. -- @field #string AIRBASE Target is an AIRBASE.
-- @field #string ZONE Target is a ZONE object. -- @field #string ZONE Target is a ZONE object.
-- @field #string OPSZONE Target is an OPSZONE object.
TARGET.ObjectType={ TARGET.ObjectType={
GROUP="Group", GROUP="Group",
UNIT="Unit", UNIT="Unit",
@ -92,6 +93,7 @@ TARGET.ObjectType={
COORDINATE="Coordinate", COORDINATE="Coordinate",
AIRBASE="Airbase", AIRBASE="Airbase",
ZONE="Zone", ZONE="Zone",
OPSZONE="OpsZone"
} }
@ -312,12 +314,18 @@ end
-- * SET_SCENERY -- * SET_SCENERY
-- * SET_OPSGROUP -- * SET_OPSGROUP
-- * SET_ZONE -- * SET_ZONE
-- * SET_OPSZONE
-- --
-- @param #TARGET self -- @param #TARGET self
-- @param Wrapper.Positionable#POSITIONABLE Object The target UNIT, GROUP, STATIC, SCENERY, AIRBASE, COORDINATE, ZONE, SET_GROUP, SET_UNIT, SET_STATIC, SET_SCENERY, SET_ZONE -- @param Wrapper.Positionable#POSITIONABLE Object The target UNIT, GROUP, STATIC, SCENERY, AIRBASE, COORDINATE, ZONE, SET_GROUP, SET_UNIT, SET_STATIC, SET_SCENERY, SET_ZONE
function TARGET:AddObject(Object) function TARGET:AddObject(Object)
if Object:IsInstanceOf("SET_GROUP") or Object:IsInstanceOf("SET_UNIT") or Object:IsInstanceOf("SET_STATIC") or Object:IsInstanceOf("SET_SCENERY") or Object:IsInstanceOf("SET_OPSGROUP") then if Object:IsInstanceOf("SET_GROUP") or
Object:IsInstanceOf("SET_UNIT") or
Object:IsInstanceOf("SET_STATIC") or
Object:IsInstanceOf("SET_SCENERY") or
Object:IsInstanceOf("SET_OPSGROUP") or
Object:IsInstanceOf("SET_OPSZONE") then
--- ---
-- Sets -- Sets
@ -982,6 +990,22 @@ function TARGET:_AddObject(Object)
target.Life0=1 target.Life0=1
target.Life=1 target.Life=1
elseif Object:IsInstanceOf("OPSZONE") then
local zone=Object --Ops.OpsZone#OPSZONE
Object=zone
target.Type=TARGET.ObjectType.OPSZONE
target.Name=zone:GetName()
target.Coordinate=zone:GetCoordinate()
target.N0=target.N0+1
target.Life0=1
target.Life=1
else else
self:E(self.lid.."ERROR: Unknown object type!") self:E(self.lid.."ERROR: Unknown object type!")
return nil return nil
@ -1097,7 +1121,7 @@ function TARGET:GetTargetLife(Target)
return 1 return 1
elseif Target.Type==TARGET.ObjectType.ZONE then elseif Target.Type==TARGET.ObjectType.ZONE or Target.Type==TARGET.ObjectType.OPSZONE then
return 1 return 1
@ -1306,6 +1330,13 @@ function TARGET:GetTargetVec3(Target, Average)
local vec3=object:GetVec3() local vec3=object:GetVec3()
return vec3 return vec3
elseif Target.Type==TARGET.ObjectType.OPSZONE then
local object=Target.Object --Ops.OpsZone#OPSZONE
local vec3=object:GetZone():GetVec3()
return vec3
end end
self:E(self.lid.."ERROR: Unknown TARGET type! Cannot get Vec3") self:E(self.lid.."ERROR: Unknown TARGET type! Cannot get Vec3")
@ -1382,7 +1413,7 @@ function TARGET:GetTargetHeading(Target)
-- A coordinate has no heading. Return 0. -- A coordinate has no heading. Return 0.
return 0 return 0
elseif Target.Type==TARGET.ObjectType.ZONE then elseif Target.Type==TARGET.ObjectType.ZONE or Target.Type==TARGET.ObjectType.OPSZONE then
local object=Target.Object --Core.Zone#ZONE local object=Target.Object --Core.Zone#ZONE
@ -1661,6 +1692,10 @@ function TARGET:GetTargetCategory(Target)
return TARGET.Category.ZONE return TARGET.Category.ZONE
elseif Target.Type==TARGET.ObjectType.OPSZONE then
return TARGET.Category.OPSZONE
else else
self:E("ERROR: unknown target category!") self:E("ERROR: unknown target category!")
end end
@ -1669,6 +1704,71 @@ function TARGET:GetTargetCategory(Target)
end end
--- Get coalition of target object. If an object has no coalition (*e.g.* a coordinate) it is returned as neutral.
-- @param #TARGET self
-- @param #TARGET.Object Target Target object.
-- @return #number Coalition number.
function TARGET:GetTargetCoalition(Target)
-- We take neutral for objects that do not have a coalition.
local coal=coalition.side.NEUTRAL
if Target.Type==TARGET.ObjectType.GROUP then
if Target.Object and Target.Object:IsAlive()~=nil then
local object=Target.Object --Wrapper.Group#GROUP
coal=object:GetCoalition()
end
elseif Target.Type==TARGET.ObjectType.UNIT then
if Target.Object and Target.Object:IsAlive()~=nil then
local object=Target.Object --Wrapper.Unit#UNIT
coal=object:GetCoalition()
end
elseif Target.Type==TARGET.ObjectType.STATIC then
local object=Target.Object --Wrapper.Static#STATIC
coal=object:GetCoalition()
elseif Target.Type==TARGET.ObjectType.SCENERY then
-- Scenery has no coalition.
elseif Target.Type==TARGET.ObjectType.AIRBASE then
local object=Target.Object --Wrapper.Airbase#AIRBASE
coal=object:GetCoalition()
elseif Target.Type==TARGET.ObjectType.COORDINATE then
-- Coordinate has no coalition.
elseif Target.Type==TARGET.ObjectType.ZONE then
-- Zone has no coalition.
elseif Target.Type==TARGET.ObjectType.OPSZONE then
local object=Target.Object --Ops.OpsZone#OPSZONE
coal=object:GetOwner()
else
self:E("ERROR: unknown target category!")
end
return coal
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Misc Functions -- Misc Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -1692,14 +1792,45 @@ end
--- Get the first target objective alive. --- Get the first target objective alive.
-- @param #TARGET self -- @param #TARGET self
-- @param Core.Point#COORDINATE RefCoordinate (Optional) Reference coordinate to determine the closest target objective.
-- @param #table Coalitions (Optional) Only consider targets of the given coalition(s).
-- @return #TARGET.Object The target objective. -- @return #TARGET.Object The target objective.
function TARGET:GetObjective() function TARGET:GetObjective(RefCoordinate, Coalitions)
if RefCoordinate then
local dmin=math.huge
local tmin=nil --#TARGET.Object
for _,_target in pairs(self.targets) do
local target=_target --#TARGET.Object
if target.Status~=TARGET.ObjectStatus.DEAD and (Coalitions==nil or UTILS.IsInTable(UTILS.EnsureTable(Coalitions), self:GetTargetCoalition(target))) then
local vec3=self:GetTargetVec3(target)
local d=UTILS.VecDist3D(vec3, RefCoordinate)
if d<dmin then
dmin=d
tmin=target
end
end
for _,_target in pairs(self.targets) do
local target=_target --#TARGET.Object
if target.Status~=TARGET.ObjectStatus.DEAD then
return target
end end
return tmin
else
for _,_target in pairs(self.targets) do
local target=_target --#TARGET.Object
if target.Status~=TARGET.ObjectStatus.DEAD and (Coalitions==nil or UTILS.IsInTable(UTILS.EnsureTable(Coalitions), self:GetTargetCoalition(target))) then
return target
end
end
end end
return nil return nil
@ -1707,10 +1838,13 @@ end
--- Get the first target object alive. --- Get the first target object alive.
-- @param #TARGET self -- @param #TARGET self
-- @param Core.Point#COORDINATE RefCoordinate Reference coordinate to determine the closest target objective.
-- @param #table Coalitions (Optional) Only consider targets of the given coalition(s).
-- @return Wrapper.Positionable#POSITIONABLE The target object or nil. -- @return Wrapper.Positionable#POSITIONABLE The target object or nil.
function TARGET:GetObject() function TARGET:GetObject(RefCoordinate, Coalitions)
local target=self:GetObjective(RefCoordinate, Coalitions)
local target=self:GetObjective()
if target then if target then
return target.Object return target.Object
end end
@ -1721,8 +1855,9 @@ end
--- Count alive objects. --- Count alive objects.
-- @param #TARGET self -- @param #TARGET self
-- @param #TARGET.Object Target Target objective. -- @param #TARGET.Object Target Target objective.
-- @param #table Coalitions (Optional) Only count targets of the given coalition(s).
-- @return #number Number of alive target objects. -- @return #number Number of alive target objects.
function TARGET:CountObjectives(Target) function TARGET:CountObjectives(Target, Coalitions)
local N=0 local N=0
@ -1735,7 +1870,9 @@ function TARGET:CountObjectives(Target)
for _,_unit in pairs(units or {}) do for _,_unit in pairs(units or {}) do
local unit=_unit --Wrapper.Unit#UNIT local unit=_unit --Wrapper.Unit#UNIT
if unit and unit:IsAlive()~=nil and unit:GetLife()>1 then if unit and unit:IsAlive()~=nil and unit:GetLife()>1 then
N=N+1 if Coalitions==nil or UTILS.IsInTable(UTILS.EnsureTable(Coalitions), unit:GetCoalition()) then
N=N+1
end
end end
end end
@ -1744,7 +1881,9 @@ function TARGET:CountObjectives(Target)
local target=Target.Object --Wrapper.Unit#UNIT local target=Target.Object --Wrapper.Unit#UNIT
if target and target:IsAlive()~=nil and target:GetLife()>1 then if target and target:IsAlive()~=nil and target:GetLife()>1 then
N=N+1 if Coalitions==nil or UTILS.IsInTable(Coalitions, target:GetCoalition()) then
N=N+1
end
end end
elseif Target.Type==TARGET.ObjectType.STATIC then elseif Target.Type==TARGET.ObjectType.STATIC then
@ -1752,7 +1891,9 @@ function TARGET:CountObjectives(Target)
local target=Target.Object --Wrapper.Static#STATIC local target=Target.Object --Wrapper.Static#STATIC
if target and target:IsAlive() then if target and target:IsAlive() then
N=N+1 if Coalitions==nil or UTILS.IsInTable(Coalitions, target:GetCoalition()) then
N=N+1
end
end end
elseif Target.Type==TARGET.ObjectType.SCENERY then elseif Target.Type==TARGET.ObjectType.SCENERY then
@ -1763,8 +1904,12 @@ function TARGET:CountObjectives(Target)
elseif Target.Type==TARGET.ObjectType.AIRBASE then elseif Target.Type==TARGET.ObjectType.AIRBASE then
local target=Target.Object --Wrapper.Airbase#AIRBASE
if Target.Status==TARGET.ObjectStatus.ALIVE then if Target.Status==TARGET.ObjectStatus.ALIVE then
N=N+1 if Coalitions==nil or UTILS.IsInTable(Coalitions, target:GetCoalition()) then
N=N+1
end
end end
elseif Target.Type==TARGET.ObjectType.COORDINATE then elseif Target.Type==TARGET.ObjectType.COORDINATE then
@ -1775,6 +1920,14 @@ function TARGET:CountObjectives(Target)
-- No target we can check! -- No target we can check!
elseif Target.Type==TARGET.ObjectType.OPSZONE then
local target=Target.Object --Ops.OpsZone#OPSZONE
if Coalitions==nil or UTILS.IsInTable(Coalitions, target:GetOwner()) then
N=N+1
end
else else
self:E(self.lid.."ERROR: Unknown target type! Cannot count targets") self:E(self.lid.."ERROR: Unknown target type! Cannot count targets")
end end
@ -1784,15 +1937,16 @@ end
--- Count alive targets. --- Count alive targets.
-- @param #TARGET self -- @param #TARGET self
-- @param #table Coalitions (Optional) Only count targets of the given coalition(s).
-- @return #number Number of alive target objects. -- @return #number Number of alive target objects.
function TARGET:CountTargets() function TARGET:CountTargets(Coalitions)
local N=0 local N=0
for _,_target in pairs(self.targets) do for _,_target in pairs(self.targets) do
local Target=_target --#TARGET.Object local Target=_target --#TARGET.Object
N=N+self:CountObjectives(Target) N=N+self:CountObjectives(Target, Coalitions)
end end

View File

@ -1061,8 +1061,8 @@ function UTILS.Vec2Norm(a)
end end
--- Calculate the distance between two 2D vectors. --- Calculate the distance between two 2D vectors.
-- @param DCS#Vec2 a Vector in 3D with x, y components. -- @param DCS#Vec2 a Vector in 2D with x, y components.
-- @param DCS#Vec2 b Vector in 3D with x, y components. -- @param DCS#Vec2 b Vector in 2D with x, y components.
-- @return #number Distance between the vectors. -- @return #number Distance between the vectors.
function UTILS.VecDist2D(a, b) function UTILS.VecDist2D(a, b)
@ -1446,6 +1446,30 @@ function UTILS.GetCoalitionName(Coalition)
end end
--- Get the enemy coalition for a given coalition.
-- @param #number Coalition The coalition ID.
-- @param #boolean Neutral Include neutral as enemy.
-- @return #table Enemy coalition table.
function UTILS.GetCoalitionEnemy(Coalition, Neutral)
local Coalitions={}
if Coalition then
if Coalition==coalition.side.RED then
Coalitions={coalition.side.BLUE}
elseif Coalition==coalition.side.BLUE then
Coalitions={coalition.side.RED}
elseif Coalition==coalition.side.NEUTRAL then
Coalitions={coalition.side.RED, coalition.side.BLUE}
end
end
if Neutral then
table.insert(Coalitions, coalition.side.NEUTRAL)
end
return Coalitions
end
--- Get the modulation name from its numerical value. --- Get the modulation name from its numerical value.
-- @param #number Modulation The modulation enumerator number. Can be either 0 or 1. -- @param #number Modulation The modulation enumerator number. Can be either 0 or 1.
-- @return #string The modulation name, i.e. "AM"=0 or "FM"=1. Anything else will return "Unknown". -- @return #string The modulation name, i.e. "AM"=0 or "FM"=1. Anything else will return "Unknown".