mirror of
https://github.com/FlightControl-Master/MOOSE.git
synced 2025-10-29 16:58:06 +00:00
Merge branch 'master' into funkyfranky
This commit is contained in:
commit
36ea613f68
@ -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,20 +383,33 @@ 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() )
|
||||||
|
|
||||||
|
if not self:Is( "Holding" ) and not self:Is( "Returning" ) then
|
||||||
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
|
local DistanceFromHomeBase = self.HomeAirbase:GetCoordinate():Get2DDistance( self.Controllable:GetCoordinate() )
|
||||||
self:F({DistanceFromHomeBase=DistanceFromHomeBase})
|
self:F({DistanceFromHomeBase=DistanceFromHomeBase})
|
||||||
|
|
||||||
if DistanceFromHomeBase > self.DisengageRadius then
|
if DistanceFromHomeBase > self.DisengageRadius then
|
||||||
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
|
self:E( self.Controllable:GetName() .. " is too far from home base, RTB!" )
|
||||||
self:Home()
|
self:Hold( 300 )
|
||||||
RTB = true
|
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()
|
||||||
@ -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
|
||||||
|
if Damage ~= InitialLife then
|
||||||
|
self:Damaged()
|
||||||
|
else
|
||||||
self:E( self.Controllable:GetName() .. " control lost! " )
|
self:E( self.Controllable:GetName() .. " control lost! " )
|
||||||
self:LostControl()
|
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() } )
|
||||||
|
|
||||||
|
if AIGroup:IsAlive() then
|
||||||
local _AI_A2A = AIGroup:GetState( AIGroup, "AI_A2A" ) -- #AI_A2A
|
local _AI_A2A = AIGroup:GetState( AIGroup, "AI_A2A" ) -- #AI_A2A
|
||||||
_AI_A2A:__RTB( 0.5 )
|
_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
|
||||||
|
|||||||
@ -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")
|
||||||
|
|||||||
@ -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,12 +2423,14 @@ 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
|
||||||
@ -2446,23 +2464,31 @@ 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 } )
|
||||||
|
self:F( { DefaultGrouping = self.DefenderDefault.Grouping, Grouping = DefenderGrouping } )
|
||||||
|
self:F( { DefendersCount = DefendersCount, DefendersNeeded = DefendersNeeded } )
|
||||||
|
|
||||||
|
while ( DefendersNeeded > 0 ) do
|
||||||
|
|
||||||
|
local Spawn = DefenderSquadron.Spawn[ math.random( 1, #DefenderSquadron.Spawn ) ] -- Functional.Spawn#SPAWN
|
||||||
|
local DefenderGrouping = ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded
|
||||||
if DefenderGrouping then
|
if DefenderGrouping then
|
||||||
Spawn:InitGrouping( ( DefenderGrouping < DefendersNeeded ) and DefenderGrouping or DefendersNeeded )
|
Spawn:InitGrouping( DefenderGrouping )
|
||||||
else
|
else
|
||||||
Spawn:InitGrouping()
|
Spawn:InitGrouping()
|
||||||
end
|
end
|
||||||
|
|
||||||
local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName )
|
local TakeoffMethod = self:GetSquadronTakeoff( ClosestDefenderSquadronName )
|
||||||
local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod )
|
local DefenderGCI = Spawn:SpawnAtAirbase( DefenderSquadron.Airbase, TakeoffMethod ) -- Wrapper.Group#GROUP
|
||||||
self:F( { GCIDefender = DefenderGCI:GetName() } )
|
self:F( { GCIDefender = DefenderGCI:GetName() } )
|
||||||
|
|
||||||
self:AddDefenderToSquadron( DefenderSquadron, DefenderGCI )
|
DefendersNeeded = DefendersNeeded - DefenderGrouping
|
||||||
|
|
||||||
|
self:AddDefenderToSquadron( DefenderSquadron, DefenderGCI, DefenderGrouping )
|
||||||
|
|
||||||
if DefenderGCI then
|
if DefenderGCI then
|
||||||
|
|
||||||
DefendersCount = DefendersCount - DefenderGCI:GetSize()
|
DefendersCount = DefendersCount - DefenderGrouping
|
||||||
|
|
||||||
local Fsm = AI_A2A_GCI:New( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed )
|
local Fsm = AI_A2A_GCI:New( DefenderGCI, Gci.EngageMinSpeed, Gci.EngageMaxSpeed )
|
||||||
Fsm:SetDispatcher( self )
|
Fsm:SetDispatcher( self )
|
||||||
@ -2487,26 +2513,52 @@ 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: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:F({"GCI 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()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end -- if DefenderGCI then
|
||||||
|
end -- while ( DefendersNeeded > 0 ) do
|
||||||
end
|
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 ) )
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -317,10 +317,15 @@ 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 )
|
||||||
|
|
||||||
|
AIGroup:E( { "AI_A2A_PATROL.PatrolRoute:", AIGroup:GetName() } )
|
||||||
|
|
||||||
|
if AIGroup:IsAlive() then
|
||||||
local _AI_A2A_Patrol = AIGroup:GetState( AIGroup, "AI_A2A_PATROL" ) -- #AI_A2A_PATROL
|
local _AI_A2A_Patrol = AIGroup:GetState( AIGroup, "AI_A2A_PATROL" ) -- #AI_A2A_PATROL
|
||||||
_AI_A2A_Patrol:Route()
|
_AI_A2A_Patrol:Route()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
--- Defines a new patrol route using the @{Process_PatrolZone} parameters and settings.
|
||||||
-- @param #AI_A2A_PATROL self
|
-- @param #AI_A2A_PATROL self
|
||||||
@ -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
|
||||||
|
|||||||
@ -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
|
||||||
|
|||||||
@ -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 )
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user