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

OPS
This commit is contained in:
Frank 2020-11-16 00:02:20 +01:00 committed by GitHub
commit ec3f43c69f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 559 additions and 68 deletions

View File

@ -744,7 +744,7 @@ do -- COORDINATE
-- @return #string MGRS coordinates. -- @return #string MGRS coordinates.
function COORDINATE:GetName() function COORDINATE:GetName()
local name=self:ToStringMGRS() local name=self:ToStringMGRS()
return rname return name
end end
--- Return velocity text of the COORDINATE. --- Return velocity text of the COORDINATE.
@ -1751,9 +1751,9 @@ do -- COORDINATE
self:F2( { ExplosionIntensity } ) self:F2( { ExplosionIntensity } )
ExplosionIntensity=ExplosionIntensity or 100 ExplosionIntensity=ExplosionIntensity or 100
if Delay and Delay>0 then if Delay and Delay>0 then
SCHEDULER:New(nil, self.Explosion, {self,ExplosionIntensity}, Delay) self:ScheduleOnce(Delay, self.Explosion, self, ExplosionIntensity)
else else
trigger.action.explosion( self:GetVec3(), ExplosionIntensity ) trigger.action.explosion(self:GetVec3(), ExplosionIntensity)
end end
return self return self
end end

View File

@ -817,6 +817,32 @@ function ZONE_RADIUS:GetScannedSetUnit()
return SetUnit return SetUnit
end end
--- Get a set of scanned units.
-- @param #ZONE_RADIUS self
-- @return Core.Set#SET_GROUP Set of groups.
function ZONE_RADIUS:GetScannedSetGroup()
self.ScanSetGroup=self.ScanSetGroup or SET_GROUP:New() --Core.Set#SET_GROUP
self.ScanSetGroup.Set={}
if self.ScanData then
for ObjectID, UnitObject in pairs( self.ScanData.Units ) do
local UnitObject = UnitObject -- DCS#Unit
if UnitObject:isExist() then
local FoundUnit=UNIT:FindByName(UnitObject:getName())
if FoundUnit then
local group=FoundUnit:GetGroup()
self.ScanSetGroup:AddGroup(group)
end
end
end
end
return self.ScanSetGroup
end
--- Count the number of different coalitions inside the zone. --- Count the number of different coalitions inside the zone.
-- @param #ZONE_RADIUS self -- @param #ZONE_RADIUS self

View File

@ -890,12 +890,14 @@ do -- ZONE_CAPTURE_COALITION
end end
-- Status text. -- Status text.
local text=string.format("CAPTURE ZONE %s: Owner=%s (Previous=%s): #blue=%d, #red=%d, Status %s", self:GetZoneName(), self:GetCoalitionName(), UTILS.GetCoalitionName(self:GetPreviousCoalition()), nBlue, nRed, State) if false then
local NewState = self:GetState() local text=string.format("CAPTURE ZONE %s: Owner=%s (Previous=%s): #blue=%d, #red=%d, Status %s", self:GetZoneName(), self:GetCoalitionName(), UTILS.GetCoalitionName(self:GetPreviousCoalition()), nBlue, nRed, State)
if NewState~=State then local NewState = self:GetState()
text=text..string.format(" --> %s", NewState) if NewState~=State then
text=text..string.format(" --> %s", NewState)
end
self:I(text)
end end
self:I(text)
end end

View File

@ -33,6 +33,9 @@
-- @field #boolean adinfinitum Resume route at first waypoint when final waypoint is reached. -- @field #boolean adinfinitum Resume route at first waypoint when final waypoint is reached.
-- @field #boolean formationPerma Formation that is used permanently and overrules waypoint formations. -- @field #boolean formationPerma Formation that is used permanently and overrules waypoint formations.
-- @field #boolean isMobile If true, group is mobile. -- @field #boolean isMobile If true, group is mobile.
-- @field #ARMYGROUP.Target engage Engage target.
-- @field #boolean retreatOnOutOfAmmo If true, the group will automatically retreat when out of ammo. Needs a retreat zone!
-- @field Core.Set#SET_ZONE retreatZones Set of retreat zones.
-- @extends Ops.OpsGroup#OPSGROUP -- @extends Ops.OpsGroup#OPSGROUP
--- *Your soul may belong to Jesus, but your ass belongs to the marines.* -- Eugene B. Sledge --- *Your soul may belong to Jesus, but your ass belongs to the marines.* -- Eugene B. Sledge
@ -49,6 +52,7 @@
ARMYGROUP = { ARMYGROUP = {
ClassName = "ARMYGROUP", ClassName = "ARMYGROUP",
formationPerma = nil, formationPerma = nil,
engage = {},
} }
--- Army group element. --- Army group element.
@ -61,14 +65,20 @@ ARMYGROUP = {
-- @field #number width Width of element in meters. -- @field #number width Width of element in meters.
-- @field #number height Height of element in meters. -- @field #number height Height of element in meters.
--- Target
-- @type ARMYGROUP.Target
-- @field Ops.Target#TARGET Target The target.
-- @field Core.Point#COORDINATE Coordinate Last known coordinate of the target.
--- Army Group version. --- Army Group version.
-- @field #string version -- @field #string version
ARMYGROUP.version="0.3.0" ARMYGROUP.version="0.4.0"
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO list -- TODO list
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- TODO: Retreat.
-- TODO: Suppression of fire. -- TODO: Suppression of fire.
-- TODO: Check if group is mobile. -- TODO: Check if group is mobile.
-- TODO: F10 menu. -- TODO: F10 menu.
@ -95,6 +105,7 @@ function ARMYGROUP:New(Group)
self:SetDefaultAlarmstate() self:SetDefaultAlarmstate()
self:SetDetection() self:SetDetection()
self:SetPatrolAdInfinitum(false) self:SetPatrolAdInfinitum(false)
self:SetRetreatZones()
-- Add FSM transitions. -- Add FSM transitions.
-- From State --> Event --> To State -- From State --> Event --> To State
@ -104,6 +115,14 @@ function ARMYGROUP:New(Group)
self:AddTransition("*", "Detour", "OnDetour") -- Make a detour to a coordinate and resume route afterwards. self:AddTransition("*", "Detour", "OnDetour") -- Make a detour to a coordinate and resume route afterwards.
self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate. self:AddTransition("OnDetour", "DetourReached", "Cruising") -- Group reached the detour coordinate.
self:AddTransition("*", "Retreat", "Retreating") --
self:AddTransition("Retreating", "Retreated", "Retreated") --
self:AddTransition("Cruising", "EngageTarget", "Engaging") -- Engage a target
self:AddTransition("Holding", "EngageTarget", "Engaging") -- Engage a target
self:AddTransition("OnDetour", "EngageTarget", "Engaging") -- Engage a target
self:AddTransition("Engaging", "Disengage", "Cruising") -- Engage a target
self:AddTransition("*", "Rearm", "Rearm") -- Group is send to a coordinate and waits until ammo is refilled. self:AddTransition("*", "Rearm", "Rearm") -- Group is send to a coordinate and waits until ammo is refilled.
self:AddTransition("Rearm", "Rearming", "Rearming") -- Group has arrived at the rearming coodinate and is waiting to be fully rearmed. self:AddTransition("Rearm", "Rearming", "Rearming") -- Group has arrived at the rearming coodinate and is waiting to be fully rearmed.
self:AddTransition("Rearming", "Rearmed", "Cruising") -- Group was rearmed. self:AddTransition("Rearming", "Rearmed", "Cruising") -- Group was rearmed.
@ -244,6 +263,24 @@ function ARMYGROUP:AddTaskAttackGroup(TargetGroup, WeaponExpend, WeaponType, Clo
return task return task
end end
--- Define a set of possible retreat zones.
-- @param #ARMYGROUP self
-- @param Core.Set#SET_ZONE RetreatZoneSet The retreat zone set. Default is an empty set.
-- @return #ARMYGROUP self
function ARMYGROUP:SetRetreatZones(RetreatZoneSet)
self.retreatZones=RetreatZoneSet or SET_ZONE:New()
return self
end
--- Add a zone to the retreat zone set.
-- @param #ARMYGROUP self
-- @param Core.Zone#ZONE_BASE RetreatZone The retreat zone.
-- @return #ARMYGROUP self
function ARMYGROUP:AddRetreatZone(RetreatZone)
self.retreatZones:AddZone(RetreatZone)
return self
end
--- Check if the group is currently holding its positon. --- Check if the group is currently holding its positon.
-- @param #ARMYGROUP self -- @param #ARMYGROUP self
-- @return #boolean If true, group was ordered to hold. -- @return #boolean If true, group was ordered to hold.
@ -265,6 +302,20 @@ function ARMYGROUP:IsOnDetour()
return self:Is("OnDetour") return self:Is("OnDetour")
end end
--- Check if the group is ready for combat. I.e. not reaming, retreating, retreated, out of ammo or engaging.
-- @param #ARMYGROUP self
-- @return #boolean If true, group is on a combat ready.
function ARMYGROUP:IsCombatReady()
local combatready=true
if self:IsRearming() or self:IsRetreating() or self.outofAmmo or self:IsEngaging() or self:is("Retreated") or self:IsDead() or self:IsStopped() or self:IsInUtero() then
combatready=false
end
return combatready
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Status -- Status
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -311,6 +362,14 @@ function ARMYGROUP:onafterStatus(From, Event, To)
-- Check if group got stuck. -- Check if group got stuck.
self:_CheckStuck() self:_CheckStuck()
-- Check damage of elements and group.
self:_CheckDamage()
-- Update engagement.
if self:IsEngaging() then
self:_UpdateEngageTarget()
end
if self.verbose>=1 then if self.verbose>=1 then
-- Get number of tasks and missions. -- Get number of tasks and missions.
@ -322,10 +381,11 @@ function ARMYGROUP:onafterStatus(From, Event, To)
local speed=UTILS.MpsToKnots(self.velocity) local speed=UTILS.MpsToKnots(self.velocity)
local speedEx=UTILS.MpsToKnots(self:GetExpectedSpeed()) local speedEx=UTILS.MpsToKnots(self:GetExpectedSpeed())
local formation=self.option.Formation or "unknown" local formation=self.option.Formation or "unknown"
local ammo=self:GetAmmoTot()
-- Info text. -- Info text.
local text=string.format("%s [ROE-AS=%d-%d T/M=%d/%d]: Wp=%d/%d-->%d (final %s), Speed=%.1f (%d), Heading=%03d", local text=string.format("%s [ROE-AS=%d-%d T/M=%d/%d]: Wp=%d/%d-->%d (final %s), Life=%.1f, Speed=%.1f (%d), Heading=%03d, Ammo=%d",
fsmstate, roe, alarm, nTaskTot, nMissions, self.currentwp, #self.waypoints, self:GetWaypointIndexNext(), tostring(self.passedfinalwp), speed, speedEx, self.heading) fsmstate, roe, alarm, nTaskTot, nMissions, self.currentwp, #self.waypoints, self:GetWaypointIndexNext(), tostring(self.passedfinalwp), self.life or 0, speed, speedEx, self.heading, ammo.Total)
self:I(self.lid..text) self:I(self.lid..text)
end end
@ -506,7 +566,7 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, Speed, Formation)
end end
end end
if not self.passedfinalwp then if self:IsEngaging() or not self.passedfinalwp then
-- Debug info. -- Debug info.
self:T(self.lid..string.format("Updateing route: WP %d-->%d (%d/%d), Speed=%.1f knots, Formation=%s", self:T(self.lid..string.format("Updateing route: WP %d-->%d (%d/%d), Speed=%.1f knots, Formation=%s",
@ -576,6 +636,13 @@ end
-- @param #number ResumeRoute If true, resume route after detour point was reached. If false, the group will stop at the detour point and wait for futher commands. -- @param #number ResumeRoute If true, resume route after detour point was reached. If false, the group will stop at the detour point and wait for futher commands.
function ARMYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Formation, ResumeRoute) function ARMYGROUP:onafterDetour(From, Event, To, Coordinate, Speed, Formation, ResumeRoute)
for _,_wp in pairs(self.waypoints) do
local wp=_wp --Ops.OpsGroup#OPSGROUP.Waypoint
if wp.detour then
self:RemoveWaypointByID(wp.uid)
end
end
-- Speed in knots. -- Speed in knots.
Speed=Speed or self:GetSpeedCruise() Speed=Speed or self:GetSpeedCruise()
@ -632,6 +699,185 @@ function ARMYGROUP:onafterRearming(From, Event, To)
end end
--- On before "Retreat" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE_BASE Zone (Optional) Zone where to retreat. Default is the closest retreat zone.
-- @param #number Formation (Optional) Formation of the group.
function ARMYGROUP:onbeforeRetreat(From, Event, To, Zone, Formation)
if not Zone then
local a=self:GetVec2()
local distmin=math.huge
local zonemin=nil
for _,_zone in pairs(self.retreatZones:GetSet()) do
local zone=_zone --Core.Zone#ZONE_BASE
local b=zone:GetVec2()
local dist=UTILS.VecDist2D(a, b)
if dist<distmin then
distmin=dist
zonemin=zone
end
end
if zonemin then
self:__Retreat(0.1, zonemin, Formation)
end
return false
end
return true
end
--- On after "Retreat" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Core.Zone#ZONE_BASE Zone (Optional) Zone where to retreat. Default is the closest retreat zone.
-- @param #number Formation (Optional) Formation of the group.
function ARMYGROUP:onafterRetreat(From, Event, To, Zone, Formation)
-- ID of current waypoint.
local uid=self:GetWaypointCurrent().uid
local Coordinate=Zone:GetRandomCoordinate()
-- Add waypoint after current.
local wp=self:AddWaypoint(Coordinate, nil, uid, Formation, true)
-- Set if we want to resume route after reaching the detour waypoint.
wp.detour=0
end
--- On after "Retreated" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function ARMYGROUP:onafterRetreated(From, Event, To)
-- Get current position.
local pos=self:GetCoordinate()
-- Create a new waypoint.
local wp=pos:WaypointGround(0)
-- Create new route consisting of only this position ==> Stop!
self:Route({wp})
end
--- On after "EngageTarget" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Group#GROUP Group the group to be engaged.
function ARMYGROUP:onbeforeEngageTarget(From, Event, To, Target)
local ammo=self:GetAmmoTot()
if ammo.Total==0 then
self:E(self.lid.."WARNING: Cannot engage TARGET because no ammo left!")
return false
end
return true
end
--- On after "EngageTarget" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Group#GROUP Group the group to be engaged.
function ARMYGROUP:onafterEngageTarget(From, Event, To, Target)
if Target:IsInstanceOf("TARGET") then
self.engage.Target=Target
else
self.engage.Target=TARGET:New(Target)
end
-- Target coordinate.
self.engage.Coordinate=UTILS.DeepCopy(self.engage.Target:GetCoordinate())
-- TODO: Backup current ROE and alarm state and reset after disengage.
-- Switch ROE and alarm state.
self:SwitchAlarmstate(ENUMS.AlarmState.Auto)
self:SwitchROE(ENUMS.ROE.WeaponFree)
-- ID of current waypoint.
local uid=self:GetWaypointCurrent().uid
-- Add waypoint after current.
self.engage.Waypoint=self:AddWaypoint(self.engage.Coordinate, nil, uid, Formation, true)
-- Set if we want to resume route after reaching the detour waypoint.
self.engage.Waypoint.detour=1
end
--- On after "EngageTarget" event.
-- @param #ARMYGROUP self
function ARMYGROUP:_UpdateEngageTarget()
if self.engage.Target and self.engage.Target:IsAlive() then
--env.info("FF Update Engage Target "..self.engage.Target:GetName())
local vec3=self.engage.Target:GetCoordinate():GetVec3()
local dist=UTILS.VecDist2D(vec3, self.engage.Coordinate:GetVec3())
if dist>100 then
--env.info("FF Update Engage Target Moved "..self.engage.Target:GetName())
self.engage.Coordinate:UpdateFromVec3(vec3)
-- ID of current waypoint.
local uid=self:GetWaypointCurrent().uid
-- Remove current waypoint
self:RemoveWaypointByID(self.engage.Waypoint.uid)
-- Add waypoint after current.
self.engage.Waypoint=self:AddWaypoint(self.engage.Coordinate, nil, uid, Formation, true)
-- Set if we want to resume route after reaching the detour waypoint.
self.engage.Waypoint.detour=0
end
else
self:Disengage()
end
end
--- On after "Disengage" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function ARMYGROUP:onafterDisengage(From, Event, To)
-- TODO: Reset ROE and alarm state.
self:_CheckGroupDone(1)
end
--- On after "Rearmed" event. --- On after "Rearmed" event.
-- @param #ARMYGROUP self -- @param #ARMYGROUP self
-- @param #string From From state. -- @param #string From From state.
@ -932,11 +1178,13 @@ function ARMYGROUP:_InitGroup()
element.categoryname=element.unit:GetCategoryName() element.categoryname=element.unit:GetCategoryName()
element.size, element.length, element.height, element.width=unit:GetObjectSize() element.size, element.length, element.height, element.width=unit:GetObjectSize()
element.ammo0=self:GetAmmoUnit(unit, false) element.ammo0=self:GetAmmoUnit(unit, false)
element.life0=unit:GetLife0()
element.life=element.life0
-- Debug text. -- Debug text.
if self.verbose>=2 then if self.verbose>=2 then
local text=string.format("Adding element %s: status=%s, skill=%s, category=%s (%d), size: %.1f (L=%.1f H=%.1f W=%.1f)", local text=string.format("Adding element %s: status=%s, skill=%s, life=%.3f category=%s (%d), size: %.1f (L=%.1f H=%.1f W=%.1f)",
element.name, element.status, element.skill, element.categoryname, element.category, element.size, element.length, element.height, element.width) element.name, element.status, element.skill, element.life, element.categoryname, element.category, element.size, element.length, element.height, element.width)
self:I(self.lid..text) self:I(self.lid..text)
end end

View File

@ -47,6 +47,7 @@
-- @field #number markerCoaliton Coalition to which the marker is dispayed. -- @field #number markerCoaliton Coalition to which the marker is dispayed.
-- @field #table DCStask DCS task structure. -- @field #table DCStask DCS task structure.
-- @field #number Ncasualties Number of own casualties during mission. -- @field #number Ncasualties Number of own casualties during mission.
-- @field #number Nkills Number of (enemy) units killed by assets of this mission.
-- @field #number Nelements Number of elements (units) assigned to mission. -- @field #number Nelements Number of elements (units) assigned to mission.
-- @field #number dTevaluate Time interval in seconds before the mission result is evaluated after mission is over. -- @field #number dTevaluate Time interval in seconds before the mission result is evaluated after mission is over.
-- @field #number Tover Mission abs. time stamp, when mission was over. -- @field #number Tover Mission abs. time stamp, when mission was over.
@ -504,8 +505,9 @@ function AUFTRAG:New(Type)
self.NrepeatFailure=0 self.NrepeatFailure=0
self.NrepeatSuccess=0 self.NrepeatSuccess=0
self.nassets=1 self.nassets=1
self.dTevaluate=0 self.dTevaluate=5
self.Ncasualties=0 self.Ncasualties=0
self.Nkills=0
self.Nelements=0 self.Nelements=0
-- FMS start state is PLANNED. -- FMS start state is PLANNED.
@ -1697,6 +1699,14 @@ function AUFTRAG:GetCasualties()
return self.Ncasualties or 0 return self.Ncasualties or 0
end end
--- Get kills, i.e. number of units that were destroyed by assets of this mission.
-- @param #AUFTRAG self
-- @return #number Number of units destroyed.
function AUFTRAG:GetKills()
return self.Nkills or 0
end
--- Check if mission is "urgent". --- Check if mission is "urgent".
-- @param #AUFTRAG self -- @param #AUFTRAG self
-- @return #boolean If `true`, mission is "urgent". -- @return #boolean If `true`, mission is "urgent".
@ -2102,6 +2112,11 @@ function AUFTRAG:onafterStatus(From, Event, To)
-- Ready to evaluate mission outcome? -- Ready to evaluate mission outcome?
local ready2evaluate=self.Tover and Tnow-self.Tover>=self.dTevaluate or false local ready2evaluate=self.Tover and Tnow-self.Tover>=self.dTevaluate or false
--env.info("FF Tover="..tostring(self.Tover))
--if self.Tover then
-- env.info("FF Tnow-Tover="..tostring(Tnow-self.Tover))
--end
-- Check if mission is OVER (done or cancelled) and enough time passed to evaluate the result. -- Check if mission is OVER (done or cancelled) and enough time passed to evaluate the result.
if self:IsOver() and ready2evaluate then if self:IsOver() and ready2evaluate then
-- Evaluate success or failure of the mission. -- Evaluate success or failure of the mission.
@ -2199,13 +2214,12 @@ function AUFTRAG:Evaluate()
local text=string.format("Evaluating mission:\n") local text=string.format("Evaluating mission:\n")
text=text..string.format("Own casualties = %d/%d\n", self.Ncasualties, self.Nelements) text=text..string.format("Own casualties = %d/%d\n", self.Ncasualties, self.Nelements)
text=text..string.format("Own losses = %.1f %%\n", owndamage) text=text..string.format("Own losses = %.1f %%\n", owndamage)
text=text..string.format("Killed units = %d\n", self.Nkills)
text=text..string.format("--------------------------\n") text=text..string.format("--------------------------\n")
text=text..string.format("Targets left = %d/%d\n", Ntargets, Ntargets0) text=text..string.format("Targets left = %d/%d\n", Ntargets, Ntargets0)
text=text..string.format("Targets life = %.1f/%.1f\n", Life, Life0) text=text..string.format("Targets life = %.1f/%.1f\n", Life, Life0)
text=text..string.format("Enemy losses = %.1f %%\n", targetdamage) text=text..string.format("Enemy losses = %.1f %%\n", targetdamage)
text=text..string.format("--------------------------\n") text=text..string.format("--------------------------\n")
--text=text..string.format("Loss ratio = %.1f %%\n", targetdamage)
--text=text..string.format("--------------------------\n")
text=text..string.format("Success Cond = %s\n", tostring(successCondition)) text=text..string.format("Success Cond = %s\n", tostring(successCondition))
text=text..string.format("Failure Cond = %s\n", tostring(failureCondition)) text=text..string.format("Failure Cond = %s\n", tostring(failureCondition))
text=text..string.format("--------------------------\n") text=text..string.format("--------------------------\n")
@ -2563,6 +2577,8 @@ function AUFTRAG:onafterAssetDead(From, Event, To, Asset)
-- Number of groups alive. -- Number of groups alive.
local N=self:CountOpsGroups() local N=self:CountOpsGroups()
self:I(self.lid..string.format("Asset %s dead! Number of ops groups remaining %d", tostring(Asset.spawngroupname), N))
-- All assets dead? -- All assets dead?
if N==0 then if N==0 then
@ -3045,7 +3061,7 @@ function AUFTRAG:CountOpsGroups()
local N=0 local N=0
for _,_groupdata in pairs(self.groupdata) do for _,_groupdata in pairs(self.groupdata) do
local groupdata=_groupdata --#AUFTRAG.GroupData local groupdata=_groupdata --#AUFTRAG.GroupData
if groupdata and groupdata.opsgroup and groupdata.opsgroup:IsAlive() then if groupdata and groupdata.opsgroup and groupdata.opsgroup:IsAlive() and not groupdata.opsgroup:IsDead() then
N=N+1 N=N+1
end end
end end

View File

@ -336,6 +336,7 @@ function FLIGHTGROUP:New(group)
self:HandleEvent(EVENTS.Crash, self.OnEventCrash) self:HandleEvent(EVENTS.Crash, self.OnEventCrash)
self:HandleEvent(EVENTS.RemoveUnit, self.OnEventRemoveUnit) self:HandleEvent(EVENTS.RemoveUnit, self.OnEventRemoveUnit)
self:HandleEvent(EVENTS.UnitLost, self.OnEventUnitLost) self:HandleEvent(EVENTS.UnitLost, self.OnEventUnitLost)
self:HandleEvent(EVENTS.Kill, self.OnEventKill)
-- Init waypoints. -- Init waypoints.
self:InitWaypoints() self:InitWaypoints()
@ -715,6 +716,12 @@ function FLIGHTGROUP:GetFuelMin()
return fuelmin*100 return fuelmin*100
end end
--- Get number of kills of this group.
-- @param #FLIGHTGROUP self
-- @return #number Number of units killed.
function FLIGHTGROUP:GetKills()
return self.Nkills
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Status -- Status
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -741,18 +748,22 @@ function FLIGHTGROUP:onbeforeStatus(From, Event, To)
-- Units with life <=1 are dead. -- Units with life <=1 are dead.
if life<=1 then if life<=1 then
--env.info(string.format("FF unit %s: live<=1 in status at T=%.3f", unit:GetName(), timer.getTime()))
isdead=true isdead=true
end end
else else
-- Not alive any more. -- Not alive any more.
--env.info(string.format("FF unit %s: NOT alive in status at T=%.3f", unit:GetName(), timer.getTime()))
isdead=true isdead=true
end end
-- This one is dead. -- This one is dead.
if isdead then if isdead then
self:E(self.lid..string.format("Element %s is dead! Probably despawned without notice or landed at a too small airbase", tostring(element.name))) local text=string.format("Element %s is dead at t=%.3f! Maybe despawned without notice or landed at a too small airbase. Calling ElementDead in 60 sec to give other events a chance",
self:ElementDead(element) tostring(element.name), timer.getTime())
self:E(self.lid..text)
self:__ElementDead(60, element)
end end
end end
@ -854,9 +865,9 @@ function FLIGHTGROUP:onafterStatus(From, Event, To)
local parking=element.parking and tostring(element.parking.TerminalID) or "X" local parking=element.parking and tostring(element.parking.TerminalID) or "X"
-- Check if element is not dead and we missed an event. -- Check if element is not dead and we missed an event.
if life<=0 and element.status~=OPSGROUP.ElementStatus.DEAD and element.status~=OPSGROUP.ElementStatus.INUTERO then --if life<=0 and element.status~=OPSGROUP.ElementStatus.DEAD and element.status~=OPSGROUP.ElementStatus.INUTERO then
self:ElementDead(element) -- self:ElementDead(element)
end --end
-- Get ammo. -- Get ammo.
local ammo=self:GetAmmoElement(element) local ammo=self:GetAmmoElement(element)
@ -1177,9 +1188,9 @@ function FLIGHTGROUP:OnEventCrash(EventData)
-- Get element. -- Get element.
local element=self:GetElementByName(unitname) local element=self:GetElementByName(unitname)
if element then if element and element.status~=OPSGROUP.ElementStatus.DEAD then
self:T3(self.lid..string.format("EVENT: Element %s crashed ==> dead", element.name)) self:T(self.lid..string.format("EVENT: Element %s crashed ==> destroyed", element.name))
self:ElementDead(element) self:ElementDestroyed(element)
end end
end end
@ -1193,7 +1204,7 @@ function FLIGHTGROUP:OnEventUnitLost(EventData)
-- Check that this is the right group. -- Check that this is the right group.
if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then
self:T(self.lid..string.format("EVENT: Unit %s lost!", EventData.IniUnitName)) self:T2(self.lid..string.format("EVENT: Unit %s lost at t=%.3f", EventData.IniUnitName, timer.getTime()))
local unit=EventData.IniUnit local unit=EventData.IniUnit
local group=EventData.IniGroup local group=EventData.IniGroup
@ -1202,8 +1213,8 @@ function FLIGHTGROUP:OnEventUnitLost(EventData)
-- Get element. -- Get element.
local element=self:GetElementByName(unitname) local element=self:GetElementByName(unitname)
if element then if element and element.status~=OPSGROUP.ElementStatus.DEAD then
self:T3(self.lid..string.format("EVENT: Element %s unit lost ==> destroyed", element.name)) self:T(self.lid..string.format("EVENT: Element %s unit lost ==> destroyed t=%.3f", element.name, timer.getTime()))
self:ElementDestroyed(element) self:ElementDestroyed(element)
end end
@ -1211,6 +1222,30 @@ function FLIGHTGROUP:OnEventUnitLost(EventData)
end end
--- Flightgroup event function handling the crash of a unit.
-- @param #FLIGHTGROUP self
-- @param Core.Event#EVENTDATA EventData Event data.
function FLIGHTGROUP:OnEventKill(EventData)
-- Check that this is the right group.
if EventData and EventData.IniGroup and EventData.IniUnit and EventData.IniGroupName and EventData.IniGroupName==self.groupname then
self:T2(self.lid..string.format("EVENT: Unit %s killed unit %s!", tostring(EventData.IniUnitName), tostring(EventData.TgtUnitName)))
local unit=EventData.IniUnit
local group=EventData.IniGroup
local unitname=EventData.IniUnitName
self.Nkills=self.Nkills+1
local mission=self:GetMissionCurrent()
if mission then
mission.Nkills=mission.Nkills+1
end
end
end
--- Flightgroup event function handling the crash of a unit. --- Flightgroup event function handling the crash of a unit.
-- @param #FLIGHTGROUP self -- @param #FLIGHTGROUP self
-- @param Core.Event#EVENTDATA EventData Event data. -- @param Core.Event#EVENTDATA EventData Event data.
@ -2439,7 +2474,7 @@ function FLIGHTGROUP:onafterFuelLow(From, Event, To)
self:I(self.lid..string.format("Send to refuel at tanker %s", tanker:GetName())) self:I(self.lid..string.format("Send to refuel at tanker %s", tanker:GetName()))
-- Get a coordinate towards the tanker. -- Get a coordinate towards the tanker.
local coordinate=self:GetCoordinate():GetIntermediateCoordinate(tanker.flightgroup:GetCoordinate(), 0.75) local coordinate=self:GetCoordinate():GetIntermediateCoordinate(tanker:GetCoordinate(), 0.75)
self:Refuel(coordinate) self:Refuel(coordinate)

View File

@ -55,6 +55,7 @@
-- @field #boolean detectionOn If true, detected units of the group are analyzed. -- @field #boolean detectionOn If true, detected units of the group are analyzed.
-- @field Ops.Auftrag#AUFTRAG missionpaused Paused mission. -- @field Ops.Auftrag#AUFTRAG missionpaused Paused mission.
-- @field #number Ndestroyed Number of destroyed units. -- @field #number Ndestroyed Number of destroyed units.
-- @field #number Nkills Number kills of this groups.
-- --
-- @field Core.Point#COORDINATE coordinate Current coordinate. -- @field Core.Point#COORDINATE coordinate Current coordinate.
-- --
@ -88,7 +89,7 @@
-- --
-- @field #OPSGROUP.Spot spot Laser and IR spot. -- @field #OPSGROUP.Spot spot Laser and IR spot.
-- --
-- @field #OPSGROUP.Ammo ammo Initial ammuont of ammo. -- @field #OPSGROUP.Ammo ammo Initial ammount of ammo.
-- --
-- @extends Core.Fsm#FSM -- @extends Core.Fsm#FSM
@ -142,6 +143,7 @@ OPSGROUP = {
icls = {}, icls = {},
callsign = {}, callsign = {},
Ndestroyed = 0, Ndestroyed = 0,
Nkills = 0,
} }
@ -154,6 +156,8 @@ OPSGROUP = {
-- @field #number length Length of element in meters. -- @field #number length Length of element in meters.
-- @field #number width Width of element in meters. -- @field #number width Width of element in meters.
-- @field #number height Height of element in meters. -- @field #number height Height of element in meters.
-- @field #number life0 Initial life points.
-- @field #number life Life points when last updated.
--- Status of group element. --- Status of group element.
-- @type OPSGROUP.ElementStatus -- @type OPSGROUP.ElementStatus
@ -354,7 +358,14 @@ function OPSGROUP:New(Group)
end end
-- Set some string id for output to DCS.log file. -- Set some string id for output to DCS.log file.
self.lid=string.format("OPSGROUP %s | ", self.groupname) self.lid=string.format("OPSGROUP %s | ", tostring(self.groupname))
if self.group then
if not self:IsExist() then
self:E(self.lid.."ERROR: GROUP does not exist! Returning nil")
return nil
end
end
-- Init set of detected units. -- Init set of detected units.
self.detectedunits=SET_UNIT:New() self.detectedunits=SET_UNIT:New()
@ -387,6 +398,9 @@ function OPSGROUP:New(Group)
self:AddTransition("*", "Status", "*") -- Status update. self:AddTransition("*", "Status", "*") -- Status update.
self:AddTransition("*", "Destroyed", "*") -- The whole group is dead.
self:AddTransition("*", "Damaged", "*") -- Someone in the group took damage.
self:AddTransition("*", "UpdateRoute", "*") -- Update route of group. Only if airborne. self:AddTransition("*", "UpdateRoute", "*") -- Update route of group. Only if airborne.
self:AddTransition("*", "Respawn", "*") -- Respawn group. self:AddTransition("*", "Respawn", "*") -- Respawn group.
self:AddTransition("*", "PassingWaypoint", "*") -- Passing waypoint. self:AddTransition("*", "PassingWaypoint", "*") -- Passing waypoint.
@ -436,6 +450,7 @@ function OPSGROUP:New(Group)
self:AddTransition("*", "ElementSpawned", "*") -- An element was spawned. self:AddTransition("*", "ElementSpawned", "*") -- An element was spawned.
self:AddTransition("*", "ElementDestroyed", "*") -- An element was destroyed. self:AddTransition("*", "ElementDestroyed", "*") -- An element was destroyed.
self:AddTransition("*", "ElementDead", "*") -- An element is dead. self:AddTransition("*", "ElementDead", "*") -- An element is dead.
self:AddTransition("*", "ElementDamaged", "*") -- An element was damaged.
------------------------ ------------------------
--- Pseudo Functions --- --- Pseudo Functions ---
@ -531,7 +546,11 @@ end
-- @return #OPSGROUP self -- @return #OPSGROUP self
function OPSGROUP:SetLaser(Code, CheckLOS, IROff, UpdateTime) function OPSGROUP:SetLaser(Code, CheckLOS, IROff, UpdateTime)
self.spot.Code=Code or 1688 self.spot.Code=Code or 1688
self.spot.CheckLOS=CheckLOS and CheckLOS or true if CheckLOS~=nil then
self.spot.CheckLOS=CheckLOS
else
self.spot.CheckLOS=true
end
self.spot.IRon=not IROff self.spot.IRon=not IROff
self.spot.dt=UpdateTime or 0.5 self.spot.dt=UpdateTime or 0.5
return self return self
@ -923,8 +942,23 @@ function OPSGROUP:DespawnElement(Element, Delay, NoEventRemoveUnit)
return self return self
end end
--- Get current 2D position vector of the group.
-- @param #OPSGROUP self
-- @return DCS#Vec2 Vector with x,y components.
function OPSGROUP:GetVec2()
--- Get current 3D vector of the group. local vec3=self:GetVec3()
if vec3 then
local vec2={x=vec3.x, y=vec3.z}
return vec2
end
return nil
end
--- Get current 3D position vector of the group.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @return DCS#Vec3 Vector with x,y,z components. -- @return DCS#Vec3 Vector with x,y,z components.
function OPSGROUP:GetVec3() function OPSGROUP:GetVec3()
@ -960,6 +994,7 @@ function OPSGROUP:GetCoordinate(NewObject)
if NewObject then if NewObject then
local coord=COORDINATE:NewFromCoordinate(self.coordinate) local coord=COORDINATE:NewFromCoordinate(self.coordinate)
return coord
else else
return self.coordinate return self.coordinate
end end
@ -1232,6 +1267,20 @@ function OPSGROUP:IsLasing()
return self.spot.On return self.spot.On
end end
--- Check if the group is currently retreating.
-- @param #OPSGROUP self
-- @return #boolean If true, group is retreating.
function OPSGROUP:IsRetreating()
return self:is("Retreating")
end
--- Check if the group is engaging another unit or group.
-- @param #OPSGROUP self
-- @return #boolean If true, group is engaging.
function OPSGROUP:IsEngaging()
return self:is("Engaging")
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Waypoint Functions -- Waypoint Functions
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -1303,7 +1352,7 @@ end
-- @return #OPSGROUP.Waypoint Waypoint data. -- @return #OPSGROUP.Waypoint Waypoint data.
function OPSGROUP:GetWaypointByID(uid) function OPSGROUP:GetWaypointByID(uid)
for _,_waypoint in pairs(self.waypoints) do for _,_waypoint in pairs(self.waypoints or {}) do
local waypoint=_waypoint --#OPSGROUP.Waypoint local waypoint=_waypoint --#OPSGROUP.Waypoint
if waypoint.uid==uid then if waypoint.uid==uid then
return waypoint return waypoint
@ -2190,11 +2239,16 @@ function OPSGROUP:onafterTaskCancel(From, Event, To, Task)
-- Set stop flag. When the flag is true, the _TaskDone function is executed and calls :TaskDone() -- Set stop flag. When the flag is true, the _TaskDone function is executed and calls :TaskDone()
Task.stopflag:Set(1) Task.stopflag:Set(1)
local done=false
if Task.dcstask.id=="Formation" then if Task.dcstask.id=="Formation" then
Task.formation:Stop() Task.formation:Stop()
self:TaskDone(Task) done=true
elseif stopflag==1 or not self:IsAlive() then 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. -- Manual call TaskDone if setting flag to one was not successful.
done=true
end
if done then
self:TaskDone(Task) self:TaskDone(Task)
end end
@ -3291,7 +3345,7 @@ end
function OPSGROUP:onafterLaserPause(From, Event, To) function OPSGROUP:onafterLaserPause(From, Event, To)
-- Debug message. -- Debug message.
self:I(self.lid.."Switching LASER off temporarily") self:T(self.lid.."Switching LASER off temporarily")
-- "Destroy" the laser beam. -- "Destroy" the laser beam.
self.spot.Laser:destroy() self.spot.Laser:destroy()
@ -3326,7 +3380,7 @@ end
function OPSGROUP:onafterLaserResume(From, Event, To) function OPSGROUP:onafterLaserResume(From, Event, To)
-- Debug info. -- Debug info.
self:I(self.lid.."Resuming LASER") self:T(self.lid.."Resuming LASER")
-- Unset paused. -- Unset paused.
self.spot.Paused=false self.spot.Paused=false
@ -3345,7 +3399,7 @@ function OPSGROUP:onafterLaserResume(From, Event, To)
if target then if target then
-- Debug message. -- Debug message.
self:I(self.lid.."Switching LASER on again at target ".. target:GetName()) self:T(self.lid.."Switching LASER on again")
self:LaserOn(target) self:LaserOn(target)
end end
@ -3480,6 +3534,10 @@ function OPSGROUP:SetLaserTarget(Target)
-- Coordinate as target. -- Coordinate as target.
self.spot.TargetType=0 self.spot.TargetType=0
self.spot.offsetTarget={x=0, y=0, z=0} self.spot.offsetTarget={x=0, y=0, z=0}
elseif Target:IsInstanceOf("SCENERY") then
-- Coordinate as target.
self.spot.TargetType=0
self.spot.offsetTarget={x=0, y=1, z=0}
else else
self:E(self.lid.."ERROR: LASER target should be a POSITIONABLE (GROUP, UNIT or STATIC) or a COORDINATE object!") self:E(self.lid.."ERROR: LASER target should be a POSITIONABLE (GROUP, UNIT or STATIC) or a COORDINATE object!")
return return
@ -3543,13 +3601,13 @@ function OPSGROUP:_UpdateLaser()
local unit=self.spot.TargetGroup:GetHighestThreat() local unit=self.spot.TargetGroup:GetHighestThreat()
if unit then if unit then
self:I(self.lid..string.format("Switching to target unit %s in the group", unit:GetName())) self:T(self.lid..string.format("Switching to target unit %s in the group", unit:GetName()))
self.spot.TargetUnit=unit self.spot.TargetUnit=unit
-- We update the laser position in the next update cycle and then check the LOS. -- We update the laser position in the next update cycle and then check the LOS.
return return
else else
-- Switch laser off. -- Switch laser off.
self:I(self.lid.."Target is not alive any more ==> switching LASER off") self:T(self.lid.."Target is not alive any more ==> switching LASER off")
self:LaserOff() self:LaserOff()
return return
end end
@ -3557,7 +3615,7 @@ function OPSGROUP:_UpdateLaser()
else else
-- Switch laser off. -- Switch laser off.
self:I(self.lid.."Target is not alive any more ==> switching LASER off") self:T(self.lid.."Target is not alive any more ==> switching LASER off")
self:LaserOff() self:LaserOff()
return return
end end
@ -3625,7 +3683,7 @@ end
-- @param #string To To state. -- @param #string To To state.
-- @param #OPSGROUP.Element Element The flight group element. -- @param #OPSGROUP.Element Element The flight group element.
function OPSGROUP:onafterElementDead(From, Event, To, Element) function OPSGROUP:onafterElementDead(From, Event, To, Element)
self:T(self.lid..string.format("Element dead %s", Element.name)) self:T(self.lid..string.format("Element dead %s at t=%.3f", Element.name, timer.getTime()))
-- Set element status. -- Set element status.
self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD) self:_UpdateStatus(Element, OPSGROUP.ElementStatus.DEAD)
@ -3666,13 +3724,24 @@ function OPSGROUP:onafterElementDead(From, Event, To, Element)
end end
--- On before "Dead" event.
-- @param #OPSGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function OPSGROUP:onbeforeDead(From, Event, To)
if self.Ndestroyed==#self.elements then
self:Destroyed()
end
end
--- On after "Dead" event. --- On after "Dead" event.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @param #string From From state. -- @param #string From From state.
-- @param #string Event Event. -- @param #string Event Event.
-- @param #string To To state. -- @param #string To To state.
function OPSGROUP:onafterDead(From, Event, To) function OPSGROUP:onafterDead(From, Event, To)
self:T(self.lid..string.format("Group dead!")) self:T(self.lid..string.format("Group dead at t=%.3f", timer.getTime()))
-- Delete waypoints so they are re-initialized at the next spawn. -- Delete waypoints so they are re-initialized at the next spawn.
self.waypoints=nil self.waypoints=nil
@ -3682,6 +3751,8 @@ function OPSGROUP:onafterDead(From, Event, To)
for _,_mission in pairs(self.missionqueue) do for _,_mission in pairs(self.missionqueue) do
local mission=_mission --Ops.Auftrag#AUFTRAG local mission=_mission --Ops.Auftrag#AUFTRAG
self:T(self.lid.."Cancelling mission because group is dead! Mission name "..tostring(mission:GetName()))
self:MissionCancel(mission) self:MissionCancel(mission)
mission:GroupDead(self) mission:GroupDead(self)
@ -3713,7 +3784,7 @@ function OPSGROUP:onafterStop(From, Event, To)
end end
-- Debug output. -- Debug output.
self:T(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from database.") self:I(self.lid.."STOPPED! Unhandled events, cleared scheduler and removed from database.")
end end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@ -3885,6 +3956,11 @@ function OPSGROUP:_CheckGroupDone(delay)
self:ScheduleOnce(delay, self._CheckGroupDone, self) self:ScheduleOnce(delay, self._CheckGroupDone, self)
else else
if self:IsEngaging() then
self:UpdateRoute()
return
end
-- Get current waypoint. -- Get current waypoint.
local waypoint=self:GetWaypoint(self.currentwp) local waypoint=self:GetWaypoint(self.currentwp)
@ -4016,6 +4092,37 @@ function OPSGROUP:_CheckStuck()
end end
--- Check damage.
-- @param #OPSGROUP self
-- @return #OPSGROUP self
function OPSGROUP:_CheckDamage()
self.life=0
local damaged=false
for _,_element in pairs(self.elements) do
local element=_element --Ops.OpsGroup#OPSGROUP
-- Current life points.
local life=element.unit:GetLife()
self.life=self.life+life
if life<element.life then
element.life=life
self:ElementDamaged(element)
damaged=true
end
end
if damaged then
self:Damaged()
end
return self
end
--- Check ammo is full. --- Check ammo is full.
-- @param #OPSGROUP self -- @param #OPSGROUP self
-- @return #boolean If true, ammo is full. -- @return #boolean If true, ammo is full.
@ -4058,6 +4165,7 @@ function OPSGROUP:_CheckAmmoStatus()
self.outofAmmo=false self.outofAmmo=false
end end
if ammo.Total==0 and not self.outofAmmo then if ammo.Total==0 and not self.outofAmmo then
env.info("FF out of ammo")
self.outofAmmo=true self.outofAmmo=true
self:OutOfAmmo() self:OutOfAmmo()
end end
@ -4098,6 +4206,11 @@ function OPSGROUP:_CheckAmmoStatus()
self:OutOfMissiles() self:OutOfMissiles()
end end
-- Check if group is engaging.
if self:IsEngaging() and ammo.Total==0 then
self:Disengage()
end
end end
end end
@ -4241,6 +4354,9 @@ function OPSGROUP:InitWaypoints()
-- Coordinate of the waypoint. -- Coordinate of the waypoint.
local coordinate=COORDINATE:New(wp.x, wp.alt, wp.y) local coordinate=COORDINATE:New(wp.x, wp.alt, wp.y)
-- Strange!
wp.speed=wp.speed or 0
-- Speed at the waypoint. -- Speed at the waypoint.
local speedknots=UTILS.MpsToKnots(wp.speed) local speedknots=UTILS.MpsToKnots(wp.speed)
@ -4399,6 +4515,15 @@ function OPSGROUP._PassingWaypoint(group, opsgroup, uid)
-- Trigger Rearming event. -- Trigger Rearming event.
opsgroup:Rearming() opsgroup:Rearming()
elseif opsgroup:IsRetreating() then
-- Trigger Retreated event.
opsgroup:Retreated()
elseif opsgroup:IsEngaging() then
-- Nothing to do really.
else else
-- Trigger DetourReached event. -- Trigger DetourReached event.

View File

@ -232,6 +232,12 @@ function TARGET:AddObject(Object)
self:AddObject(object) self:AddObject(object)
end end
elseif Object:IsInstanceOf("GROUP") then
for _,unit in pairs(Object:GetUnits()) do
self:_AddObject(unit)
end
else else
--- ---
@ -244,6 +250,19 @@ function TARGET:AddObject(Object)
end end
--- Check if TARGET is alive.
-- @param #TARGET self
-- @param #boolean If true, target is alive.
function TARGET:IsAlive()
return self:Is("Alive")
end
--- Check if TARGET is dead.
-- @param #TARGET self
-- @param #boolean If true, target is dead.
function TARGET:IsDead()
return self:Is("Dead")
end
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Start & Status -- Start & Status
@ -302,7 +321,7 @@ function TARGET:onafterStatus(From, Event, To)
end end
-- Log output verbose=1. -- Log output verbose=1.
if self.verbose>=1 then if self.verbose>=0 then
local text=string.format("%s: Targets=%d/%d Life=%.1f/%.1f Damage=%.1f", fsmstate, self:CountTargets(), self.Ntargets0, self:GetLife(), self:GetLife0(), self:GetDamage()) local text=string.format("%s: Targets=%d/%d Life=%.1f/%.1f Damage=%.1f", fsmstate, self:CountTargets(), self.Ntargets0, self:GetLife(), self:GetLife0(), self:GetDamage())
if damaged then if damaged then
text=text.." Damaged!" text=text.." Damaged!"
@ -311,7 +330,7 @@ function TARGET:onafterStatus(From, Event, To)
end end
-- Log output verbose=2. -- Log output verbose=2.
if self.verbose>=2 then if self.verbose>=0 then
local text="Target:" local text="Target:"
for i,_target in pairs(self.targets) do for i,_target in pairs(self.targets) do
local target=_target --#TARGET.Object local target=_target --#TARGET.Object
@ -349,7 +368,8 @@ end
-- @param #TARGET.Object Target Target object. -- @param #TARGET.Object Target Target object.
function TARGET:onafterObjectDestroyed(From, Event, To, Target) function TARGET:onafterObjectDestroyed(From, Event, To, Target)
self:T(self.lid..string.format("Object %s destroyed", Target.Name)) -- Debug message.
self:I(self.lid..string.format("Object %s destroyed", Target.Name))
-- Set target status. -- Set target status.
Target.Status=TARGET.ObjectStatus.DEAD Target.Status=TARGET.ObjectStatus.DEAD
@ -405,16 +425,20 @@ function TARGET:OnEventUnitDeadOrLost(EventData)
if EventData and EventData.IniUnitName then if EventData and EventData.IniUnitName then
-- Debug info. -- Debug info.
--self:T3(self.lid..string.format("EVENT: Unit %s dead or lost!", EventData.IniUnitName)) self:I(self.lid..string.format("EVENT: Unit %s dead or lost!", EventData.IniUnitName))
-- Get target. -- Get target.
local target=self:GetTargetByName(EventData.IniUnitName) local target=self:GetTargetByName(EventData.IniUnitName)
if not target then
target=self:GetTargetByName(EventData.IniGroupName)
end
-- Check if this is one of ours. -- Check if this is one of ours.
if target and target.Status==TARGET.ObjectStatus.ALIVE then if target and target.Status==TARGET.ObjectStatus.ALIVE then
-- Debug message. -- Debug message.
self:T3(self.lid..string.format("EVENT: target unit %s dead or lost ==> destroyed", target.Name)) self:I(self.lid..string.format("EVENT: target unit %s dead or lost ==> destroyed", target.Name))
-- Trigger object destroyed event. -- Trigger object destroyed event.
self:ObjectDestroyed(target) self:ObjectDestroyed(target)
@ -525,12 +549,12 @@ function TARGET:_AddObject(Object)
elseif Object:IsInstanceOf("COORDINATE") then elseif Object:IsInstanceOf("COORDINATE") then
local coord=Object --Core.Point#COORDINATE local coord=UTILS.DeepCopy(Object) --Core.Point#COORDINATE
target.Type=TARGET.ObjectType.COORDINATE target.Type=TARGET.ObjectType.COORDINATE
target.Name=coord:ToStringMGRS() target.Name=coord:ToStringMGRS()
target.Coordinate=Object target.Coordinate=coord
target.Life0=1 target.Life0=1
target.Life=1 target.Life=1
@ -683,8 +707,12 @@ function TARGET:GetTargetVec3(Target)
local object=Target.Object --Wrapper.Group#GROUP local object=Target.Object --Wrapper.Group#GROUP
if object and object:IsAlive() then if object and object:IsAlive() then
local vec3=object:GetVec3()
return vec3
return object:GetVec3() else
return nil
end end
@ -693,7 +721,10 @@ function TARGET:GetTargetVec3(Target)
local object=Target.Object --Wrapper.Unit#UNIT local object=Target.Object --Wrapper.Unit#UNIT
if object and object:IsAlive() then if object and object:IsAlive() then
return object:GetVec3() local vec3=object:GetVec3()
return vec3
else
return nil
end end
elseif Target.Type==TARGET.ObjectType.STATIC then elseif Target.Type==TARGET.ObjectType.STATIC then
@ -701,7 +732,10 @@ function TARGET:GetTargetVec3(Target)
local object=Target.Object --Wrapper.Static#STATIC local object=Target.Object --Wrapper.Static#STATIC
if object and object:IsAlive() then if object and object:IsAlive() then
return object:GetVec3() local vec3=object:GetVec3()
return vec3
else
return nil
end end
elseif Target.Type==TARGET.ObjectType.SCENERY then elseif Target.Type==TARGET.ObjectType.SCENERY then
@ -709,14 +743,18 @@ function TARGET:GetTargetVec3(Target)
local object=Target.Object --Wrapper.Scenery#SCENERY local object=Target.Object --Wrapper.Scenery#SCENERY
if object then if object then
return object:GetVec3() local vec3=object:GetVec3()
return vec3
else
return nil
end end
elseif Target.Type==TARGET.ObjectType.AIRBASE then elseif Target.Type==TARGET.ObjectType.AIRBASE then
local object=Target.Object --Wrapper.Airbase#AIRBASE local object=Target.Object --Wrapper.Airbase#AIRBASE
return object:GetVec3() local vec3=object:GetVec3()
return vec3
--if Target.Status==TARGET.ObjectStatus.ALIVE then --if Target.Status==TARGET.ObjectStatus.ALIVE then
--end --end
@ -725,7 +763,8 @@ function TARGET:GetTargetVec3(Target)
local object=Target.Object --Core.Point#COORDINATE local object=Target.Object --Core.Point#COORDINATE
return {x=object.x, y=object.y, z=object.z} local vec3={x=object.x, y=object.y, z=object.z}
return vec3
end end
@ -1007,7 +1046,7 @@ function TARGET:CountTargets()
-- No target we can check! -- No target we can check!
else else
self:E(self.lid.."ERROR unknown target type") self:E(self.lid.."ERROR: Unknown target type! Cannot count targets")
end end
end end