** ARMYGROUP**
- Added suppression option

**COMMANDER**
- Added function to add targets with defined resources

**OPSGROUP**
- Added option to pause multiple missions

**INTEL**
- Fixed bug in cluster calc

**LEGION**
- Added function to get alive opsgroups

**TARGET**
* Added start condition
This commit is contained in:
Frank
2022-05-27 22:14:21 +02:00
parent d3d815f26a
commit ae54cd8fde
15 changed files with 774 additions and 160 deletions

View File

@@ -34,6 +34,11 @@
-- @field #boolean isMobile If true, group is mobile.
-- @field #ARMYGROUP.Target engage Engage target.
-- @field Core.Set#SET_ZONE retreatZones Set of retreat zones.
-- @field #boolean suppressOn Bla
-- @field #boolean isSuppressed Bla
-- @field #number TsuppressMin Bla
-- @field #number TsuppressMax Bla
-- @field #number TsuppressAve Bla
-- @extends Ops.OpsGroup#OPSGROUP
--- *Your soul may belong to Jesus, but your ass belongs to the marines.* -- Eugene B Sledge
@@ -122,6 +127,9 @@ function ARMYGROUP:New(group)
self:AddTransition("*", "Retreat", "Retreating") -- Order a retreat.
self:AddTransition("Retreating", "Retreated", "Retreated") -- Group retreated.
self:AddTransition("*", "Suppressed", "*") -- Group is suppressed
self:AddTransition("*", "Unsuppressed", "*") -- Group is unsuppressed.
self:AddTransition("Cruising", "EngageTarget", "Engaging") -- Engage a target from Cruising state
self:AddTransition("Holding", "EngageTarget", "Engaging") -- Engage a target from Holding state
self:AddTransition("OnDetour", "EngageTarget", "Engaging") -- Engage a target from OnDetour state
@@ -280,6 +288,7 @@ function ARMYGROUP:New(group)
-- @function [parent=#ARMYGROUP] EngageTarget
-- @param #ARMYGROUP self
-- @param Wrapper.Group#GROUP Group the group to be engaged.
-- @param #number Speed Speed in knots.
-- @param #string Formation Formation used in the engagement.
--- Triggers the FSM event "EngageTarget" after a delay.
@@ -287,6 +296,7 @@ function ARMYGROUP:New(group)
-- @param #ARMYGROUP self
-- @param #number delay Delay in seconds.
-- @param Wrapper.Group#GROUP Group the group to be engaged.
-- @param #number Speed Speed in knots.
-- @param #string Formation Formation used in the engagement.
@@ -297,6 +307,7 @@ function ARMYGROUP:New(group)
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Group#GROUP Group the group to be engaged.
-- @param #number Speed Speed in knots.
-- @param #string Formation Formation used in the engagement.
@@ -386,7 +397,7 @@ function ARMYGROUP:New(group)
self:HandleEvent(EVENTS.Birth, self.OnEventBirth)
self:HandleEvent(EVENTS.Dead, self.OnEventDead)
self:HandleEvent(EVENTS.RemoveUnit, self.OnEventRemoveUnit)
--self:HandleEvent(EVENTS.Hit, self.OnEventHit)
self:HandleEvent(EVENTS.Hit, self.OnEventHit)
-- Start the status monitoring.
self.timerStatus=TIMER:New(self.Status, self):Start(1, 30)
@@ -572,6 +583,47 @@ function ARMYGROUP:AddRetreatZone(RetreatZone)
return self
end
--- Set suppression on. average, minimum and maximum time a unit is suppressed each time it gets hit.
-- @param #ARMYGROUP self
-- @param #number Tave Average time [seconds] a group will be suppressed. Default is 15 seconds.
-- @param #number Tmin (Optional) Minimum time [seconds] a group will be suppressed. Default is 5 seconds.
-- @param #number Tmax (Optional) Maximum time a group will be suppressed. Default is 25 seconds.
-- @return #ARMYGROUP self
function ARMYGROUP:SetSuppressionOn(Tave, Tmin, Tmax)
-- Activate suppression.
self.suppressionOn=true
-- Minimum suppression time is input or default 5 sec (but at least 1 second).
self.TsuppressMin=Tmin or 1
self.TsuppressMin=math.max(self.TsuppressMin, 1)
-- Maximum suppression time is input or default but at least Tmin.
self.TsuppressMax=Tmax or 15
self.TsuppressMax=math.max(self.TsuppressMax, self.TsuppressMin)
-- Expected suppression time is input or default but at leat Tmin and at most Tmax.
self.TsuppressAve=Tave or 10
self.TsuppressAve=math.max(self.TsuppressMin)
self.TsuppressAve=math.min(self.TsuppressMax)
-- Debug Info
self:T(self.lid..string.format("Set ave suppression time to %d seconds.", self.TsuppressAve))
self:T(self.lid..string.format("Set min suppression time to %d seconds.", self.TsuppressMin))
self:T(self.lid..string.format("Set max suppression time to %d seconds.", self.TsuppressMax))
return self
end
--- Set suppression off.
-- @param #ARMYGROUP self
-- @return #ARMYGROUP self
function ARMYGROUP:SetSuppressionOff()
-- Activate suppression.
self.suppressionOn=false
end
--- Check if the group is currently holding its positon.
-- @param #ARMYGROUP self
-- @return #boolean If true, group was ordered to hold.
@@ -651,10 +703,14 @@ function ARMYGROUP:Status()
-- Check if group is waiting.
if self:IsWaiting() then
if self.Twaiting and self.dTwait then
if timer.getAbsTime()>self.Twaiting+self.dTwait then
if timer.getAbsTime()>self.Twaiting+self.dTwait then
self.Twaiting=nil
self.dTwait=nil
self:Cruise()
if self:_CountPausedMissions()>0 then
self:UnpauseMission()
else
self:Cruise()
end
end
end
end
@@ -799,22 +855,6 @@ end
-- DCS Events ==> See OPSGROUP
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--- Event function handling when a unit is hit.
-- @param #ARMYGROUP self
-- @param Core.Event#EVENTDATA EventData Event data.
function ARMYGROUP:OnEventHit(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
local unit=EventData.IniUnit
local group=EventData.IniGroup
local unitname=EventData.IniUnitName
-- TODO: suppression
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- FSM Events
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1126,7 +1166,7 @@ function ARMYGROUP:onafterUpdateRoute(From, Event, To, n, N, Speed, Formation)
self.speedWp=wp.speed
-- Debug output.
if self.verbose>=10 or true then
if self.verbose>=10 then
for i,_wp in pairs(waypoints) do
local wp=_wp --Ops.OpsGroup#OPSGROUP.Waypoint
@@ -1228,6 +1268,16 @@ end
function ARMYGROUP:onafterOutOfAmmo(From, Event, To)
self:T(self.lid..string.format("Group is out of ammo at t=%.3f", timer.getTime()))
-- Get current task.
local task=self:GetTaskCurrent()
if task then
if task.dcstask.id=="FireAtPoint" or task.dcstask.id==AUFTRAG.SpecialTask.BARRAGE then
self:T(self.lid..string.format("Cancelling current %s task because out of ammo!", task.dcstask.id))
self:TaskCancel(task)
end
end
-- Fist, check if we want to rearm once out-of-ammo.
--TODO: IsMobile() check
if self.rearmOnOutOfAmmo then
@@ -1250,16 +1300,6 @@ function ARMYGROUP:onafterOutOfAmmo(From, Event, To)
if self.rtzOnOutOfAmmo then
self:__RTZ(-1)
end
-- Get current task.
local task=self:GetTaskCurrent()
if task then
if task.dcstask.id=="FireAtPoint" or task.dcstask.id==AUFTRAG.SpecialTask.BARRAGE then
self:T(self.lid..string.format("Cancelling current %s task because out of ammo!", task.dcstask.id))
self:TaskCancel(task)
end
end
end
@@ -1292,6 +1332,15 @@ function ARMYGROUP:onbeforeRearm(From, Event, To, Coordinate, Formation)
allowed=false
end
-- Check if coordinate is provided.
if allowed and not Coordinate then
local truck=self:FindNearestAmmoSupply()
if truck and truck:IsAlive() then
self:__Rearm(-0.1, truck:GetCoordinate(), Formation)
end
return false
end
-- Try again...
if dt then
self:T(self.lid..string.format("Trying Rearm again in %.2f sec", dt))
@@ -1589,7 +1638,7 @@ function ARMYGROUP:onafterEngageTarget(From, Event, To, Target, Speed, Formation
self.engage.Coordinate=UTILS.DeepCopy(self.engage.Target:GetCoordinate())
-- Get a coordinate close to the target.
local intercoord=self:GetCoordinate():GetIntermediateCoordinate(self.engage.Coordinate, 0.9)
local intercoord=self:GetCoordinate():GetIntermediateCoordinate(self.engage.Coordinate, 0.95)
-- Backup ROE and alarm state.
self.engage.roe=self:GetROE()
@@ -1752,6 +1801,21 @@ function ARMYGROUP:onafterCruise(From, Event, To, Speed, Formation)
end
--- On after "Hit" event.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @param Wrapper.Unit#UNIT Enemy Unit that hit the element or `nil`.
function ARMYGROUP:onafterHit(From, Event, To, Enemy)
self:T(self.lid..string.format("ArmyGroup hit by %s", Enemy and Enemy:GetName() or "unknown"))
if self.suppressionOn then
env.info(self.lid.."FF suppress")
self:_Suppress()
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-- Routing
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
@@ -1996,6 +2060,100 @@ function ARMYGROUP:FindNearestAmmoSupply(Radius)
return nil, nil
end
--- Suppress fire of the group by setting its ROE to weapon hold.
-- @param #ARMYGROUP self
function ARMYGROUP:_Suppress()
-- Current time.
local Tnow=timer.getTime()
-- Current ROE
local currROE=self:GetROE()
-- Get randomized time the unit is suppressed.
local sigma=(self.TsuppressMax-self.TsuppressMin)/4
-- Gaussian distribution.
local Tsuppress=UTILS.RandomGaussian(self.TsuppressAve,sigma,self.TsuppressMin, self.TsuppressMax)
-- Time at which the suppression is over.
local renew=true
if not self.TsuppressionOver then
-- Group is not suppressed currently.
self.TsuppressionOver=Tnow+Tsuppress
-- Group will hold their weapons.
self:SwitchROE(ENUMS.ROE.WeaponHold)
-- Backup ROE.
self.suppressionROE=currROE
else
-- Check if suppression is longer than current time.
if Tsuppress+Tnow > self.TsuppressionOver then
self.TsuppressionOver=Tnow+Tsuppress
else
renew=false
end
end
-- Recovery event will be called in Tsuppress seconds.
if renew then
self:__Unsuppressed(self.TsuppressionOver-Tnow)
end
-- Debug message.
self:T(self.lid..string.format("Suppressed for %d sec", Tsuppress))
end
--- Before "Recovered" event. Check if suppression time is over.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
-- @return #boolean
function ARMYGROUP:onbeforeUnsuppressed(From, Event, To)
-- Current time.
local Tnow=timer.getTime()
-- Debug info
self:T(self.lid..string.format("onbeforeRecovered: Time now: %d - Time over: %d", Tnow, self.TsuppressionOver))
-- Recovery is only possible if enough time since the last hit has passed.
if Tnow >= self.TsuppressionOver then
return true
else
return false
end
end
--- After "Recovered" event. Group has recovered and its ROE is set back to the "normal" unsuppressed state. Optionally the group is flared green.
-- @param #ARMYGROUP self
-- @param #string From From state.
-- @param #string Event Event.
-- @param #string To To state.
function ARMYGROUP:onafterUnsuppressed(From, Event, To)
-- Debug message.
local text=string.format("Group %s has recovered!", self:GetName())
MESSAGE:New(text, 10):ToAll()
self:T(self.lid..text)
-- Set ROE back to default.
self:SwitchROE(self.suppressionROE)
-- Flare unit green.
if true then
self.group:FlareGreen()
end
end
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------