Merge branch 'master' into funkyfranky

This commit is contained in:
funkyfranky 2017-08-02 21:28:46 +02:00
commit 36ea613f68
7 changed files with 260 additions and 111 deletions

View File

@ -222,6 +222,7 @@ function AI_A2A:New( AIGroup )
self:AddTransition( "*", "Return", "Returning" ) self:AddTransition( "*", "Return", "Returning" )
self:AddTransition( "*", "Hold", "Holding" )
self:AddTransition( "*", "Home", "Home" ) self:AddTransition( "*", "Home", "Home" )
self:AddTransition( "*", "LostControl", "LostControl" ) self:AddTransition( "*", "LostControl", "LostControl" )
self:AddTransition( "*", "Fuel", "Fuel" ) self:AddTransition( "*", "Fuel", "Fuel" )
@ -382,21 +383,34 @@ end
--- @param #AI_A2A self --- @param #AI_A2A self
function AI_A2A:onafterStatus() function AI_A2A:onafterStatus()
self:F()
self:F( " Checking Status" )
if self.Controllable and self.Controllable:IsAlive() then if self.Controllable and self.Controllable:IsAlive() then
local RTB = false local RTB = false
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() ) local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
self:F({DistanceFromHomeBase=DistanceFromHomeBase})
if DistanceFromHomeBase > self.DisengageRadius then if not self:Is( "Holding" ) and not self:Is( "Returning" ) then
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" ) local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
self:Home() self:F({DistanceFromHomeBase=DistanceFromHomeBase})
RTB = true
if DistanceFromHomeBase > self.DisengageRadius then
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
self:Hold( 300 )
RTB = false
end
end end
if self:Is( "Damaged" ) or self:Is( "LostControl" ) then
if DistanceFromHomeBase < 5000 then
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
self:Home( "Destroy" )
end
end
local Fuel = self.Controllable:GetUnit(1):GetFuel() local Fuel = self.Controllable:GetUnit(1):GetFuel()
self:F({Fuel=Fuel}) self:F({Fuel=Fuel})
@ -427,10 +441,15 @@ function AI_A2A:onafterStatus()
-- Check if planes went RTB and are out of control. -- Check if planes went RTB and are out of control.
if self.Controllable:HasTask() == false then if self.Controllable:HasTask() == false then
if not self:Is( "Started" ) and if not self:Is( "Started" ) and
not self:Is( "Stopped" ) then not self:Is( "Stopped" ) and
not self:Is( "Home" ) then
if self.IdleCount >= 2 then if self.IdleCount >= 2 then
self:E( self.Controllable:GetName() .. " control lost! " ) if Damage ~= InitialLife then
self:LostControl() self:Damaged()
else
self:E( self.Controllable:GetName() .. " control lost! " )
self:LostControl()
end
else else
self.IdleCount = self.IdleCount + 1 self.IdleCount = self.IdleCount + 1
end end
@ -451,11 +470,30 @@ end
--- @param Wrapper.Group#GROUP AIGroup --- @param Wrapper.Group#GROUP AIGroup
function AI_A2A.RTBRoute( AIGroup ) function AI_A2A.RTBRoute( AIGroup )
AIGroup:E( { "RTBRoute:", AIGroup:GetName() } ) AIGroup:E( { "AI_A2A.RTBRoute:", AIGroup:GetName() } )
local _AI_A2A = AIGroup:GetState( AIGroup, "AI_A2A" ) -- #AI_A2A
_AI_A2A:__RTB( 0.5 ) if AIGroup:IsAlive() then
local _AI_A2A = AIGroup:GetState( AIGroup, "AI_A2A" ) -- #AI_A2A
_AI_A2A:__RTB( 0.5 )
local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
AIGroup:SetTask( Task )
end
end end
--- @param Wrapper.Group#GROUP AIGroup
function AI_A2A.RTBHold( AIGroup )
AIGroup:E( { "AI_A2A.RTBHold:", AIGroup:GetName() } )
if AIGroup:IsAlive() then
local _AI_A2A = AIGroup:GetState( AIGroup, "AI_A2A" ) -- #AI_A2A
_AI_A2A:__RTB( 0.5 )
_AI_A2A:Return()
local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
AIGroup:SetTask( Task )
end
end
--- @param #AI_A2A self --- @param #AI_A2A self
@ -468,8 +506,6 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
self:E( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" ) self:E( "Group " .. AIGroup:GetName() .. " ... RTB! ( " .. self:GetState() .. " )" )
self.CheckStatus = false
self:ClearTargetDistance() self:ClearTargetDistance()
AIGroup:ClearTasks() AIGroup:ClearTasks()
@ -486,6 +522,7 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
local ToAirbaseCoord = CurrentCoord:Translate( 5000, ToAirbaseAngle ) local ToAirbaseCoord = CurrentCoord:Translate( 5000, ToAirbaseAngle )
if Distance < 5000 then if Distance < 5000 then
self:E( "RTB and near the airbase!" )
self:Home() self:Home()
return return
end end
@ -501,6 +538,7 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
self:F( { Angle = ToAirbaseAngle, ToTargetSpeed = ToTargetSpeed } ) self:F( { Angle = ToAirbaseAngle, ToTargetSpeed = ToTargetSpeed } )
self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } ) self:T2( { self.MinSpeed, self.MaxSpeed, ToTargetSpeed } )
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint EngageRoute[#EngageRoute+1] = ToPatrolRoutePoint
AIGroup:OptionROEHoldFire() AIGroup:OptionROEHoldFire()
@ -511,12 +549,13 @@ function AI_A2A:onafterRTB( AIGroup, From, Event, To )
local Tasks = {} local Tasks = {}
Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A.RTBRoute" ) Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A.RTBRoute" )
EngageRoute[1].task = AIGroup:TaskCombo( Tasks ) Tasks[#Tasks+1] = AIGroup:TaskOrbitCircle( 4000, 350 )
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( Tasks )
AIGroup:SetState( AIGroup, "AI_A2A", self ) AIGroup:SetState( AIGroup, "AI_A2A", self )
--- NOW ROUTE THE GROUP! --- NOW ROUTE THE GROUP!
AIGroup:WayPointExecute( 1, 0 ) AIGroup:SetTask( AIGroup:TaskRoute( EngageRoute ), 1 )
end end
@ -534,6 +573,30 @@ function AI_A2A:onafterHome( AIGroup, From, Event, To )
end end
--- @param #AI_A2A self
-- @param Wrapper.Group#GROUP AIGroup
function AI_A2A:onafterHold( AIGroup, From, Event, To, HoldTime )
self:F( { AIGroup, From, Event, To } )
self:E( "Group " .. self.Controllable:GetName() .. " ... Holding! ( " .. self:GetState() .. " )" )
if AIGroup and AIGroup:IsAlive() then
local OrbitTask = AIGroup:TaskOrbitCircle( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ), self.PatrolMinSpeed )
local TimedOrbitTask = AIGroup:TaskControlled( OrbitTask, AIGroup:TaskCondition( nil, nil, nil, nil, HoldTime , nil ) )
local RTBTask = AIGroup:TaskFunction( 1, 1, "AI_A2A.RTBHold" )
local OrbitHoldTask = AIGroup:TaskOrbitCircle( 4000, self.PatrolMinSpeed )
AIGroup:SetState( AIGroup, "AI_A2A", self )
AIGroup:SetTask( AIGroup:TaskCombo( { TimedOrbitTask, RTBTask, OrbitHoldTask } ), 0 )
end
end
--- @param #AI_A2A self --- @param #AI_A2A self

View File

@ -350,8 +350,15 @@ end
--- @param Wrapper.Group#GROUP AIGroup --- @param Wrapper.Group#GROUP AIGroup
function AI_A2A_CAP.AttackRoute( AIGroup ) function AI_A2A_CAP.AttackRoute( AIGroup )
local EngageZone = AIGroup:GetState( AIGroup, "AI_A2A_CAP" ) -- AI.AI_Cap#AI_A2A_CAP AIGroup:E( { "AI_A2A_CAP.AttackRoute:", AIGroup:GetName() } )
EngageZone:__Engage( 0.5 )
if AIGroup:IsAlive() then
local _AI_A2A_CAP = AIGroup:GetState( AIGroup, "AI_A2A_CAP" ) -- AI.AI_Cap#AI_A2A_CAP
_AI_A2A_CAP:__Engage( 0.5 )
--local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
--AIGroup:SetTask( Task )
end
end end
--- @param #AI_A2A_CAP self --- @param #AI_A2A_CAP self
@ -427,10 +434,6 @@ function AI_A2A_CAP:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
end end
end end
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
self.Controllable:WayPointInitialize( EngageRoute )
if #AttackTasks == 0 then if #AttackTasks == 0 then
self:E("No targets found -> Going back to Patrolling") self:E("No targets found -> Going back to Patrolling")
self:__Abort( 0.5 ) self:__Abort( 0.5 )
@ -438,17 +441,17 @@ function AI_A2A_CAP:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
AIGroup:OptionROEOpenFire() AIGroup:OptionROEOpenFire()
AIGroup:OptionROTPassiveDefense() AIGroup:OptionROTPassiveDefense()
AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( 1, #AttackTasks, "AI_A2A_CAP.AttackRoute" ) AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A_CAP.AttackRoute" )
AttackTasks[#AttackTasks+1] = AIGroup:TaskOrbitCircle( 4000, self.PatrolMinSpeed ) --AttackTasks[#AttackTasks+1] = AIGroup:TaskOrbitCircle( AIGroup:GetHeight(), self.PatrolMinSpeed )
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( AttackTasks ) EngageRoute[1].task = AIGroup:TaskCombo( AttackTasks )
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
AIGroup:SetState( AIGroup, "AI_A2A_CAP", self ) AIGroup:SetState( AIGroup, "AI_A2A_CAP", self )
end end
--- NOW ROUTE THE GROUP! --- NOW ROUTE THE GROUP!
AIGroup:WayPointExecute( 1, 0 ) AIGroup:SetTask( AIGroup:TaskRoute( EngageRoute ), 1 )
end end
else else
self:E("No targets found -> Going back to Patrolling") self:E("No targets found -> Going back to Patrolling")

View File

@ -460,6 +460,8 @@ do -- AI_A2A_DISPATCHER
-- For example with a group setting of 2, if 3 targets are detected and cannot be engaged by CAP or any airborne flight, -- For example with a group setting of 2, if 3 targets are detected and cannot be engaged by CAP or any airborne flight,
-- a GCI needs to be started, the GCI flights will be grouped as follows: Group 1 of 2 flights and Group 2 of one flight! -- a GCI needs to be started, the GCI flights will be grouped as follows: Group 1 of 2 flights and Group 2 of one flight!
-- --
-- Even more ... If one target has been detected, and the overhead is 1.5, grouping is 1, then two groups of planes will be spawned, with one unit each!
--
-- The **grouping value is set for a Squadron**, and can be **dynamically adjusted** during mission execution, so to adjust the defense flights grouping when the tactical situation changes. -- The **grouping value is set for a Squadron**, and can be **dynamically adjusted** during mission execution, so to adjust the defense flights grouping when the tactical situation changes.
-- --
-- ### 6.4. Overhead and Balance the effectiveness of the air defenses in case of GCI -- ### 6.4. Overhead and Balance the effectiveness of the air defenses in case of GCI
@ -484,6 +486,8 @@ do -- AI_A2A_DISPATCHER
-- The amount of defending units is calculated by multiplying the amount of detected attacking planes as part of the detected group -- The amount of defending units is calculated by multiplying the amount of detected attacking planes as part of the detected group
-- multiplied by the Overhead and rounded up to the smallest integer. -- multiplied by the Overhead and rounded up to the smallest integer.
-- --
-- For example ... If one target has been detected, and the overhead is 1.5, grouping is 1, then two groups of planes will be spawned, with one unit each!
--
-- The **overhead value is set for a Squadron**, and can be **dynamically adjusted** during mission execution, so to adjust the defense overhead when the tactical situation changes. -- The **overhead value is set for a Squadron**, and can be **dynamically adjusted** during mission execution, so to adjust the defense overhead when the tactical situation changes.
-- --
-- ## 7. Setup a squadron for CAP -- ## 7. Setup a squadron for CAP
@ -772,6 +776,8 @@ do -- AI_A2A_DISPATCHER
self:SetEngageRadius() self:SetEngageRadius()
self:SetGciRadius() self:SetGciRadius()
self:SetIntercept( 300 ) -- A default intercept delay time of 300 seconds.
self:SetDisengageRadius( 100000 ) -- The default disengage radius is 100 km.
self:SetDefaultTakeoff( AI_A2A_DISPATCHER.Takeoff.Air ) self:SetDefaultTakeoff( AI_A2A_DISPATCHER.Takeoff.Air )
self:SetDefaultLanding( AI_A2A_DISPATCHER.Landing.NearAirbase ) self:SetDefaultLanding( AI_A2A_DISPATCHER.Landing.NearAirbase )
@ -781,8 +787,6 @@ do -- AI_A2A_DISPATCHER
self:SetDefaultDamageThreshold( 0.4 ) -- When 40% of damage, go RTB. self:SetDefaultDamageThreshold( 0.4 ) -- When 40% of damage, go RTB.
self:SetDefaultCapTimeInterval( 180, 600 ) -- Between 180 and 600 seconds. self:SetDefaultCapTimeInterval( 180, 600 ) -- Between 180 and 600 seconds.
self:SetDefaultCapLimit( 1 ) -- Maximum one CAP per squadron. self:SetDefaultCapLimit( 1 ) -- Maximum one CAP per squadron.
self:SetIntercept( 300 ) -- A default intercept delay time of 300 seconds.
self:SetDisengageRadius( 100000 ) -- The default disengage radius is 100 km.
self:AddTransition( "Started", "Assign", "Started" ) self:AddTransition( "Started", "Assign", "Started" )
@ -1478,10 +1482,16 @@ do -- AI_A2A_DISPATCHER
Cap.CapLimit = CapLimit Cap.CapLimit = CapLimit
Cap.Scheduler = Cap.Scheduler or SCHEDULER:New( self ) Cap.Scheduler = Cap.Scheduler or SCHEDULER:New( self )
local Scheduler = Cap.Scheduler -- Core.Scheduler#SCHEDULER local Scheduler = Cap.Scheduler -- Core.Scheduler#SCHEDULER
local ScheduleID = Cap.ScheduleID
local Variance = ( Cap.HighInterval - Cap.LowInterval ) / 2 local Variance = ( Cap.HighInterval - Cap.LowInterval ) / 2
local Median = Cap.LowInterval + Variance local Median = Cap.LowInterval + Variance
local Randomization = Variance / Median local Randomization = Variance / Median
Scheduler:Schedule(self, self.SchedulerCAP, { SquadronName }, Median, Median, Randomization )
if ScheduleID then
Scheduler:Stop( ScheduleID )
end
Cap.ScheduleID = Scheduler:Schedule( self, self.SchedulerCAP, { SquadronName }, Median, Median, Randomization )
else else
error( "This squadron does not exist:" .. SquadronName ) error( "This squadron does not exist:" .. SquadronName )
end end
@ -2163,11 +2173,11 @@ do -- AI_A2A_DISPATCHER
--- @param #AI_A2A_DISPATCHER self --- @param #AI_A2A_DISPATCHER self
function AI_A2A_DISPATCHER:AddDefenderToSquadron( Squadron, Defender ) function AI_A2A_DISPATCHER:AddDefenderToSquadron( Squadron, Defender, Size )
self.Defenders = self.Defenders or {} self.Defenders = self.Defenders or {}
local DefenderName = Defender:GetName() local DefenderName = Defender:GetName()
self.Defenders[ DefenderName ] = Squadron self.Defenders[ DefenderName ] = Squadron
Squadron.Resources = Squadron.Resources - Defender:GetSize() Squadron.Resources = Squadron.Resources - Size
self:F( { DefenderName = DefenderName, SquadronResources = Squadron.Resources } ) self:F( { DefenderName = DefenderName, SquadronResources = Squadron.Resources } )
end end
@ -2324,7 +2334,7 @@ do -- AI_A2A_DISPATCHER
local TakeoffMethod = self:GetSquadronTakeoff( SquadronName ) local TakeoffMethod = self:GetSquadronTakeoff( SquadronName )
local DefenderCAP = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod ) local DefenderCAP = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod )
self:AddDefenderToSquadron( DefenderSquadron, DefenderCAP ) self:AddDefenderToSquadron( DefenderSquadron, DefenderCAP, DefenderGrouping )
if DefenderCAP then if DefenderCAP then
@ -2367,13 +2377,19 @@ do -- AI_A2A_DISPATCHER
end end
--- @param #AI_A2A_DISPATCHER self --- @param #AI_A2A_DISPATCHER self
function Fsm:onafterHome( Defender, From, Event, To ) function Fsm:onafterHome( Defender, From, Event, To, Action )
self:F({"CAP Home"}) self:F({"CAP Home"})
self:GetParent(self).onafterHome( self, Defender, From, Event, To ) self:GetParent(self).onafterHome( self, Defender, From, Event, To )
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
local AIGroup = self:GetControllable() local AIGroup = self:GetControllable()
local Squadron = Dispatcher:GetSquadronFromDefender( AIGroup ) local Squadron = Dispatcher:GetSquadronFromDefender( AIGroup )
if Action and Action == "Destroy" then
Dispatcher:RemoveDefenderFromSquadron( Squadron, AIGroup )
AIGroup:Destroy()
end
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then
Dispatcher:RemoveDefenderFromSquadron( Squadron, AIGroup ) Dispatcher:RemoveDefenderFromSquadron( Squadron, AIGroup )
AIGroup:Destroy() AIGroup:Destroy()
@ -2407,18 +2423,20 @@ do -- AI_A2A_DISPATCHER
local ClosestDistance = 0 local ClosestDistance = 0
local ClosestDefenderSquadronName = nil local ClosestDefenderSquadronName = nil
while( DefendersCount > 0 ) do local BreakLoop = false
while( DefendersCount > 0 and not BreakLoop ) do
for SquadronName, DefenderSquadron in pairs( self.DefenderSquadrons or {} ) do for SquadronName, DefenderSquadron in pairs( self.DefenderSquadrons or {} ) do
for InterceptID, Intercept in pairs( DefenderSquadron.Gci or {} ) do for InterceptID, Intercept in pairs( DefenderSquadron.Gci or {} ) do
self:E( { DefenderSquadron } ) --self:E( { DefenderSquadron } )
local SpawnCoord = DefenderSquadron.Airbase:GetCoordinate() -- Core.Point#COORDINATE local SpawnCoord = DefenderSquadron.Airbase:GetCoordinate() -- Core.Point#COORDINATE
--local TargetCoord = AttackerSet:GetFirst():GetCoordinate() --local TargetCoord = AttackerSet:GetFirst():GetCoordinate()
local TargetCoord = DetectedItem.InterceptCoord local TargetCoord = DetectedItem.InterceptCoord
if TargetCoord then if TargetCoord then
local Distance = SpawnCoord:Get2DDistance( TargetCoord ) local Distance = SpawnCoord:Get2DDistance( TargetCoord )
self:F( { Distance = Distance, TargetCoord = TargetCoord } ) self:F( { Distance = Distance, TargetCoord = TargetCoord } )
if ClosestDistance == 0 or Distance < ClosestDistance then if ClosestDistance == 0 or Distance < ClosestDistance then
@ -2446,67 +2464,101 @@ do -- AI_A2A_DISPATCHER
local DefenderGrouping = DefenderSquadron.Grouping or self.DefenderDefault.Grouping local DefenderGrouping = DefenderSquadron.Grouping or self.DefenderDefault.Grouping
local DefendersNeeded = math.ceil( DefendersCount * DefenderOverhead ) local DefendersNeeded = math.ceil( DefendersCount * DefenderOverhead )
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] self:F( { DefaultOverhead = self.DefenderDefault.Overhead, Overhead = DefenderOverhead } )
if DefenderGrouping then self:F( { DefaultGrouping = self.DefenderDefault.Grouping, Grouping = DefenderGrouping } )
Spawn:InitGrouping( ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded ) self:F( { DefendersCount = DefendersCount, DefendersNeeded = DefendersNeeded } )
else
Spawn:InitGrouping()
end
local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName ) while ( DefendersNeeded > 0 ) do
local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod )
self:F( { GCIDefender = DefenderGCI:GetName() } )
self:AddDefenderToSquadron( DefenderSquadron, DefenderGCI ) local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Functional.Spawn#SPAWN
local DefenderGrouping = ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded
if DefenderGrouping then
if DefenderGCI then Spawn:InitGrouping( DefenderGrouping )
else
DefendersCount = DefendersCount - DefenderGCI:GetSize() Spawn:InitGrouping()
local Fsm = AI_A2A_GCI:New( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed )
Fsm:SetDispatcher( self )
Fsm:SetHomeAirbase( DefenderSquadron.Airbase )
Fsm:SetFuelThreshold( self.DefenderDefault.FuelThreshold, 60 )
Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold )
Fsm:SetDisengageRadius( self.DisengageRadius )
Fsm:Start()
Fsm:__Engage( 2, DetectedItem.Set ) -- Engage on the TargetSetUnit
self:SetDefenderTask( DefenderGCI, "GCI", Fsm, DetectedItem )
function Fsm:onafterRTB( Defender, From, Event, To )
self:F({"GCI RTB"})
self:GetParent(self).onafterRTB( self, Defender, From, Event, To )
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
local AIGroup = self:GetControllable()
Dispatcher:ClearDefenderTaskTarget( AIGroup )
end end
--- @param #AI_A2A_DISPATCHER self local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName )
function Fsm:onafterHome( Defender, From, Event, To ) local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod ) -- Wrapper.Group#GROUP
self:F({"GCI Home"}) self:F( { GCIDefender = DefenderGCI:GetName() } )
self:GetParent(self).onafterHome( self, Defender, From, Event, To )
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER DefendersNeeded = DefendersNeeded - DefenderGrouping
local AIGroup = self:GetControllable()
local Squadron = Dispatcher:GetSquadronFromDefender( AIGroup ) self:AddDefenderToSquadron( DefenderSquadron, DefenderGCI, DefenderGrouping )
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then
Dispatcher:RemoveDefenderFromSquadron( Squadron, AIGroup ) if DefenderGCI then
AIGroup:Destroy()
DefendersCount = DefendersCount - DefenderGrouping
local Fsm = AI_A2A_GCI:New( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed )
Fsm:SetDispatcher( self )
Fsm:SetHomeAirbase( DefenderSquadron.Airbase )
Fsm:SetFuelThreshold( self.DefenderDefault.FuelThreshold, 60 )
Fsm:SetDamageThreshold( self.DefenderDefault.DamageThreshold )
Fsm:SetDisengageRadius( self.DisengageRadius )
Fsm:Start()
Fsm:__Engage( 2, DetectedItem.Set ) -- Engage on the TargetSetUnit
self:SetDefenderTask( DefenderGCI, "GCI", Fsm, DetectedItem )
function Fsm:onafterRTB( Defender, From, Event, To )
self:F({"GCI RTB"})
self:GetParent(self).onafterRTB( self, Defender, From, Event, To )
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
local AIGroup = self:GetControllable()
Dispatcher:ClearDefenderTaskTarget( AIGroup )
end end
end
end --- @param #AI_A2A_DISPATCHER self
function Fsm:onafterLostControl( Defender, From, Event, To )
self:F({"GCI Home"})
self:GetParent(self).onafterHome( self, Defender, From, Event, To )
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
local AIGroup = self:GetControllable() -- Wrapper.Group#GROUP
local Squadron = Dispatcher:GetSquadronFromDefender( AIGroup )
if AIGroup:IsAboveRunway() then
Dispatcher:RemoveDefenderFromSquadron( Squadron, AIGroup )
AIGroup:Destroy()
end
end
--- @param #AI_A2A_DISPATCHER self
function Fsm:onafterHome( Defender, From, Event, To, Action )
self:F({"GCI Home"})
self:GetParent(self).onafterHome( self, Defender, From, Event, To )
local Dispatcher = self:GetDispatcher() -- #AI_A2A_DISPATCHER
local AIGroup = self:GetControllable()
local Squadron = Dispatcher:GetSquadronFromDefender( AIGroup )
if Action and Action == "Destroy" then
Dispatcher:RemoveDefenderFromSquadron( Squadron, AIGroup )
AIGroup:Destroy()
end
if Dispatcher:GetSquadronLanding( Squadron.Name ) == AI_A2A_DISPATCHER.Landing.NearAirbase then
Dispatcher:RemoveDefenderFromSquadron( Squadron, AIGroup )
AIGroup:Destroy()
end
end
end -- if DefenderGCI then
end -- while ( DefendersNeeded > 0 ) do
end end
else
-- No more resources, try something else.
-- Subject for a later enhancement to try to depart from another squadron and disable this one.
BreakLoop = true
break
end end
else else
-- There isn't any closest airbase anymore, break the loop. -- There isn't any closest airbase anymore, break the loop.
break break
end end
end end -- if DefenderSquadron then
end end
@ -2640,7 +2692,16 @@ do -- AI_A2A_DISPATCHER
for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do for Defender, DefenderTask in pairs( self:GetDefenderTasks() ) do
local Defender = Defender -- Wrapper.Group#GROUP local Defender = Defender -- Wrapper.Group#GROUP
if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then if DefenderTask.Target and DefenderTask.Target.Index == DetectedItem.Index then
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) %s", Defender:GetName(), DefenderTask.Type, DefenderTask.Fsm:GetState(), Defender:GetSize(), Defender:HasTask() == true and "Executing" or "Idle" ) ) local Fuel = Defender:GetUnit(1):GetFuel() * 100
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
Defender:GetName(),
DefenderTask.Type,
DefenderTask.Fsm:GetState(),
Defender:GetSize(),
Fuel,
Damage,
Defender:HasTask() == true and "Executing" or "Idle" ) )
end end
end end
end end
@ -2654,7 +2715,16 @@ do -- AI_A2A_DISPATCHER
local Defender = Defender -- Wrapper.Group#GROUP local Defender = Defender -- Wrapper.Group#GROUP
if not DefenderTask.Target then if not DefenderTask.Target then
local DefenderHasTask = Defender:HasTask() local DefenderHasTask = Defender:HasTask()
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) %s", Defender:GetName(), DefenderTask.Type, DefenderTask.Fsm:GetState(), Defender:GetSize(), Defender:HasTask() == true and "Executing" or "Idle" ) ) local Fuel = Defender:GetUnit(1):GetFuel() * 100
local Damage = Defender:GetLife() / Defender:GetLife0() * 100
Report:Add( string.format( " - %s ( %s - %s ): ( #%d ) F: %3d, D:%3d - %s",
Defender:GetName(),
DefenderTask.Type,
DefenderTask.Fsm:GetState(),
Defender:GetSize(),
Fuel,
Damage,
Defender:HasTask() == true and "Executing" or "Idle" ) )
end end
end end
Report:Add( string.format( "\n - %d Tasks", TaskCount ) ) Report:Add( string.format( "\n - %d Tasks", TaskCount ) )

View File

@ -311,11 +311,17 @@ end
-- todo: need to fix this global function -- todo: need to fix this global function
--- @param Wrapper.Group#GROUP AIControllable --- @param Wrapper.Group#GROUP AIControllable
function AI_A2A_GCI.InterceptRoute( AIControllable ) function AI_A2A_GCI.InterceptRoute( AIGroup )
local EngageZone = AIControllable:GetState( AIControllable, "EngageZone" ) -- AI.AI_Cap#AI_A2A_GCI AIGroup:E( { "AI_A2A_GCI.InterceptRoute:", AIGroup:GetName() } )
EngageZone:E( "NewEngageRoute" )
EngageZone:__Engage( 0.5 ) if AIGroup:IsAlive() then
local _AI_A2A_GCI = AIGroup:GetState( AIGroup, "AI_A2A_GCI" ) -- AI.AI_Cap#AI_A2A_GCI
_AI_A2A_GCI:__Engage( 0.5 )
--local Task = AIGroup:TaskOrbitCircle( 4000, 400 )
--AIGroup:SetTask( Task )
end
end end
--- @param #AI_A2A_GCI self --- @param #AI_A2A_GCI self
@ -411,16 +417,17 @@ function AI_A2A_GCI:onafterEngage( AIGroup, From, Event, To, AttackSetUnit )
AIGroup:OptionROEOpenFire() AIGroup:OptionROEOpenFire()
AIGroup:OptionROTPassiveDefense() AIGroup:OptionROTPassiveDefense()
AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( 1, #AttackTasks, "AI_A2A_GCI.InterceptRoute" ) AttackTasks[#AttackTasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A_GCI.InterceptRoute" )
AttackTasks[#AttackTasks+1] = AIGroup:TaskOrbitCircle( 4000, self.EngageMinSpeed ) --AttackTasks[#AttackTasks+1] = AIGroup:TaskOrbitCircle( AIGroup:GetHeight(), self.EngageMinSpeed )
EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( AttackTasks ) EngageRoute[#EngageRoute].task = AIGroup:TaskCombo( AttackTasks )
--- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ... --- Do a trick, link the NewEngageRoute function of the object to the AIControllable in a temporary variable ...
AIGroup:SetState( AIGroup, "EngageZone", self ) AIGroup:SetState( AIGroup, "AI_A2A_GCI", self )
end end
--- NOW ROUTE THE GROUP! --- NOW ROUTE THE GROUP!
AIGroup:WayPointExecute( 1, 0 ) --AIGroup:ClearTasks()
AIGroup:SetTask( AIGroup:TaskRoute( EngageRoute ), 1 )
end end
else else

View File

@ -317,8 +317,13 @@ end
-- Note that this method is required, as triggers the next route when patrolling for the Controllable. -- Note that this method is required, as triggers the next route when patrolling for the Controllable.
function AI_A2A_PATROL.PatrolRoute( AIGroup ) function AI_A2A_PATROL.PatrolRoute( AIGroup )
local _AI_A2A_Patrol = AIGroup:GetState( AIGroup, "AI_A2A_PATROL" ) -- #AI_A2A_PATROL AIGroup:E( { "AI_A2A_PATROL.PatrolRoute:", AIGroup:GetName() } )
_AI_A2A_Patrol:Route()
if AIGroup:IsAlive() then
local _AI_A2A_Patrol = AIGroup:GetState( AIGroup, "AI_A2A_PATROL" ) -- #AI_A2A_PATROL
_AI_A2A_Patrol:Route()
end
end end
@ -347,7 +352,7 @@ function AI_A2A_PATROL:onafterRoute( AIGroup, From, Event, To )
local CurrentCoord = AIGroup:GetCoordinate() local CurrentCoord = AIGroup:GetCoordinate()
local ToTargetCoord = self.PatrolZone:GetRandomPointVec2() local ToTargetCoord = self.PatrolZone:GetRandomPointVec2()
ToTargetCoord:SetAlt(math.random( self.PatrolFloorAltitude,self.PatrolCeilingAltitude ) ) ToTargetCoord:SetAlt( math.random( self.PatrolFloorAltitude, self.PatrolCeilingAltitude ) )
self:SetTargetDistance( ToTargetCoord ) -- For RTB status check self:SetTargetDistance( ToTargetCoord ) -- For RTB status check
local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed ) local ToTargetSpeed = math.random( self.PatrolMinSpeed, self.PatrolMaxSpeed )
@ -364,9 +369,6 @@ function AI_A2A_PATROL:onafterRoute( AIGroup, From, Event, To )
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint PatrolRoute[#PatrolRoute+1] = ToPatrolRoutePoint
--- Now we're going to do something special, we're going to call a function from a waypoint action at the AIControllable...
AIGroup:WayPointInitialize( PatrolRoute )
local Tasks = {} local Tasks = {}
Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A_PATROL.PatrolRoute" ) Tasks[#Tasks+1] = AIGroup:TaskFunction( 1, 1, "AI_A2A_PATROL.PatrolRoute" )
@ -375,8 +377,11 @@ function AI_A2A_PATROL:onafterRoute( AIGroup, From, Event, To )
--- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the AIControllable in a temporary variable ... --- Do a trick, link the NewPatrolRoute function of the PATROLGROUP object to the AIControllable in a temporary variable ...
AIGroup:SetState( AIGroup, "AI_A2A_PATROL", self ) AIGroup:SetState( AIGroup, "AI_A2A_PATROL", self )
AIGroup:OptionROEReturnFire()
AIGroup:OptionROTPassiveDefense()
--- NOW ROUTE THE GROUP! --- NOW ROUTE THE GROUP!
AIGroup:WayPointExecute( 1, 2 ) AIGroup:SetTask( AIGroup:TaskRoute( PatrolRoute ), 0.5 )
end end
end end

View File

@ -79,8 +79,8 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments self.Schedule[Scheduler][self.CallID].Arguments = ScheduleArguments
self.Schedule[Scheduler][self.CallID].StartTime = timer.getTime() + ( Start or 0 ) self.Schedule[Scheduler][self.CallID].StartTime = timer.getTime() + ( Start or 0 )
self.Schedule[Scheduler][self.CallID].Start = Start + .1 self.Schedule[Scheduler][self.CallID].Start = Start + .1
self.Schedule[Scheduler][self.CallID].Repeat = Repeat self.Schedule[Scheduler][self.CallID].Repeat = Repeat or 0
self.Schedule[Scheduler][self.CallID].Randomize = Randomize self.Schedule[Scheduler][self.CallID].Randomize = Randomize or 0
self.Schedule[Scheduler][self.CallID].Stop = Stop self.Schedule[Scheduler][self.CallID].Stop = Stop
self:T3( self.Schedule[Scheduler][self.CallID] ) self:T3( self.Schedule[Scheduler][self.CallID] )
@ -133,10 +133,10 @@ function SCHEDULEDISPATCHER:AddSchedule( Scheduler, ScheduleFunction, ScheduleAr
end end
local CurrentTime = timer.getTime() local CurrentTime = timer.getTime()
local StartTime = CurrentTime + Start local StartTime = Schedule.StartTime
if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then if Status and (( Result == nil ) or ( Result and Result ~= false ) ) then
if Repeat ~= 0 and ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) then if Repeat ~= 0 and ( ( Stop == 0 ) or ( Stop ~= 0 and CurrentTime <= StartTime + Stop ) ) then
local ScheduleTime = local ScheduleTime =
CurrentTime + CurrentTime +
Repeat + Repeat +
@ -182,10 +182,11 @@ function SCHEDULEDISPATCHER:Start( Scheduler, CallID )
-- Only start when there is no ScheduleID defined! -- Only start when there is no ScheduleID defined!
-- This prevents to "Start" the scheduler twice with the same CallID... -- This prevents to "Start" the scheduler twice with the same CallID...
if not Schedule[CallID].ScheduleID then if not Schedule[CallID].ScheduleID then
Schedule[CallID].StartTime = timer.getTime() -- Set the StartTime field to indicate when the scheduler started.
Schedule[CallID].ScheduleID = timer.scheduleFunction( Schedule[CallID].ScheduleID = timer.scheduleFunction(
Schedule[CallID].CallHandler, Schedule[CallID].CallHandler,
CallID, CallID,
timer.getTime() + Schedule[CallID].Start timer.getTime() + Schedule[CallID].Start + math.random( - ( Schedule[CallID].Randomize * Schedule[CallID].Repeat / 2 ), ( Schedule[CallID].Randomize * Schedule[CallID].Repeat / 2 ) )
) )
end end
else else

View File

@ -340,7 +340,7 @@ function CONTROLLABLE:SetTask( DCSTask, WaitTime )
-- Therefore we schedule the functions to set the mission and options for the Controllable. -- Therefore we schedule the functions to set the mission and options for the Controllable.
-- Controller.setTask( Controller, DCSTask ) -- Controller.setTask( Controller, DCSTask )
if not WaitTime then if not WaitTime or WaitTime == 0 then
Controller:setTask( DCSTask ) Controller:setTask( DCSTask )
else else
self.TaskScheduler:Schedule( Controller, Controller.setTask, { DCSTask }, WaitTime ) self.TaskScheduler:Schedule( Controller, Controller.setTask, { DCSTask }, WaitTime )